Add unit testing to story download enqueuer.

This commit is contained in:
Alex Hart 2022-09-01 13:17:31 -03:00 committed by Greyson Parrelli
parent d2f639c57f
commit 13eb89746b
3 changed files with 300 additions and 0 deletions

View file

@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.database
import android.app.Application
import android.content.Context
import androidx.annotation.VisibleForTesting
import net.zetetic.database.sqlcipher.SQLiteOpenHelper
import org.signal.core.util.SqlUtil
import org.signal.core.util.logging.Log
@ -221,6 +222,12 @@ open class SignalDatabase(private val context: Application, databaseSecret: Data
}
}
@JvmStatic
@VisibleForTesting
fun setSignalDatabaseInstanceForTesting(signalDatabase: SignalDatabase) {
this.instance = signalDatabase
}
@JvmStatic
val rawDatabase: net.zetetic.database.sqlcipher.SQLiteDatabase
get() = instance!!.rawWritableDatabase

View file

@ -0,0 +1,177 @@
package org.thoughtcrime.securesms.database
import org.thoughtcrime.securesms.attachments.AttachmentId
import org.thoughtcrime.securesms.attachments.DatabaseAttachment
import org.thoughtcrime.securesms.audio.AudioHash
import org.thoughtcrime.securesms.blurhash.BlurHash
import org.thoughtcrime.securesms.contactshare.Contact
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch
import org.thoughtcrime.securesms.database.documents.NetworkFailure
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
import org.thoughtcrime.securesms.database.model.ParentStoryId
import org.thoughtcrime.securesms.database.model.Quote
import org.thoughtcrime.securesms.database.model.ReactionRecord
import org.thoughtcrime.securesms.database.model.StoryType
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
import org.thoughtcrime.securesms.linkpreview.LinkPreview
import org.thoughtcrime.securesms.mms.SlideDeck
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.stickers.StickerLocator
import org.thoughtcrime.securesms.util.MediaUtil
/**
* Builds MessageRecords and related components for direct usage in unit testing. Does not modify the database.
*/
object FakeMessageRecords {
fun buildDatabaseAttachment(
attachmentId: AttachmentId = AttachmentId(1, 1),
mmsId: Long = 1,
hasData: Boolean = true,
hasThumbnail: Boolean = true,
contentType: String = MediaUtil.IMAGE_JPEG,
transferProgress: Int = AttachmentDatabase.TRANSFER_PROGRESS_DONE,
size: Long = 0L,
fileName: String = "",
cdnNumber: Int = 1,
location: String = "",
key: String = "",
relay: String = "",
digest: ByteArray = byteArrayOf(),
fastPreflightId: String = "",
voiceNote: Boolean = false,
borderless: Boolean = false,
videoGif: Boolean = false,
width: Int = 0,
height: Int = 0,
quote: Boolean = false,
caption: String? = null,
stickerLocator: StickerLocator? = null,
blurHash: BlurHash? = null,
audioHash: AudioHash? = null,
transformProperties: AttachmentDatabase.TransformProperties? = null,
displayOrder: Int = 0,
uploadTimestamp: Long = 200
): DatabaseAttachment {
return DatabaseAttachment(
attachmentId,
mmsId,
hasData,
hasThumbnail,
contentType,
transferProgress,
size,
fileName,
cdnNumber,
location,
key,
relay,
digest,
fastPreflightId,
voiceNote,
borderless,
videoGif,
width,
height,
quote,
caption,
stickerLocator,
blurHash,
audioHash,
transformProperties,
displayOrder,
uploadTimestamp
)
}
fun buildLinkPreview(
url: String = "",
title: String = "",
description: String = "",
date: Long = 200,
attachmentId: AttachmentId? = null
): LinkPreview {
return LinkPreview(
url,
title,
description,
date,
attachmentId
)
}
fun buildMediaMmsMessageRecord(
id: Long = 1,
conversationRecipient: Recipient = Recipient.UNKNOWN,
individualRecipient: Recipient = conversationRecipient,
recipientDeviceId: Int = 1,
dateSent: Long = 200,
dateReceived: Long = 400,
dateServer: Long = 300,
deliveryReceiptCount: Int = 0,
threadId: Long = 1,
body: String = "body",
slideDeck: SlideDeck = SlideDeck(),
partCount: Int = slideDeck.slides.count(),
mailbox: Long = MmsSmsColumns.Types.BASE_INBOX_TYPE,
mismatches: Set<IdentityKeyMismatch> = emptySet(),
failures: Set<NetworkFailure> = emptySet(),
subscriptionId: Int = -1,
expiresIn: Long = -1,
expireStarted: Long = -1,
viewOnce: Boolean = false,
readReceiptCount: Int = 0,
quote: Quote? = null,
contacts: List<Contact> = emptyList(),
linkPreviews: List<LinkPreview> = emptyList(),
unidentified: Boolean = false,
reactions: List<ReactionRecord> = emptyList(),
remoteDelete: Boolean = false,
mentionsSelf: Boolean = false,
notifiedTimestamp: Long = 350,
viewedReceiptCount: Int = 0,
receiptTimestamp: Long = 0,
messageRanges: BodyRangeList? = null,
storyType: StoryType = StoryType.NONE,
parentStoryId: ParentStoryId? = null,
giftBadge: GiftBadge? = null
): MediaMmsMessageRecord {
return MediaMmsMessageRecord(
id,
conversationRecipient,
individualRecipient,
recipientDeviceId,
dateSent,
dateReceived,
dateServer,
deliveryReceiptCount,
threadId,
body,
slideDeck,
partCount,
mailbox,
mismatches,
failures,
subscriptionId,
expiresIn,
expireStarted,
viewOnce,
readReceiptCount,
quote,
contacts,
linkPreviews,
unidentified,
reactions,
remoteDelete,
mentionsSelf,
notifiedTimestamp,
viewedReceiptCount,
receiptTimestamp,
messageRanges,
storyType,
parentStoryId,
giftBadge
)
}
}

