Compare commits

...

4 Commits

Author SHA1 Message Date
ganfra 202504fea9 Timeline: add some fakes and fixtures 2022-07-13 17:28:27 +02:00
ganfra a800a837cc Timeline tests: unignored 2022-07-12 15:37:47 +02:00
ganfra 28a79b4672 Test: use this new syncOnce in tests 2022-07-11 19:10:09 +02:00
ganfra 4c2b28075c Sync: add syncOnce method 2022-07-11 19:06:34 +02:00
15 changed files with 363 additions and 89 deletions

View File

@ -51,7 +51,6 @@ import org.matrix.android.sdk.api.session.room.timeline.Timeline
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
import org.matrix.android.sdk.api.session.sync.SyncState
import timber.log.Timber
import java.util.UUID
import java.util.concurrent.CancellationException
import java.util.concurrent.CountDownLatch
@ -142,42 +141,8 @@ class CommonTestHelper internal constructor(context: Context) {
* @param session the session to sync
*/
fun syncSession(session: Session, timeout: Long = TestConstants.timeOutMillis * 10) {
val lock = CountDownLatch(1)
coroutineScope.launch {
session.syncService().startSync(true)
val syncLiveData = session.syncService().getSyncStateLive()
val syncObserver = object : Observer<SyncState> {
override fun onChanged(t: SyncState?) {
if (session.syncService().hasAlreadySynced()) {
lock.countDown()
syncLiveData.removeObserver(this)
}
}
}
syncLiveData.observeForever(syncObserver)
}
await(lock, timeout)
}
/**
* This methods clear the cache and waits for initialSync
*
* @param session the session to sync
*/
fun clearCacheAndSync(session: Session, timeout: Long = TestConstants.timeOutMillis) {
waitWithLatch(timeout) { latch ->
session.clearCache()
val syncLiveData = session.syncService().getSyncStateLive()
val syncObserver = object : Observer<SyncState> {
override fun onChanged(t: SyncState?) {
if (session.syncService().hasAlreadySynced()) {
Timber.v("Clear cache and synced")
syncLiveData.removeObserver(this)
latch.countDown()
}
}
}
syncLiveData.observeForever(syncObserver)
runBlockingTest(timeout) {
session.syncService().syncOnce(0L)
session.syncService().startSync(true)
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.matrix.android.sdk.session.room.timeline
package org.matrix.android.sdk.internal.session.room.timeline
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.zhuinden.monarchy.Monarchy
@ -32,9 +32,8 @@ import org.matrix.android.sdk.internal.database.helper.addTimelineEvent
import org.matrix.android.sdk.internal.database.mapper.toEntity
import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.SessionRealmModule
import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
import org.matrix.android.sdk.internal.util.time.DefaultClock
import org.matrix.android.sdk.session.room.timeline.RoomDataHelper.createFakeMessageEvent
import org.matrix.android.sdk.internal.session.room.timeline.RoomDataHelper.createFakeMessageEvent
@RunWith(AndroidJUnit4::class)
internal class ChunkEntityTest : InstrumentedTest {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.matrix.android.sdk.session.room.timeline
package org.matrix.android.sdk.internal.session.room.timeline
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.events.model.Event

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.room.timeline
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.zhuinden.monarchy.Monarchy
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.kotlin.executeTransactionAwait
import kotlinx.coroutines.runBlocking
import org.amshove.kluent.shouldBe
import org.amshove.kluent.shouldBeEqualTo
import org.amshove.kluent.shouldNotBe
import org.junit.After
import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.ChunkEntityFields
import org.matrix.android.sdk.internal.database.model.SessionRealmModule
import org.matrix.android.sdk.internal.session.room.timeline.fakes.FakeLightweightSettingsStorage
import org.matrix.android.sdk.internal.session.room.timeline.fakes.FakeStreamEventsManager
import org.matrix.android.sdk.internal.session.room.timeline.fakes.FakeTokenChunkEvent
import org.matrix.android.sdk.internal.session.room.timeline.fixtures.aListOfTextMessageEvents
import org.matrix.android.sdk.internal.util.time.DefaultClock
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class TokenChunkEventPersistorTest : InstrumentedTest {
private lateinit var monarchy: Monarchy
private lateinit var realm: Realm
private val clock = DefaultClock()
private val userId = "@userId:server.com"
private val lightweightSettingsStorage = FakeLightweightSettingsStorage()
private val streamEventsManager = FakeStreamEventsManager().apply {
givenDispatchPaginatedEventReceived()
}
@Before
fun setup() {
Realm.init(context())
val testConfig = RealmConfiguration.Builder()
.inMemory()
.name("TokenChunkEventPersistorTest")
.modules(SessionRealmModule())
.build()
monarchy = Monarchy.Builder().setRealmConfiguration(testConfig).build()
realm = Realm.getInstance(monarchy.realmConfiguration)
}
@After
fun tearDown() {
realm.close()
}
@Test
fun given_new_chunk_events_should_all_be_added_and_unique() = runBlocking {
val roomId = "room-id"
val tokenChunkEventPersistor =
TokenChunkEventPersistor(monarchy, userId, lightweightSettingsStorage, liveEventManager = { streamEventsManager.instance }, clock)
val fakeTokenChunkEvent = FakeTokenChunkEvent(
start = "start",
end = "end",
events = aListOfTextMessageEvents(10, roomId = roomId)
)
val result = tokenChunkEventPersistor.insertInDb(fakeTokenChunkEvent, roomId, direction = PaginationDirection.BACKWARDS)
result shouldBeEqualTo TokenChunkEventPersistor.Result.SUCCESS
realm.refresh()
val chunkEntity = realm.where(ChunkEntity::class.java)
.equalTo(ChunkEntityFields.NEXT_TOKEN, "start")
.equalTo(ChunkEntityFields.PREV_TOKEN, "end")
.findFirst()!!
chunkEntity.nextChunk shouldBe null
chunkEntity.prevChunk shouldBe null
chunkEntity.timelineEvents.size shouldBeEqualTo 10
Unit
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,10 +14,11 @@
* limitations under the License.
*/
package org.matrix.android.sdk.session.room.timeline
package org.matrix.android.sdk.internal.session.room.timeline.fakes
import org.matrix.android.sdk.internal.session.room.timeline.GetContextOfEventTask
import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
import org.matrix.android.sdk.internal.session.room.timeline.RoomDataHelper
import org.matrix.android.sdk.internal.session.room.timeline.TokenChunkEventPersistor
import kotlin.random.Random
@ -30,6 +31,10 @@ internal class FakeGetContextOfEventTask constructor(private val tokenChunkEvent
Random.nextLong().toString(),
fakeEvents
)
return tokenChunkEventPersistor.insertInDb(tokenChunkEvent, params.roomId, PaginationDirection.BACKWARDS)
return tokenChunkEventPersistor.insertInDb(
receivedChunk = tokenChunkEvent,
roomId = params.roomId,
direction = PaginationDirection.BACKWARDS
)
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.room.timeline.fakes
import org.matrix.android.sdk.api.settings.LightweightSettingsStorage
internal class FakeLightweightSettingsStorage : LightweightSettingsStorage {
private var threadMessageEnabled = false
override fun setThreadMessagesEnabled(enabled: Boolean) {
threadMessageEnabled = enabled
}
override fun areThreadMessagesEnabled(): Boolean {
return threadMessageEnabled
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,9 +14,10 @@
* limitations under the License.
*/
package org.matrix.android.sdk.session.room.timeline
package org.matrix.android.sdk.internal.session.room.timeline.fakes
import org.matrix.android.sdk.internal.session.room.timeline.PaginationTask
import org.matrix.android.sdk.internal.session.room.timeline.RoomDataHelper
import org.matrix.android.sdk.internal.session.room.timeline.TokenChunkEventPersistor
import javax.inject.Inject
import kotlin.random.Random
@ -26,6 +27,10 @@ internal class FakePaginationTask @Inject constructor(private val tokenChunkEven
override suspend fun execute(params: PaginationTask.Params): TokenChunkEventPersistor.Result {
val fakeEvents = RoomDataHelper.createFakeListOfEvents(30)
val tokenChunkEvent = FakeTokenChunkEvent(params.from, Random.nextLong().toString(), fakeEvents)
return tokenChunkEventPersistor.insertInDb(tokenChunkEvent, params.roomId, params.direction)
return tokenChunkEventPersistor.insertInDb(
receivedChunk = tokenChunkEvent,
roomId = params.roomId,
direction = params.direction
)
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.room.timeline.fakes
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.runs
import org.matrix.android.sdk.internal.session.StreamEventsManager
internal class FakeStreamEventsManager {
val instance = mockk<StreamEventsManager>()
fun givenDispatchPaginatedEventReceived() {
every { instance.dispatchPaginatedEventReceived(any(), any()) } just runs
}
}

View File

@ -1,11 +1,11 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.matrix.android.sdk.session.room.timeline
package org.matrix.android.sdk.internal.session.room.timeline.fakes
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.internal.session.room.timeline.TokenChunkEvent

View File

@ -0,0 +1,125 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.room.timeline.fixtures
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.model.RoomNameContent
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
import org.matrix.android.sdk.api.session.room.model.message.MessageType
internal fun aTextMessageEvent(
roomId: String = "room-id",
eventId: String = "event-id",
senderId: String = "sender-id",
body: String = "body"
): Event = Event(
type = EventType.MESSAGE,
eventId = eventId,
content = MessageTextContent(
msgType = MessageType.MSGTYPE_TEXT,
body = body
).toContent(),
prevContent = null,
originServerTs = 0,
senderId = senderId,
stateKey = null,
roomId = roomId,
unsignedData = null,
redacts = null
)
internal fun aRoomCreateEvent(
roomId: String = "room-id",
eventId: String = "event-id",
senderId: String = "sender-id",
): Event = Event(
type = EventType.STATE_ROOM_CREATE,
eventId = eventId,
content = RoomCreateContent(
creator = senderId
).toContent(),
prevContent = null,
originServerTs = 0,
senderId = senderId,
stateKey = "",
roomId = roomId,
unsignedData = null,
redacts = null
)
internal fun aRoomMemberEvent(
roomId: String = "room-id",
eventId: String = "event-id",
senderId: String = "sender-id",
membership: Membership = Membership.JOIN,
displayName: String = "Alice",
): Event = Event(
type = EventType.STATE_ROOM_MEMBER,
eventId = eventId,
content = RoomMemberContent(
membership = membership,
displayName = displayName
).toContent(),
prevContent = null,
originServerTs = 0,
senderId = senderId,
stateKey = senderId,
roomId = roomId,
unsignedData = null,
redacts = null
)
internal fun aRoomNameEvent(
roomId: String = "room-id",
eventId: String = "event-id",
senderId: String = "sender-id",
roomName: String = "Alice and Bob Room"
): Event = Event(
type = EventType.STATE_ROOM_NAME,
eventId = eventId,
content = RoomNameContent(
name = roomName
).toContent(),
prevContent = null,
originServerTs = 0,
senderId = senderId,
stateKey = "",
roomId = roomId,
unsignedData = null,
redacts = null
)
internal fun aListOfTextMessageEvents(
size: Int = 10,
roomId: String = "room-id",
eventIdPrefix: String = "event-id",
senderId: String = "sender-id",
bodyPrefix: String = "body"
) = (0 until size).map {
aTextMessageEvent(
roomId = roomId,
eventId = "{$eventIdPrefix}_{$it}",
senderId = senderId,
body = "{$bodyPrefix}_{$it}",
)
}

View File

@ -17,10 +17,13 @@
package org.matrix.android.sdk.session.room.timeline
import androidx.test.filters.LargeTest
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.amshove.kluent.internal.assertEquals
import org.amshove.kluent.shouldBe
import org.amshove.kluent.shouldBeFalse
import org.amshove.kluent.shouldBeTrue
import org.amshove.kluent.shouldNotBe
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@ -31,6 +34,7 @@ import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.room.timeline.Timeline
import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
@ -61,28 +65,38 @@ class TimelineForwardPaginationTest : InstrumentedTest {
aliceSession.cryptoService().setWarnOnUnknownDevices(false)
val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!!
// Alice sends X messages
val message = "Message from Alice"
val sentMessages = commonTestHelper.sendTextMessage(
roomFromAlicePOV,
aliceSession.getRoom(aliceRoomId)!!,
message,
numberOfMessagesToSend
)
Timber.tag("TimelineTest").v("Sent ${sentMessages.size} messages")
// Alice clear the cache and restart the sync
commonTestHelper.clearCacheAndSync(aliceSession)
val aliceTimeline = roomFromAlicePOV.timelineService().createTimeline(null, TimelineSettings(30))
commonTestHelper.runBlockingTest {
aliceSession.getRoom(aliceRoomId) shouldNotBe null
Timber.tag("TimelineTest").v("Clear cache")
aliceSession.clearCache()
aliceSession.getRoom(aliceRoomId) shouldBe null
Timber.tag("TimelineTest").v("Launch initial sync")
aliceSession.syncService().syncOnce(0L)
aliceSession.getRoom(aliceRoomId) shouldNotBe null
}
val aliceRoom = aliceSession.getRoom(aliceRoomId)!!
Timber.tag("TimelineTest").v("Got roomSummary : ${aliceRoom.roomSummary()}")
val aliceTimeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
aliceTimeline.start()
Timber.tag("TimelineTest").v("Start timeline with initialSize of 30.")
// Alice sees the 10 last message of the room, and can only navigate BACKWARD
run {
val lock = CountDownLatch(1)
val eventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
Timber.e("Alice timeline updated: with ${snapshot.size} events:")
Timber.tag("TimelineTest").v("Alice timeline updated: with ${snapshot.size} events:")
snapshot.forEach {
Timber.w(" event ${it.root.content}")
Timber.tag("TimelineTest").v(" event ${it.root.content}")
}
// Ok, we have the 10 last messages of the initial sync
@ -104,11 +118,10 @@ class TimelineForwardPaginationTest : InstrumentedTest {
run {
val lock = CountDownLatch(1)
val aliceEventsListener = commonTestHelper.createEventListener(lock) { snapshot ->
Timber.e("Alice timeline updated: with ${snapshot.size} events:")
Timber.tag("TimelineTest").v("#restartWithEventId Alice timeline updated: with ${snapshot.size} events:")
snapshot.forEach {
Timber.w(" event ${it.root.content}")
Timber.tag("TimelineTest").v(" event ${it.root.content}")
}
// The event is not in db, so it is fetch alone
snapshot.size == 1 &&
snapshot.all { it.root.content.toModel<MessageContent>()?.body?.startsWith("Message from Alice").orFalse() }

View File

@ -17,10 +17,10 @@
package org.matrix.android.sdk.session.room.timeline
import androidx.test.filters.LargeTest
import kotlinx.coroutines.runBlocking
import org.amshove.kluent.shouldBeFalse
import org.amshove.kluent.shouldBeTrue
import org.junit.FixMethodOrder
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@ -40,7 +40,6 @@ import java.util.concurrent.CountDownLatch
@RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
@Ignore("This test will be ignored until it is fixed")
@LargeTest
class TimelinePreviousLastForwardTest : InstrumentedTest {
@ -232,11 +231,12 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
bobTimeline.addListener(eventsListener)
bobTimeline.paginate(Timeline.Direction.FORWARDS, 50)
bobTimeline.paginate(Timeline.Direction.FORWARDS, 50)
commonTestHelper.await(lock)
bobTimeline.removeAllListeners()
commonTestHelper.runBlockingTest {
val timelineEvents = bobTimeline.awaitPaginate(Timeline.Direction.FORWARDS, 50)
Timber.v("Number of timelineEvents=${timelineEvents.size}")
}
bobTimeline.hasMoreToLoad(Timeline.Direction.FORWARDS).shouldBeFalse()
bobTimeline.hasMoreToLoad(Timeline.Direction.BACKWARDS).shouldBeFalse()
}

View File

@ -20,7 +20,6 @@ import androidx.test.filters.LargeTest
import kotlinx.coroutines.runBlocking
import org.amshove.kluent.internal.assertEquals
import org.junit.FixMethodOrder
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@ -35,11 +34,11 @@ import org.matrix.android.sdk.api.session.room.timeline.Timeline
import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
import org.matrix.android.sdk.common.CommonTestHelper.Companion.runCryptoTest
import org.matrix.android.sdk.common.TestConstants
import timber.log.Timber
@RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
@LargeTest
@Ignore
class TimelineSimpleBackPaginationTest : InstrumentedTest {
@Test
@ -68,28 +67,14 @@ class TimelineSimpleBackPaginationTest : InstrumentedTest {
val bobTimeline = roomFromBobPOV.timelineService().createTimeline(null, TimelineSettings(30))
bobTimeline.start()
commonTestHelper.waitWithLatch(timeout = TestConstants.timeOutMillis * 10) {
val listener = object : Timeline.Listener {
override fun onStateUpdated(direction: Timeline.Direction, state: Timeline.PaginationState) {
if (direction == Timeline.Direction.FORWARDS) {
return
}
if (state.hasMoreToLoad && !state.loading) {
bobTimeline.paginate(Timeline.Direction.BACKWARDS, 30)
} else if (!state.hasMoreToLoad) {
bobTimeline.removeListener(this)
it.countDown()
}
}
commonTestHelper.runBlockingTest {
while (bobTimeline.hasMoreToLoad(Timeline.Direction.BACKWARDS)) {
val timelineEvents = bobTimeline.awaitPaginate(direction = Timeline.Direction.BACKWARDS, 30)
Timber.v("Number of TimelineEvents= ${timelineEvents.size}")
}
bobTimeline.addListener(listener)
bobTimeline.paginate(Timeline.Direction.BACKWARDS, 30)
}
assertEquals(false, bobTimeline.hasMoreToLoad(Timeline.Direction.FORWARDS))
assertEquals(false, bobTimeline.hasMoreToLoad(Timeline.Direction.BACKWARDS))
val onlySentEvents = runBlocking {
bobTimeline.getSnapshot()
}
@ -99,7 +84,6 @@ class TimelineSimpleBackPaginationTest : InstrumentedTest {
(it.root.content.toModel<MessageTextContent>())?.body?.startsWith(message).orFalse()
}
assertEquals(numberOfMessagesToSent, onlySentEvents.size)
bobTimeline.dispose()
}
}

View File

@ -21,6 +21,9 @@ import kotlinx.coroutines.flow.SharedFlow
import org.matrix.android.sdk.api.session.sync.model.SyncResponse
interface SyncService {
suspend fun syncOnce(timeout: Long): SyncResponse
/**
* This method start the sync thread.
*/

View File

@ -17,8 +17,15 @@
package org.matrix.android.sdk.internal.session.sync
import androidx.lifecycle.LiveData
import io.realm.RealmConfiguration
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.session.sync.SyncRequestState
import org.matrix.android.sdk.api.session.sync.SyncService
import org.matrix.android.sdk.api.session.sync.model.SyncResponse
import org.matrix.android.sdk.internal.database.awaitNotEmptyResult
import org.matrix.android.sdk.internal.database.model.SyncEntity
import org.matrix.android.sdk.internal.database.model.SyncEntityFields
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.di.SessionId
import org.matrix.android.sdk.internal.di.WorkManagerProvider
import org.matrix.android.sdk.internal.session.SessionState
@ -35,7 +42,9 @@ internal class DefaultSyncService @Inject constructor(
private val syncTokenStore: SyncTokenStore,
private val syncRequestStateTracker: SyncRequestStateTracker,
private val sessionState: SessionState,
private val syncTask: SyncTask,
) : SyncService {
private var syncThread: SyncThread? = null
override fun requireBackgroundSync() {
@ -50,6 +59,11 @@ internal class DefaultSyncService @Inject constructor(
SyncWorker.stopAnyBackgroundSync(workManagerProvider)
}
override suspend fun syncOnce(timeout: Long): SyncResponse {
val syncParams = SyncTask.Params(timeout = timeout, presence = null, afterPause = false)
return syncTask.execute(syncParams)
}
override fun startSync(fromForeground: Boolean) {
Timber.i("Starting sync thread")
assert(sessionState.isOpen)