View file

@ -0,0 +1,116 @@
package org.thoughtcrime.securesms.stories
import io.reactivex.rxjava3.plugins.RxJavaPlugins
import io.reactivex.rxjava3.schedulers.TestScheduler
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.Mock
import org.mockito.MockedStatic
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
import org.mockito.kotlin.any
import org.mockito.kotlin.isA
import org.mockito.kotlin.never
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import org.thoughtcrime.securesms.attachments.AttachmentId
import org.thoughtcrime.securesms.database.AttachmentDatabase
import org.thoughtcrime.securesms.database.FakeMessageRecords
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.jobmanager.JobManager
import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob
class StoriesTest {
@Rule
@JvmField
val mockitoRule: MockitoRule = MockitoJUnit.rule()
@Mock
private lateinit var mockAttachmentDatabase: AttachmentDatabase
@Mock
private lateinit var mockJobManager: JobManager
@Mock
private lateinit var mockApplicationDependenciesStatic: MockedStatic<ApplicationDependencies>
@Mock
private lateinit var mockSignalDatabaseStatic: MockedStatic<SignalDatabase>
@Mock
private lateinit var mockSignalDatabase: SignalDatabase
private val testScheduler = TestScheduler()
@Before
fun setUp() {
RxJavaPlugins.setInitIoSchedulerHandler { testScheduler }
RxJavaPlugins.setIoSchedulerHandler { testScheduler }
SignalDatabase.setSignalDatabaseInstanceForTesting(mockSignalDatabase)
whenever(SignalDatabase.attachments).thenReturn(mockAttachmentDatabase)
whenever(ApplicationDependencies.getJobManager()).thenReturn(mockJobManager)
whenever(mockAttachmentDatabase.getAttachmentsForMessage(any())).thenReturn(emptyList())
}
@After
fun tearDown() {
RxJavaPlugins.reset()
}
@Test
fun `Given a MessageRecord with no attachments and a LinkPreview without a thumbnail, when I enqueueAttachmentsFromStoryForDownload, then I enqueue nothing`() {
// GIVEN
val messageRecord = FakeMessageRecords.buildMediaMmsMessageRecord(
linkPreviews = listOf(FakeMessageRecords.buildLinkPreview())
)
// WHEN
val testObserver = Stories.enqueueAttachmentsFromStoryForDownload(messageRecord, true).test()
testScheduler.triggerActions()
// THEN
testObserver.assertComplete()
verify(mockJobManager, never()).add(any())
}
@Test
fun `Given a MessageRecord with no attachments and a LinkPreview with a thumbnail, when I enqueueAttachmentsFromStoryForDownload, then I enqueue once`() {
// GIVEN
val messageRecord = FakeMessageRecords.buildMediaMmsMessageRecord(
linkPreviews = listOf(
FakeMessageRecords.buildLinkPreview(
attachmentId = AttachmentId(1, 2)
)
)
)
// WHEN
val testObserver = Stories.enqueueAttachmentsFromStoryForDownload(messageRecord, true).test()
testScheduler.triggerActions()
// THEN
testObserver.assertComplete()
verify(mockJobManager).add(isA<AttachmentDownloadJob>())
}
@Test
fun `Given a MessageRecord with an attachment, when I enqueueAttachmentsFromStoryForDownload, then I enqueue once`() {
// GIVEN
val attachment = FakeMessageRecords.buildDatabaseAttachment()
val messageRecord = FakeMessageRecords.buildMediaMmsMessageRecord()
whenever(mockAttachmentDatabase.getAttachmentsForMessage(any())).thenReturn(listOf(attachment))
// WHEN
val testObserver = Stories.enqueueAttachmentsFromStoryForDownload(messageRecord, true).test()
testScheduler.triggerActions()
// THEN
testObserver.assertComplete()
verify(mockJobManager).add(isA<AttachmentDownloadJob>())
}
}