parent
9fa6d4774d
commit
7b0df17d9a
22 changed files with 2598 additions and 2571 deletions
|
@ -1,79 +0,0 @@
|
|||
package org.thoughtcrime.securesms.database;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class CursorRecyclerViewAdapterTest {
|
||||
private CursorRecyclerViewAdapter adapter;
|
||||
private Context context;
|
||||
private Cursor cursor;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
context = mock(Context.class);
|
||||
cursor = mock(Cursor.class);
|
||||
when(cursor.getCount()).thenReturn(100);
|
||||
when(cursor.moveToPosition(anyInt())).thenReturn(true);
|
||||
|
||||
adapter = new CursorRecyclerViewAdapter(context, cursor) {
|
||||
@Override
|
||||
public ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindItemViewHolder(ViewHolder viewHolder, @NonNull Cursor cursor) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSanityCount() throws Exception {
|
||||
assertEquals(adapter.getItemCount(), 100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderCount() throws Exception {
|
||||
adapter.setHeaderView(new View(context));
|
||||
assertEquals(adapter.getItemCount(), 101);
|
||||
|
||||
assertEquals(adapter.getItemViewType(0), CursorRecyclerViewAdapter.HEADER_TYPE);
|
||||
assertNotEquals(adapter.getItemViewType(1), CursorRecyclerViewAdapter.HEADER_TYPE);
|
||||
assertNotEquals(adapter.getItemViewType(100), CursorRecyclerViewAdapter.HEADER_TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFooterCount() throws Exception {
|
||||
adapter.setFooterView(new View(context));
|
||||
assertEquals(adapter.getItemCount(), 101);
|
||||
assertEquals(adapter.getItemViewType(100), CursorRecyclerViewAdapter.FOOTER_TYPE);
|
||||
assertNotEquals(adapter.getItemViewType(0), CursorRecyclerViewAdapter.FOOTER_TYPE);
|
||||
assertNotEquals(adapter.getItemViewType(99), CursorRecyclerViewAdapter.FOOTER_TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderFooterCount() throws Exception {
|
||||
adapter.setHeaderView(new View(context));
|
||||
adapter.setFooterView(new View(context));
|
||||
assertEquals(adapter.getItemCount(), 102);
|
||||
assertEquals(adapter.getItemViewType(101), CursorRecyclerViewAdapter.FOOTER_TYPE);
|
||||
assertEquals(adapter.getItemViewType(0), CursorRecyclerViewAdapter.HEADER_TYPE);
|
||||
assertNotEquals(adapter.getItemViewType(1), CursorRecyclerViewAdapter.HEADER_TYPE);
|
||||
assertNotEquals(adapter.getItemViewType(100), CursorRecyclerViewAdapter.FOOTER_TYPE);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package org.thoughtcrime.securesms.database
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Test
|
||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter.FOOTER_TYPE
|
||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter.HEADER_TYPE
|
||||
|
||||
class CursorRecyclerViewAdapterTest {
|
||||
private val context: Context = mockk<Context>()
|
||||
private val cursor: Cursor = mockk<Cursor>(relaxUnitFun = true) {
|
||||
every { count } returns 100
|
||||
every { moveToPosition(any()) } returns true
|
||||
}
|
||||
private val adapter = object : CursorRecyclerViewAdapter<RecyclerView.ViewHolder?>(context, cursor) {
|
||||
override fun onCreateItemViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder? = null
|
||||
override fun onBindItemViewHolder(viewHolder: RecyclerView.ViewHolder?, cursor: Cursor) = Unit
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSanityCount() {
|
||||
assertEquals(100, adapter.itemCount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHeaderCount() {
|
||||
adapter.headerView = View(context)
|
||||
assertEquals(101, adapter.itemCount)
|
||||
|
||||
assertEquals(HEADER_TYPE, adapter.getItemViewType(0))
|
||||
assertNotEquals(HEADER_TYPE, adapter.getItemViewType(1))
|
||||
assertNotEquals(HEADER_TYPE, adapter.getItemViewType(100))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFooterCount() {
|
||||
adapter.setFooterView(View(context))
|
||||
assertEquals(101, adapter.itemCount)
|
||||
assertEquals(FOOTER_TYPE, adapter.getItemViewType(100))
|
||||
assertNotEquals(FOOTER_TYPE, adapter.getItemViewType(0))
|
||||
assertNotEquals(FOOTER_TYPE, adapter.getItemViewType(99))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testHeaderFooterCount() {
|
||||
adapter.headerView = View(context)
|
||||
adapter.setFooterView(View(context))
|
||||
assertEquals(102, adapter.itemCount)
|
||||
assertEquals(FOOTER_TYPE, adapter.getItemViewType(101))
|
||||
assertEquals(HEADER_TYPE, adapter.getItemViewType(0))
|
||||
assertNotEquals(HEADER_TYPE, adapter.getItemViewType(1))
|
||||
assertNotEquals(FOOTER_TYPE, adapter.getItemViewType(100))
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,117 +0,0 @@
|
|||
package org.thoughtcrime.securesms.jobmanager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.jobmanager.persistence.JobSpec;
|
||||
import org.thoughtcrime.securesms.jobmanager.persistence.JobStorage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import kotlin.jvm.functions.Function1;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class JobMigratorTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void init() {
|
||||
Log.initialize(mock(Log.Logger.class));
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError.class)
|
||||
public void JobMigrator_crashWhenTooFewMigrations() {
|
||||
new JobMigrator(1, 2, Collections.emptyList());
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError.class)
|
||||
public void JobMigrator_crashWhenTooManyMigrations() {
|
||||
new JobMigrator(1, 2, Arrays.asList(new EmptyMigration(2), new EmptyMigration(3)));
|
||||
}
|
||||
|
||||
@Test(expected = AssertionError.class)
|
||||
public void JobMigrator_crashWhenSkippingMigrations() {
|
||||
new JobMigrator(1, 3, Arrays.asList(new EmptyMigration(2), new EmptyMigration(4)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void JobMigrator_properInitialization() {
|
||||
new JobMigrator(1, 3, Arrays.asList(new EmptyMigration(2), new EmptyMigration(3)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_callsAppropriateMigrations_fullSet() {
|
||||
JobMigration migration1 = spy(new EmptyMigration(2));
|
||||
JobMigration migration2 = spy(new EmptyMigration(3));
|
||||
|
||||
JobMigrator subject = new JobMigrator(1, 3, Arrays.asList(migration1, migration2));
|
||||
int version = subject.migrate(simpleJobStorage());
|
||||
|
||||
assertEquals(3, version);
|
||||
verify(migration1).migrate(any());
|
||||
verify(migration2).migrate(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_callsAppropriateMigrations_subset() {
|
||||
JobMigration migration1 = spy(new EmptyMigration(2));
|
||||
JobMigration migration2 = spy(new EmptyMigration(3));
|
||||
|
||||
JobMigrator subject = new JobMigrator(2, 3, Arrays.asList(migration1, migration2));
|
||||
int version = subject.migrate(simpleJobStorage());
|
||||
|
||||
assertEquals(3, version);
|
||||
verify(migration1, never()).migrate(any());
|
||||
verify(migration2).migrate(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_callsAppropriateMigrations_none() {
|
||||
JobMigration migration1 = spy(new EmptyMigration(2));
|
||||
JobMigration migration2 = spy(new EmptyMigration(3));
|
||||
|
||||
JobMigrator subject = new JobMigrator(3, 3, Arrays.asList(migration1, migration2));
|
||||
int version = subject.migrate(simpleJobStorage());
|
||||
|
||||
assertEquals(3, version);
|
||||
verify(migration1, never()).migrate(any());
|
||||
verify(migration2, never()).migrate(any());
|
||||
}
|
||||
|
||||
private static JobStorage simpleJobStorage() {
|
||||
JobStorage jobStorage = mock(JobStorage.class);
|
||||
JobSpec job = new JobSpec("1", "f1", null, 1, 1, 1, 1, 1, 1, null, null, false, false, 0, 0);
|
||||
|
||||
when(jobStorage.debugGetJobSpecs(anyInt())).thenReturn(new ArrayList<>(Collections.singletonList(job)));
|
||||
doAnswer(invocation -> {
|
||||
Function1<JobSpec, JobSpec> transformer = invocation.getArgument(0);
|
||||
return transformer.invoke(job);
|
||||
}).when(jobStorage).transformJobs(any());
|
||||
|
||||
return jobStorage;
|
||||
}
|
||||
|
||||
private static class EmptyMigration extends JobMigration {
|
||||
|
||||
protected EmptyMigration(int endVersion) {
|
||||
super(endVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull JobData migrate(@NonNull JobData jobData) {
|
||||
return jobData;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package org.thoughtcrime.securesms.jobmanager
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertThrows
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.Test
|
||||
import org.signal.core.util.logging.Log.initialize
|
||||
import org.thoughtcrime.securesms.jobmanager.persistence.JobSpec
|
||||
import org.thoughtcrime.securesms.jobmanager.persistence.JobStorage
|
||||
import org.thoughtcrime.securesms.testutil.EmptyLogger
|
||||
|
||||
class JobMigratorTest {
|
||||
@Test
|
||||
fun test_JobMigrator_crashWhenTooFewMigrations() {
|
||||
val error = assertThrows(AssertionError::class.java) {
|
||||
JobMigrator(1, 2, emptyList())
|
||||
}
|
||||
assertEquals("You must have a migration for every version!", error.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_JobMigrator_crashWhenTooManyMigrations() {
|
||||
val error = assertThrows(AssertionError::class.java) {
|
||||
JobMigrator(1, 2, listOf<JobMigration>(EmptyMigration(2), EmptyMigration(3)))
|
||||
}
|
||||
assertEquals("You must have a migration for every version!", error.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_JobMigrator_crashWhenSkippingMigrations() {
|
||||
val error = assertThrows(AssertionError::class.java) {
|
||||
JobMigrator(1, 3, listOf<JobMigration>(EmptyMigration(2), EmptyMigration(4)))
|
||||
}
|
||||
assertEquals("Missing migration for version 3!", error.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_JobMigrator_properInitialization() {
|
||||
JobMigrator(1, 3, listOf<JobMigration>(EmptyMigration(2), EmptyMigration(3)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_callsAppropriateMigrations_fullSet() {
|
||||
val migration1 = EmptyMigration(2)
|
||||
val migration2 = EmptyMigration(3)
|
||||
|
||||
val subject = JobMigrator(1, 3, listOf(migration1, migration2))
|
||||
val version = subject.migrate(simpleJobStorage())
|
||||
|
||||
assertEquals(3, version)
|
||||
assertTrue(migration1.migrated)
|
||||
assertTrue(migration2.migrated)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_callsAppropriateMigrations_subset() {
|
||||
val migration1 = EmptyMigration(2)
|
||||
val migration2 = EmptyMigration(3)
|
||||
|
||||
val subject = JobMigrator(2, 3, listOf(migration1, migration2))
|
||||
val version = subject.migrate(simpleJobStorage())
|
||||
|
||||
assertEquals(3, version)
|
||||
assertFalse(migration1.migrated)
|
||||
assertTrue(migration2.migrated)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_callsAppropriateMigrations_none() {
|
||||
val migration1 = EmptyMigration(2)
|
||||
val migration2 = EmptyMigration(3)
|
||||
|
||||
val subject = JobMigrator(3, 3, listOf(migration1, migration2))
|
||||
val version = subject.migrate(simpleJobStorage())
|
||||
|
||||
assertEquals(3, version)
|
||||
assertFalse(migration1.migrated)
|
||||
assertFalse(migration2.migrated)
|
||||
}
|
||||
|
||||
private class EmptyMigration(endVersion: Int) : JobMigration(endVersion) {
|
||||
private var _migrated: Boolean = false
|
||||
val migrated: Boolean get() = _migrated
|
||||
|
||||
override fun migrate(jobData: JobData): JobData {
|
||||
_migrated = true
|
||||
return jobData
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@BeforeClass
|
||||
fun init() {
|
||||
initialize(EmptyLogger())
|
||||
}
|
||||
|
||||
private fun simpleJobStorage(): JobStorage {
|
||||
val job = JobSpec(
|
||||
id = "1",
|
||||
factoryKey = "f1",
|
||||
queueKey = null,
|
||||
createTime = 1,
|
||||
lastRunAttemptTime = 1,
|
||||
nextBackoffInterval = 1,
|
||||
runAttempt = 1,
|
||||
maxAttempts = 1,
|
||||
lifespan = 1,
|
||||
serializedData = null,
|
||||
serializedInputData = null,
|
||||
isRunning = false,
|
||||
isMemoryOnly = false,
|
||||
globalPriority = 0,
|
||||
queuePriority = 0
|
||||
)
|
||||
return mockk<JobStorage> {
|
||||
every { debugGetJobSpecs(any()) } returns listOf(job)
|
||||
every { transformJobs(any()) } answers {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val transformer = invocation.args.single() as Function1<JobSpec, JobSpec>
|
||||
transformer(job)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package org.thoughtcrime.securesms.jobmanager.migrations;
|
||||
|
||||
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.thoughtcrime.securesms.jobmanager.JsonJobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration.JobData;
|
||||
import org.thoughtcrime.securesms.jobs.FailingJob;
|
||||
import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class RecipientIdFollowUpJobMigrationTest {
|
||||
|
||||
@Rule
|
||||
public MockitoRule rule = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private MockedStatic<Recipient> recipientMockedStatic;
|
||||
|
||||
@Mock
|
||||
private MockedStatic<Job.Parameters> jobParametersMockedStatic;
|
||||
|
||||
@Test
|
||||
public void migrate_sendDeliveryReceiptJob_good() throws Exception {
|
||||
JobData testData = new JobData("SendDeliveryReceiptJob", null, -1, -1, new JsonJobData.Builder().putString("recipient", "1")
|
||||
.putLong("message_id", 1)
|
||||
.putLong("timestamp", 2)
|
||||
.serialize());
|
||||
RecipientIdFollowUpJobMigration subject = new RecipientIdFollowUpJobMigration();
|
||||
JobData converted = subject.migrate(testData);
|
||||
|
||||
assertEquals("SendDeliveryReceiptJob", converted.getFactoryKey());
|
||||
assertNull(converted.getQueueKey());
|
||||
|
||||
JsonJobData data = JsonJobData.deserialize(converted.getData());
|
||||
assertEquals("1", data.getString("recipient"));
|
||||
assertEquals(1, data.getLong("message_id"));
|
||||
assertEquals(2, data.getLong("timestamp"));
|
||||
|
||||
new SendDeliveryReceiptJob.Factory().create(mock(Job.Parameters.class), converted.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_sendDeliveryReceiptJob_bad() throws Exception {
|
||||
JobData testData = new JobData("SendDeliveryReceiptJob", null, -1, -1, new JsonJobData.Builder().putString("recipient", "1")
|
||||
.serialize());
|
||||
RecipientIdFollowUpJobMigration subject = new RecipientIdFollowUpJobMigration();
|
||||
JobData converted = subject.migrate(testData);
|
||||
|
||||
assertEquals("FailingJob", converted.getFactoryKey());
|
||||
assertNull(converted.getQueueKey());
|
||||
|
||||
new FailingJob.Factory().create(mock(Job.Parameters.class), converted.getData());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package org.thoughtcrime.securesms.jobmanager.migrations
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Test
|
||||
import org.thoughtcrime.securesms.jobmanager.Job
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration.JobData
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData
|
||||
import org.thoughtcrime.securesms.jobs.FailingJob
|
||||
import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob
|
||||
|
||||
class RecipientIdFollowUpJobMigrationTest {
|
||||
@Test
|
||||
fun migrate_sendDeliveryReceiptJob_good() {
|
||||
val testData = JobData(
|
||||
"SendDeliveryReceiptJob",
|
||||
null,
|
||||
-1,
|
||||
-1,
|
||||
JsonJobData.Builder().putString("recipient", "1")
|
||||
.putLong("message_id", 1)
|
||||
.putLong("timestamp", 2)
|
||||
.serialize()
|
||||
)
|
||||
val subject = RecipientIdFollowUpJobMigration()
|
||||
val converted = subject.migrate(testData)
|
||||
|
||||
assertEquals("SendDeliveryReceiptJob", converted.factoryKey)
|
||||
assertNull(converted.queueKey)
|
||||
|
||||
val data = JsonJobData.deserialize(converted.data)
|
||||
assertEquals("1", data.getString("recipient"))
|
||||
assertEquals(1, data.getLong("message_id"))
|
||||
assertEquals(2, data.getLong("timestamp"))
|
||||
|
||||
SendDeliveryReceiptJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_sendDeliveryReceiptJob_bad() {
|
||||
val testData = JobData(
|
||||
"SendDeliveryReceiptJob",
|
||||
null,
|
||||
-1,
|
||||
-1,
|
||||
JsonJobData.Builder().putString("recipient", "1")
|
||||
.serialize()
|
||||
)
|
||||
val subject = RecipientIdFollowUpJobMigration()
|
||||
val converted = subject.migrate(testData)
|
||||
|
||||
assertEquals("FailingJob", converted.factoryKey)
|
||||
assertNull(converted.queueKey)
|
||||
|
||||
FailingJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
|
||||
}
|
||||
}
|
|
@ -1,286 +0,0 @@
|
|||
package org.thoughtcrime.securesms.jobmanager.migrations;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
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.thoughtcrime.securesms.jobmanager.JsonJobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration.JobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.migrations.RecipientIdJobMigration.NewSerializableSyncMessageId;
|
||||
import org.thoughtcrime.securesms.jobmanager.migrations.RecipientIdJobMigration.OldSerializableSyncMessageId;
|
||||
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceReadUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceVerifiedUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceViewOnceOpenJob;
|
||||
import org.thoughtcrime.securesms.jobs.PushGroupSendJob;
|
||||
import org.thoughtcrime.securesms.jobs.IndividualSendJob;
|
||||
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob;
|
||||
import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class RecipientIdJobMigrationTest {
|
||||
|
||||
@Rule
|
||||
public MockitoRule rule = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private MockedStatic<Recipient> recipientMockedStatic;
|
||||
|
||||
@Mock
|
||||
private MockedStatic<Job.Parameters> jobParametersMockStatic;
|
||||
|
||||
@Test
|
||||
public void migrate_multiDeviceContactUpdateJob() throws Exception {
|
||||
JobData testData = new JobData("MultiDeviceContactUpdateJob", "MultiDeviceContactUpdateJob", -1, -1, new JsonJobData.Builder().putBoolean("force_sync", false).putString("address", "+16101234567").serialize());
|
||||
mockRecipientResolve("+16101234567", 1);
|
||||
|
||||
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
|
||||
JobData converted = subject.migrate(testData);
|
||||
JsonJobData data = JsonJobData.deserialize(converted.getData());
|
||||
|
||||
assertEquals("MultiDeviceContactUpdateJob", converted.getFactoryKey());
|
||||
assertEquals("MultiDeviceContactUpdateJob", converted.getQueueKey());
|
||||
assertFalse(data.getBoolean("force_sync"));
|
||||
assertFalse(data.hasString("address"));
|
||||
assertEquals("1", data.getString("recipient"));
|
||||
|
||||
new MultiDeviceContactUpdateJob.Factory().create(mock(Job.Parameters.class), converted.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_multiDeviceViewOnceOpenJob() throws Exception {
|
||||
OldSerializableSyncMessageId oldId = new OldSerializableSyncMessageId("+16101234567", 1);
|
||||
JobData testData = new JobData("MultiDeviceRevealUpdateJob", null, -1, -1, new JsonJobData.Builder().putString("message_id", JsonUtils.toJson(oldId)).serialize());
|
||||
mockRecipientResolve("+16101234567", 1);
|
||||
|
||||
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
|
||||
JobData converted = subject.migrate(testData);
|
||||
JsonJobData data = JsonJobData.deserialize(converted.getData());
|
||||
|
||||
assertEquals("MultiDeviceRevealUpdateJob", converted.getFactoryKey());
|
||||
assertNull(converted.getQueueKey());
|
||||
assertEquals(JsonUtils.toJson(new NewSerializableSyncMessageId("1", 1)), data.getString("message_id"));
|
||||
|
||||
new MultiDeviceViewOnceOpenJob.Factory().create(mock(Job.Parameters.class), converted.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_sendDeliveryReceiptJob() throws Exception {
|
||||
JobData testData = new JobData("SendDeliveryReceiptJob", null, -1, -1, new JsonJobData.Builder().putString("address", "+16101234567")
|
||||
.putLong("message_id", 1)
|
||||
.putLong("timestamp", 2)
|
||||
.serialize());
|
||||
mockRecipientResolve("+16101234567", 1);
|
||||
|
||||
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
|
||||
JobData converted = subject.migrate(testData);
|
||||
JsonJobData data = JsonJobData.deserialize(converted.getData());
|
||||
|
||||
assertEquals("SendDeliveryReceiptJob", converted.getFactoryKey());
|
||||
assertNull(converted.getQueueKey());
|
||||
assertEquals("1", data.getString("recipient"));
|
||||
assertEquals(1, data.getLong("message_id"));
|
||||
assertEquals(2, data.getLong("timestamp"));
|
||||
|
||||
new SendDeliveryReceiptJob.Factory().create(mock(Job.Parameters.class), converted.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_multiDeviceVerifiedUpdateJob() throws Exception {
|
||||
JobData testData = new JobData("MultiDeviceVerifiedUpdateJob", "__MULTI_DEVICE_VERIFIED_UPDATE__", -1, -1, new JsonJobData.Builder().putString("destination", "+16101234567")
|
||||
.putString("identity_key", "abcd")
|
||||
.putInt("verified_status", 1)
|
||||
.putLong("timestamp", 123)
|
||||
.serialize());
|
||||
mockRecipientResolve("+16101234567", 1);
|
||||
|
||||
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
|
||||
JobData converted = subject.migrate(testData);
|
||||
JsonJobData data = JsonJobData.deserialize(converted.getData());
|
||||
|
||||
assertEquals("MultiDeviceVerifiedUpdateJob", converted.getFactoryKey());
|
||||
assertEquals("__MULTI_DEVICE_VERIFIED_UPDATE__", converted.getQueueKey());
|
||||
assertEquals("abcd", data.getString("identity_key"));
|
||||
assertEquals(1, data.getInt("verified_status"));
|
||||
assertEquals(123, data.getLong("timestamp"));
|
||||
assertEquals("1", data.getString("destination"));
|
||||
|
||||
new MultiDeviceVerifiedUpdateJob.Factory().create(mock(Job.Parameters.class), converted.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_pushGroupSendJob_null() throws Exception {
|
||||
JobData testData = new JobData("PushGroupSendJob", "someGroupId", -1, -1, new JsonJobData.Builder().putString("filter_address", null)
|
||||
.putLong("message_id", 123)
|
||||
.serialize());
|
||||
mockRecipientResolve("someGroupId", 5);
|
||||
|
||||
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
|
||||
JobData converted = subject.migrate(testData);
|
||||
JsonJobData data = JsonJobData.deserialize(converted.getData());
|
||||
|
||||
assertEquals("PushGroupSendJob", converted.getFactoryKey());
|
||||
assertEquals(RecipientId.from(5).toQueueKey(), converted.getQueueKey());
|
||||
assertNull(data.getString("filter_recipient"));
|
||||
assertFalse(data.hasString("filter_address"));
|
||||
|
||||
new PushGroupSendJob.Factory().create(mock(Job.Parameters.class), converted.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_pushGroupSendJob_nonNull() throws Exception {
|
||||
JobData testData = new JobData("PushGroupSendJob", "someGroupId", -1, -1, new JsonJobData.Builder().putString("filter_address", "+16101234567")
|
||||
.putLong("message_id", 123)
|
||||
.serialize());
|
||||
mockRecipientResolve("+16101234567", 1);
|
||||
mockRecipientResolve("someGroupId", 5);
|
||||
|
||||
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
|
||||
JobData converted = subject.migrate(testData);
|
||||
JsonJobData data = JsonJobData.deserialize(converted.getData());
|
||||
|
||||
assertEquals("PushGroupSendJob", converted.getFactoryKey());
|
||||
assertEquals(RecipientId.from(5).toQueueKey(), converted.getQueueKey());
|
||||
assertEquals("1", data.getString("filter_recipient"));
|
||||
assertFalse(data.hasString("filter_address"));
|
||||
|
||||
new PushGroupSendJob.Factory().create(mock(Job.Parameters.class), converted.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_directoryRefreshJob_null() throws Exception {
|
||||
JobData testData = new JobData("DirectoryRefreshJob", "DirectoryRefreshJob", -1, -1, new JsonJobData.Builder().putString("address", null).putBoolean("notify_of_new_users", true).serialize());
|
||||
|
||||
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
|
||||
JobData converted = subject.migrate(testData);
|
||||
JsonJobData data = JsonJobData.deserialize(converted.getData());
|
||||
|
||||
assertEquals("DirectoryRefreshJob", converted.getFactoryKey());
|
||||
assertEquals("DirectoryRefreshJob", converted.getQueueKey());
|
||||
assertNull(data.getString("recipient"));
|
||||
assertTrue(data.getBoolean("notify_of_new_users"));
|
||||
assertFalse(data.hasString("address"));
|
||||
|
||||
new DirectoryRefreshJob.Factory().create(mock(Job.Parameters.class), converted.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_directoryRefreshJob_nonNull() throws Exception {
|
||||
JobData testData = new JobData("DirectoryRefreshJob", "DirectoryRefreshJob", -1, -1, new JsonJobData.Builder().putString("address", "+16101234567").putBoolean("notify_of_new_users", true).serialize());
|
||||
mockRecipientResolve("+16101234567", 1);
|
||||
|
||||
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
|
||||
JobData converted = subject.migrate(testData);
|
||||
JsonJobData data = JsonJobData.deserialize(converted.getData());
|
||||
|
||||
assertEquals("DirectoryRefreshJob", converted.getFactoryKey());
|
||||
assertEquals("DirectoryRefreshJob", converted.getQueueKey());
|
||||
assertTrue(data.getBoolean("notify_of_new_users"));
|
||||
assertEquals("1", data.getString("recipient"));
|
||||
assertFalse(data.hasString("address"));
|
||||
|
||||
new DirectoryRefreshJob.Factory().create(mock(Job.Parameters.class), converted.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_retrieveProfileAvatarJob() throws Exception {
|
||||
JobData testData = new JobData("RetrieveProfileAvatarJob", "RetrieveProfileAvatarJob+16101234567", -1, -1, new JsonJobData.Builder().putString("address", "+16101234567").putString("profile_avatar", "abc").serialize());
|
||||
mockRecipientResolve("+16101234567", 1);
|
||||
|
||||
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
|
||||
JobData converted = subject.migrate(testData);
|
||||
JsonJobData data = JsonJobData.deserialize(converted.getData());
|
||||
|
||||
assertEquals("RetrieveProfileAvatarJob", converted.getFactoryKey());
|
||||
assertEquals("RetrieveProfileAvatarJob::" + RecipientId.from(1).toQueueKey(), converted.getQueueKey());
|
||||
assertEquals("1", data.getString("recipient"));
|
||||
|
||||
|
||||
new RetrieveProfileAvatarJob.Factory().create(mock(Job.Parameters.class), converted.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_multiDeviceReadUpdateJob_empty() throws Exception {
|
||||
JobData testData = new JobData("MultiDeviceReadUpdateJob", null, -1, -1, new JsonJobData.Builder().putStringArray("message_ids", new String[0]).serialize());
|
||||
|
||||
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
|
||||
JobData converted = subject.migrate(testData);
|
||||
JsonJobData data = JsonJobData.deserialize(converted.getData());
|
||||
|
||||
assertEquals("MultiDeviceReadUpdateJob", converted.getFactoryKey());
|
||||
assertNull(converted.getQueueKey());
|
||||
assertEquals(0, data.getStringArray("message_ids").length);
|
||||
|
||||
new MultiDeviceReadUpdateJob.Factory().create(mock(Job.Parameters.class), converted.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_multiDeviceReadUpdateJob_twoIds() throws Exception {
|
||||
OldSerializableSyncMessageId id1 = new OldSerializableSyncMessageId("+16101234567", 1);
|
||||
OldSerializableSyncMessageId id2 = new OldSerializableSyncMessageId("+16101112222", 2);
|
||||
|
||||
JobData testData = new JobData("MultiDeviceReadUpdateJob", null, -1, -1, new JsonJobData.Builder().putStringArray("message_ids", new String[]{ JsonUtils.toJson(id1), JsonUtils.toJson(id2) }).serialize());
|
||||
mockRecipientResolve("+16101234567", 1);
|
||||
mockRecipientResolve("+16101112222", 2);
|
||||
|
||||
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
|
||||
JobData converted = subject.migrate(testData);
|
||||
JsonJobData data = JsonJobData.deserialize(converted.getData());
|
||||
|
||||
assertEquals("MultiDeviceReadUpdateJob", converted.getFactoryKey());
|
||||
assertNull(converted.getQueueKey());
|
||||
|
||||
String[] updated = data.getStringArray("message_ids");
|
||||
assertEquals(2, updated.length);
|
||||
|
||||
assertEquals(JsonUtils.toJson(new NewSerializableSyncMessageId("1", 1)), updated[0]);
|
||||
assertEquals(JsonUtils.toJson(new NewSerializableSyncMessageId("2", 2)), updated[1]);
|
||||
|
||||
new MultiDeviceReadUpdateJob.Factory().create(mock(Job.Parameters.class), converted.getData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrate_pushMediaSendJob() throws Exception {
|
||||
JobData testData = new JobData("PushMediaSendJob", "+16101234567", -1, -1, new JsonJobData.Builder().putLong("message_id", 1).serialize());
|
||||
mockRecipientResolve("+16101234567", 1);
|
||||
|
||||
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
|
||||
JobData converted = subject.migrate(testData);
|
||||
JsonJobData data = JsonJobData.deserialize(converted.getData());
|
||||
|
||||
assertEquals("PushMediaSendJob", converted.getFactoryKey());
|
||||
assertEquals(RecipientId.from(1).toQueueKey(), converted.getQueueKey());
|
||||
assertEquals(1, data.getLong("message_id"));
|
||||
|
||||
new IndividualSendJob.Factory().create(mock(Job.Parameters.class), converted.getData());
|
||||
}
|
||||
|
||||
private void mockRecipientResolve(String address, long recipientId) {
|
||||
Recipient mockRecipient = mockRecipient(recipientId);
|
||||
recipientMockedStatic.when(() -> Recipient.external(any(), eq(address))).thenReturn(mockRecipient);
|
||||
}
|
||||
|
||||
private Recipient mockRecipient(long id) {
|
||||
Recipient recipient = mock(Recipient.class);
|
||||
when(recipient.getId()).thenReturn(RecipientId.from(id));
|
||||
return recipient;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,365 @@
|
|||
package org.thoughtcrime.securesms.jobmanager.migrations
|
||||
|
||||
import android.app.Application
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkObject
|
||||
import io.mockk.unmockkAll
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.thoughtcrime.securesms.jobmanager.Job
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration.JobData
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData
|
||||
import org.thoughtcrime.securesms.jobmanager.migrations.RecipientIdJobMigration.NewSerializableSyncMessageId
|
||||
import org.thoughtcrime.securesms.jobmanager.migrations.RecipientIdJobMigration.OldSerializableSyncMessageId
|
||||
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob
|
||||
import org.thoughtcrime.securesms.jobs.IndividualSendJob
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceReadUpdateJob
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceVerifiedUpdateJob
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceViewOnceOpenJob
|
||||
import org.thoughtcrime.securesms.jobs.PushGroupSendJob
|
||||
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
|
||||
import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.util.JsonUtils
|
||||
|
||||
class RecipientIdJobMigrationTest {
|
||||
@Before
|
||||
fun setup() {
|
||||
mockkObject(Recipient)
|
||||
every { Recipient.live(any()) } returns mockk<LiveRecipient>(relaxed = true)
|
||||
}
|
||||
|
||||
@After
|
||||
fun cleanup() {
|
||||
unmockkAll()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_multiDeviceContactUpdateJob() {
|
||||
val testData = JobData(
|
||||
factoryKey = "MultiDeviceContactUpdateJob",
|
||||
queueKey = "MultiDeviceContactUpdateJob",
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder().putBoolean("force_sync", false).putString("address", "+16101234567").serialize()
|
||||
)
|
||||
mockRecipientResolve("+16101234567", 1)
|
||||
|
||||
val subject = RecipientIdJobMigration(mockk<Application>())
|
||||
val converted = subject.migrate(testData)
|
||||
val data = JsonJobData.deserialize(converted.data)
|
||||
|
||||
assertEquals("MultiDeviceContactUpdateJob", converted.factoryKey)
|
||||
assertEquals("MultiDeviceContactUpdateJob", converted.queueKey)
|
||||
assertFalse(data.getBoolean("force_sync"))
|
||||
assertFalse(data.hasString("address"))
|
||||
assertEquals("1", data.getString("recipient"))
|
||||
|
||||
MultiDeviceContactUpdateJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_multiDeviceViewOnceOpenJob() {
|
||||
val oldId = OldSerializableSyncMessageId("+16101234567", 1)
|
||||
val testData = JobData(
|
||||
factoryKey = "MultiDeviceRevealUpdateJob",
|
||||
queueKey = null,
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder().putString("message_id", JsonUtils.toJson(oldId)).serialize()
|
||||
)
|
||||
mockRecipientResolve("+16101234567", 1)
|
||||
|
||||
val subject = RecipientIdJobMigration(mockk<Application>())
|
||||
val converted = subject.migrate(testData)
|
||||
val data = JsonJobData.deserialize(converted.data)
|
||||
|
||||
assertEquals("MultiDeviceRevealUpdateJob", converted.factoryKey)
|
||||
assertNull(converted.queueKey)
|
||||
assertEquals(JsonUtils.toJson(NewSerializableSyncMessageId("1", 1)), data.getString("message_id"))
|
||||
|
||||
MultiDeviceViewOnceOpenJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_sendDeliveryReceiptJob() {
|
||||
val testData = JobData(
|
||||
factoryKey = "SendDeliveryReceiptJob",
|
||||
queueKey = null,
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder().putString("address", "+16101234567")
|
||||
.putLong("message_id", 1)
|
||||
.putLong("timestamp", 2)
|
||||
.serialize()
|
||||
)
|
||||
mockRecipientResolve("+16101234567", 1)
|
||||
|
||||
val subject = RecipientIdJobMigration(mockk<Application>())
|
||||
val converted = subject.migrate(testData)
|
||||
val data = JsonJobData.deserialize(converted.data)
|
||||
|
||||
assertEquals("SendDeliveryReceiptJob", converted.factoryKey)
|
||||
assertNull(converted.queueKey)
|
||||
assertEquals("1", data.getString("recipient"))
|
||||
assertEquals(1, data.getLong("message_id"))
|
||||
assertEquals(2, data.getLong("timestamp"))
|
||||
|
||||
SendDeliveryReceiptJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_multiDeviceVerifiedUpdateJob() {
|
||||
val testData = JobData(
|
||||
factoryKey = "MultiDeviceVerifiedUpdateJob",
|
||||
queueKey = "__MULTI_DEVICE_VERIFIED_UPDATE__",
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder().putString("destination", "+16101234567")
|
||||
.putString("identity_key", "abcd")
|
||||
.putInt("verified_status", 1)
|
||||
.putLong("timestamp", 123)
|
||||
.serialize()
|
||||
)
|
||||
mockRecipientResolve("+16101234567", 1)
|
||||
|
||||
val subject = RecipientIdJobMigration(mockk<Application>())
|
||||
val converted = subject.migrate(testData)
|
||||
val data = JsonJobData.deserialize(converted.data)
|
||||
|
||||
assertEquals("MultiDeviceVerifiedUpdateJob", converted.factoryKey)
|
||||
assertEquals("__MULTI_DEVICE_VERIFIED_UPDATE__", converted.queueKey)
|
||||
assertEquals("abcd", data.getString("identity_key"))
|
||||
assertEquals(1, data.getInt("verified_status"))
|
||||
assertEquals(123, data.getLong("timestamp"))
|
||||
assertEquals("1", data.getString("destination"))
|
||||
|
||||
MultiDeviceVerifiedUpdateJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_pushGroupSendJob_null() {
|
||||
val testData = JobData(
|
||||
factoryKey = "PushGroupSendJob",
|
||||
queueKey = "someGroupId",
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder().putString("filter_address", null)
|
||||
.putLong("message_id", 123)
|
||||
.serialize()
|
||||
)
|
||||
mockRecipientResolve("someGroupId", 5)
|
||||
|
||||
val subject = RecipientIdJobMigration(mockk<Application>())
|
||||
val converted = subject.migrate(testData)
|
||||
val data = JsonJobData.deserialize(converted.data)
|
||||
|
||||
assertEquals("PushGroupSendJob", converted.factoryKey)
|
||||
assertEquals(RecipientId.from(5).toQueueKey(), converted.queueKey)
|
||||
assertNull(data.getString("filter_recipient"))
|
||||
assertFalse(data.hasString("filter_address"))
|
||||
|
||||
PushGroupSendJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_pushGroupSendJob_nonNull() {
|
||||
val testData = JobData(
|
||||
factoryKey = "PushGroupSendJob",
|
||||
queueKey = "someGroupId",
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder().putString("filter_address", "+16101234567")
|
||||
.putLong("message_id", 123)
|
||||
.serialize()
|
||||
)
|
||||
mockRecipientResolve("+16101234567", 1)
|
||||
mockRecipientResolve("someGroupId", 5)
|
||||
|
||||
val subject = RecipientIdJobMigration(mockk<Application>())
|
||||
val converted = subject.migrate(testData)
|
||||
val data = JsonJobData.deserialize(converted.data)
|
||||
|
||||
assertEquals("PushGroupSendJob", converted.factoryKey)
|
||||
assertEquals(RecipientId.from(5).toQueueKey(), converted.queueKey)
|
||||
assertEquals("1", data.getString("filter_recipient"))
|
||||
assertFalse(data.hasString("filter_address"))
|
||||
|
||||
PushGroupSendJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_directoryRefreshJob_null() {
|
||||
val testData = JobData(
|
||||
factoryKey = "DirectoryRefreshJob",
|
||||
queueKey = "DirectoryRefreshJob",
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder()
|
||||
.putString("address", null)
|
||||
.putBoolean("notify_of_new_users", true)
|
||||
.serialize()
|
||||
)
|
||||
|
||||
val subject = RecipientIdJobMigration(mockk<Application>())
|
||||
val converted = subject.migrate(testData)
|
||||
val data = JsonJobData.deserialize(converted.data)
|
||||
|
||||
assertEquals("DirectoryRefreshJob", converted.factoryKey)
|
||||
assertEquals("DirectoryRefreshJob", converted.queueKey)
|
||||
assertNull(data.getString("recipient"))
|
||||
assertTrue(data.getBoolean("notify_of_new_users"))
|
||||
assertFalse(data.hasString("address"))
|
||||
|
||||
DirectoryRefreshJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_directoryRefreshJob_nonNull() {
|
||||
val testData = JobData(
|
||||
factoryKey = "DirectoryRefreshJob",
|
||||
queueKey = "DirectoryRefreshJob",
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder()
|
||||
.putString("address", "+16101234567")
|
||||
.putBoolean("notify_of_new_users", true)
|
||||
.serialize()
|
||||
)
|
||||
mockRecipientResolve("+16101234567", 1)
|
||||
|
||||
val subject = RecipientIdJobMigration(mockk<Application>())
|
||||
val converted = subject.migrate(testData)
|
||||
val data = JsonJobData.deserialize(converted.data)
|
||||
|
||||
assertEquals("DirectoryRefreshJob", converted.factoryKey)
|
||||
assertEquals("DirectoryRefreshJob", converted.queueKey)
|
||||
assertTrue(data.getBoolean("notify_of_new_users"))
|
||||
assertEquals("1", data.getString("recipient"))
|
||||
assertFalse(data.hasString("address"))
|
||||
|
||||
DirectoryRefreshJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_retrieveProfileAvatarJob() {
|
||||
val testData = JobData(
|
||||
factoryKey = "RetrieveProfileAvatarJob",
|
||||
queueKey = "RetrieveProfileAvatarJob+16101234567",
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder()
|
||||
.putString("address", "+16101234567")
|
||||
.putString("profile_avatar", "abc")
|
||||
.serialize()
|
||||
)
|
||||
mockRecipientResolve("+16101234567", 1)
|
||||
|
||||
val subject = RecipientIdJobMigration(mockk<Application>())
|
||||
val converted = subject.migrate(testData)
|
||||
val data = JsonJobData.deserialize(converted.data)
|
||||
|
||||
assertEquals("RetrieveProfileAvatarJob", converted.factoryKey)
|
||||
assertEquals("RetrieveProfileAvatarJob::" + RecipientId.from(1).toQueueKey(), converted.queueKey)
|
||||
assertEquals("1", data.getString("recipient"))
|
||||
|
||||
RetrieveProfileAvatarJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_multiDeviceReadUpdateJob_empty() {
|
||||
val testData = JobData(
|
||||
factoryKey = "MultiDeviceReadUpdateJob",
|
||||
queueKey = null,
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder()
|
||||
.putStringArray("message_ids", arrayOfNulls(0))
|
||||
.serialize()
|
||||
)
|
||||
|
||||
val subject = RecipientIdJobMigration(mockk<Application>())
|
||||
val converted = subject.migrate(testData)
|
||||
val data = JsonJobData.deserialize(converted.data)
|
||||
|
||||
assertEquals("MultiDeviceReadUpdateJob", converted.factoryKey)
|
||||
assertNull(converted.queueKey)
|
||||
assertEquals(0, data.getStringArray("message_ids").size)
|
||||
|
||||
MultiDeviceReadUpdateJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_multiDeviceReadUpdateJob_twoIds() {
|
||||
val id1 = OldSerializableSyncMessageId("+16101234567", 1)
|
||||
val id2 = OldSerializableSyncMessageId("+16101112222", 2)
|
||||
|
||||
val testData = JobData(
|
||||
factoryKey = "MultiDeviceReadUpdateJob",
|
||||
queueKey = null,
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder()
|
||||
.putStringArray("message_ids", arrayOf(JsonUtils.toJson(id1), JsonUtils.toJson(id2)))
|
||||
.serialize()
|
||||
)
|
||||
mockRecipientResolve("+16101234567", 1)
|
||||
mockRecipientResolve("+16101112222", 2)
|
||||
|
||||
val subject = RecipientIdJobMigration(mockk<Application>())
|
||||
val converted = subject.migrate(testData)
|
||||
val data = JsonJobData.deserialize(converted.data)
|
||||
|
||||
assertEquals("MultiDeviceReadUpdateJob", converted.factoryKey)
|
||||
assertNull(converted.queueKey)
|
||||
|
||||
val updated = data.getStringArray("message_ids")
|
||||
assertEquals(2, updated.size)
|
||||
|
||||
assertEquals(JsonUtils.toJson(NewSerializableSyncMessageId("1", 1)), updated[0])
|
||||
assertEquals(JsonUtils.toJson(NewSerializableSyncMessageId("2", 2)), updated[1])
|
||||
|
||||
MultiDeviceReadUpdateJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun migrate_pushMediaSendJob() {
|
||||
val testData = JobData(
|
||||
factoryKey = "PushMediaSendJob",
|
||||
queueKey = "+16101234567",
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder().putLong("message_id", 1).serialize()
|
||||
)
|
||||
mockRecipientResolve("+16101234567", 1)
|
||||
|
||||
val subject = RecipientIdJobMigration(mockk<Application>())
|
||||
val converted = subject.migrate(testData)
|
||||
val data = JsonJobData.deserialize(converted.data)
|
||||
|
||||
assertEquals("PushMediaSendJob", converted.factoryKey)
|
||||
assertEquals(RecipientId.from(1).toQueueKey(), converted.queueKey)
|
||||
assertEquals(1, data.getLong("message_id"))
|
||||
|
||||
IndividualSendJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
|
||||
}
|
||||
|
||||
private fun mockRecipientResolve(address: String, recipientId: Long) {
|
||||
every { Recipient.external(any(), address) } returns mockRecipient(recipientId)
|
||||
}
|
||||
|
||||
private fun mockRecipient(id: Long): Recipient {
|
||||
return mockk<Recipient> {
|
||||
every { this@mockk.id } returns RecipientId.from(id)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
package org.thoughtcrime.securesms.jobmanager.migrations;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.thoughtcrime.securesms.database.MessageTable;
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration;
|
||||
import org.thoughtcrime.securesms.jobs.SendReadReceiptJob;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class SendReadReceiptsJobMigrationTest {
|
||||
|
||||
private final MessageTable mockDatabase = mock(MessageTable.class);
|
||||
private final SendReadReceiptsJobMigration testSubject = new SendReadReceiptsJobMigration(mockDatabase);
|
||||
|
||||
@Test
|
||||
public void givenSendReadReceiptJobDataWithoutThreadIdAndThreadIdFound_whenIMigrate_thenIInsertThreadId() {
|
||||
// GIVEN
|
||||
SendReadReceiptJob job = new SendReadReceiptJob(1, RecipientId.from(2), new ArrayList<>(), new ArrayList<>());
|
||||
JobMigration.JobData jobData = new JobMigration.JobData(job.getFactoryKey(),
|
||||
"asdf",
|
||||
-1,
|
||||
-1,
|
||||
new JsonJobData.Builder()
|
||||
.putString("recipient", RecipientId.from(2).serialize())
|
||||
.putLongArray("message_ids", new long[]{1, 2, 3, 4, 5})
|
||||
.putLong("timestamp", 292837649).serialize());
|
||||
when(mockDatabase.getThreadIdForMessage(anyLong())).thenReturn(1234L);
|
||||
|
||||
// WHEN
|
||||
JobMigration.JobData result = testSubject.migrate(jobData);
|
||||
JsonJobData data = JsonJobData.deserialize(result.getData());
|
||||
|
||||
// THEN
|
||||
assertEquals(1234L, data.getLong("thread"));
|
||||
assertEquals(RecipientId.from(2).serialize(), data.getString("recipient"));
|
||||
assertTrue(data.hasLongArray("message_ids"));
|
||||
assertTrue(data.hasLong("timestamp"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSendReadReceiptJobDataWithoutThreadIdAndThreadIdNotFound_whenIMigrate_thenIGetAFailingJob() {
|
||||
// GIVEN
|
||||
SendReadReceiptJob job = new SendReadReceiptJob(1, RecipientId.from(2), new ArrayList<>(), new ArrayList<>());
|
||||
JobMigration.JobData jobData = new JobMigration.JobData(job.getFactoryKey(),
|
||||
"asdf",
|
||||
-1,
|
||||
-1,
|
||||
new JsonJobData.Builder()
|
||||
.putString("recipient", RecipientId.from(2).serialize())
|
||||
.putLongArray("message_ids", new long[]{})
|
||||
.putLong("timestamp", 292837649).serialize());
|
||||
when(mockDatabase.getThreadIdForMessage(anyLong())).thenReturn(-1L);
|
||||
|
||||
// WHEN
|
||||
JobMigration.JobData result = testSubject.migrate(jobData);
|
||||
|
||||
// THEN
|
||||
assertEquals("FailingJob", result.getFactoryKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSendReadReceiptJobDataWithThreadId_whenIMigrate_thenIDoNotReplace() {
|
||||
// GIVEN
|
||||
SendReadReceiptJob job = new SendReadReceiptJob(1, RecipientId.from(2), new ArrayList<>(), new ArrayList<>());
|
||||
JobMigration.JobData jobData = new JobMigration.JobData(job.getFactoryKey(), "asdf", -1, -1, job.serialize());
|
||||
|
||||
// WHEN
|
||||
JobMigration.JobData result = testSubject.migrate(jobData);
|
||||
|
||||
// THEN
|
||||
assertEquals(jobData, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSomeOtherJobDataWithThreadId_whenIMigrate_thenIDoNotReplace() {
|
||||
// GIVEN
|
||||
JobMigration.JobData jobData = new JobMigration.JobData("SomeOtherJob", "asdf", -1, -1, new JsonJobData.Builder().putLong("thread", 1).serialize());
|
||||
|
||||
// WHEN
|
||||
JobMigration.JobData result = testSubject.migrate(jobData);
|
||||
|
||||
// THEN
|
||||
assertEquals(jobData, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSomeOtherJobDataWithoutThreadId_whenIMigrate_thenIDoNotReplace() {
|
||||
// GIVEN
|
||||
JobMigration.JobData jobData = new JobMigration.JobData("SomeOtherJob", "asdf", -1, -1, new JsonJobData.Builder().serialize());
|
||||
|
||||
// WHEN
|
||||
JobMigration.JobData result = testSubject.migrate(jobData);
|
||||
|
||||
// THEN
|
||||
assertEquals(jobData, result);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package org.thoughtcrime.securesms.jobmanager.migrations
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.thoughtcrime.securesms.database.MessageTable
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration.JobData
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData
|
||||
import org.thoughtcrime.securesms.jobs.SendReadReceiptJob
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
|
||||
class SendReadReceiptsJobMigrationTest {
|
||||
private val mockDatabase = mockk<MessageTable>()
|
||||
private val testSubject = SendReadReceiptsJobMigration(mockDatabase)
|
||||
|
||||
@Test
|
||||
fun givenSendReadReceiptJobDataWithoutThreadIdAndThreadIdFound_whenIMigrate_thenIInsertThreadId() {
|
||||
// GIVEN
|
||||
val job = SendReadReceiptJob(1, RecipientId.from(2), ArrayList(), ArrayList())
|
||||
val jobData = JobData(
|
||||
factoryKey = job.factoryKey,
|
||||
queueKey = "asdf",
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder()
|
||||
.putString("recipient", RecipientId.from(2).serialize())
|
||||
.putLongArray("message_ids", longArrayOf(1, 2, 3, 4, 5))
|
||||
.putLong("timestamp", 292837649).serialize()
|
||||
)
|
||||
every { mockDatabase.getThreadIdForMessage(any()) } returns 1234L
|
||||
|
||||
// WHEN
|
||||
val result = testSubject.migrate(jobData)
|
||||
val data = JsonJobData.deserialize(result.data)
|
||||
|
||||
// THEN
|
||||
assertEquals(1234L, data.getLong("thread"))
|
||||
assertEquals(RecipientId.from(2).serialize(), data.getString("recipient"))
|
||||
assertTrue(data.hasLongArray("message_ids"))
|
||||
assertTrue(data.hasLong("timestamp"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenSendReadReceiptJobDataWithoutThreadIdAndThreadIdNotFound_whenIMigrate_thenIGetAFailingJob() {
|
||||
// GIVEN
|
||||
val job = SendReadReceiptJob(1, RecipientId.from(2), ArrayList(), ArrayList())
|
||||
val jobData = JobData(
|
||||
factoryKey = job.factoryKey,
|
||||
queueKey = "asdf",
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder()
|
||||
.putString("recipient", RecipientId.from(2).serialize())
|
||||
.putLongArray("message_ids", longArrayOf())
|
||||
.putLong("timestamp", 292837649).serialize()
|
||||
)
|
||||
every { mockDatabase.getThreadIdForMessage(any()) } returns -1L
|
||||
|
||||
// WHEN
|
||||
val result = testSubject.migrate(jobData)
|
||||
|
||||
// THEN
|
||||
assertEquals("FailingJob", result.factoryKey)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenSendReadReceiptJobDataWithThreadId_whenIMigrate_thenIDoNotReplace() {
|
||||
// GIVEN
|
||||
val job = SendReadReceiptJob(1, RecipientId.from(2), ArrayList(), ArrayList())
|
||||
val jobData = JobData(job.factoryKey, "asdf", -1, -1, job.serialize())
|
||||
|
||||
// WHEN
|
||||
val result = testSubject.migrate(jobData)
|
||||
|
||||
// THEN
|
||||
assertEquals(jobData, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenSomeOtherJobDataWithThreadId_whenIMigrate_thenIDoNotReplace() {
|
||||
// GIVEN
|
||||
val jobData = JobData("SomeOtherJob", "asdf", -1, -1, JsonJobData.Builder().putLong("thread", 1).serialize())
|
||||
|
||||
// WHEN
|
||||
val result = testSubject.migrate(jobData)
|
||||
|
||||
// THEN
|
||||
assertEquals(jobData, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenSomeOtherJobDataWithoutThreadId_whenIMigrate_thenIDoNotReplace() {
|
||||
// GIVEN
|
||||
val jobData = JobData("SomeOtherJob", "asdf", -1, -1, JsonJobData.Builder().serialize())
|
||||
|
||||
// WHEN
|
||||
val result = testSubject.migrate(jobData)
|
||||
|
||||
// THEN
|
||||
assertEquals(jobData, result)
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
package org.thoughtcrime.securesms.jobmanager.migrations;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.thoughtcrime.securesms.database.GroupTable;
|
||||
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration;
|
||||
import org.thoughtcrime.securesms.jobs.FailingJob;
|
||||
import org.thoughtcrime.securesms.jobs.SenderKeyDistributionSendJob;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class SenderKeyDistributionSendJobRecipientMigrationTest {
|
||||
|
||||
private final GroupTable mockDatabase = mock(GroupTable.class);
|
||||
private final SenderKeyDistributionSendJobRecipientMigration testSubject = new SenderKeyDistributionSendJobRecipientMigration(mockDatabase);
|
||||
|
||||
private static final GroupId GROUP_ID = GroupId.pushOrThrow(Util.getSecretBytes(32));
|
||||
|
||||
@Test
|
||||
public void normalMigration() {
|
||||
// GIVEN
|
||||
JobMigration.JobData jobData = new JobMigration.JobData(SenderKeyDistributionSendJob.KEY,
|
||||
"asdf",
|
||||
-1,
|
||||
-1,
|
||||
new JsonJobData.Builder()
|
||||
.putString("recipient_id", RecipientId.from(1).serialize())
|
||||
.putBlobAsString("group_id", GROUP_ID.getDecodedId())
|
||||
.serialize());
|
||||
|
||||
GroupRecord mockGroup = mock(GroupRecord.class);
|
||||
when(mockGroup.getRecipientId()).thenReturn(RecipientId.from(2));
|
||||
when(mockDatabase.getGroup(GROUP_ID)).thenReturn(Optional.of(mockGroup));
|
||||
|
||||
// WHEN
|
||||
JobMigration.JobData result = testSubject.migrate(jobData);
|
||||
JsonJobData data = JsonJobData.deserialize(result.getData());
|
||||
|
||||
// THEN
|
||||
assertEquals(RecipientId.from(1).serialize(), data.getString("recipient_id"));
|
||||
assertEquals(RecipientId.from(2).serialize(), data.getString("thread_recipient_id"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cannotFindGroup() {
|
||||
// GIVEN
|
||||
JobMigration.JobData jobData = new JobMigration.JobData(SenderKeyDistributionSendJob.KEY,
|
||||
"asdf",
|
||||
-1,
|
||||
-1,
|
||||
new JsonJobData.Builder()
|
||||
.putString("recipient_id", RecipientId.from(1).serialize())
|
||||
.putBlobAsString("group_id", GROUP_ID.getDecodedId())
|
||||
.serialize());
|
||||
|
||||
// WHEN
|
||||
JobMigration.JobData result = testSubject.migrate(jobData);
|
||||
|
||||
// THEN
|
||||
assertEquals(FailingJob.KEY, result.getFactoryKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingGroupId() {
|
||||
// GIVEN
|
||||
JobMigration.JobData jobData = new JobMigration.JobData(SenderKeyDistributionSendJob.KEY,
|
||||
"asdf",
|
||||
-1,
|
||||
-1,
|
||||
new JsonJobData.Builder()
|
||||
.putString("recipient_id", RecipientId.from(1).serialize())
|
||||
.serialize());
|
||||
|
||||
// WHEN
|
||||
JobMigration.JobData result = testSubject.migrate(jobData);
|
||||
|
||||
// THEN
|
||||
assertEquals(FailingJob.KEY, result.getFactoryKey());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package org.thoughtcrime.securesms.jobmanager.migrations
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.thoughtcrime.securesms.database.GroupTable
|
||||
import org.thoughtcrime.securesms.database.model.GroupRecord
|
||||
import org.thoughtcrime.securesms.groups.GroupId
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration.JobData
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData
|
||||
import org.thoughtcrime.securesms.jobs.FailingJob
|
||||
import org.thoughtcrime.securesms.jobs.SenderKeyDistributionSendJob
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import java.util.Optional
|
||||
|
||||
class SenderKeyDistributionSendJobRecipientMigrationTest {
|
||||
private val mockDatabase = mockk<GroupTable>(relaxed = true)
|
||||
private val testSubject = SenderKeyDistributionSendJobRecipientMigration(mockDatabase)
|
||||
|
||||
@Test
|
||||
fun normalMigration() {
|
||||
// GIVEN
|
||||
val jobData = JobData(
|
||||
factoryKey = SenderKeyDistributionSendJob.KEY,
|
||||
queueKey = "asdf",
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder()
|
||||
.putString("recipient_id", RecipientId.from(1).serialize())
|
||||
.putBlobAsString("group_id", GROUP_ID.decodedId)
|
||||
.serialize()
|
||||
)
|
||||
|
||||
val mockGroup = mockk<GroupRecord> {
|
||||
every { recipientId } returns RecipientId.from(2)
|
||||
}
|
||||
every { mockDatabase.getGroup(GROUP_ID) } returns Optional.of(mockGroup)
|
||||
|
||||
// WHEN
|
||||
val result = testSubject.migrate(jobData)
|
||||
val data = JsonJobData.deserialize(result.data)
|
||||
|
||||
// THEN
|
||||
assertEquals(RecipientId.from(1).serialize(), data.getString("recipient_id"))
|
||||
assertEquals(RecipientId.from(2).serialize(), data.getString("thread_recipient_id"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cannotFindGroup() {
|
||||
// GIVEN
|
||||
val jobData = JobData(
|
||||
factoryKey = SenderKeyDistributionSendJob.KEY,
|
||||
queueKey = "asdf",
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder()
|
||||
.putString("recipient_id", RecipientId.from(1).serialize())
|
||||
.putBlobAsString("group_id", GROUP_ID.decodedId)
|
||||
.serialize()
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val result = testSubject.migrate(jobData)
|
||||
|
||||
// THEN
|
||||
assertEquals(FailingJob.KEY, result.factoryKey)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun missingGroupId() {
|
||||
// GIVEN
|
||||
val jobData = JobData(
|
||||
factoryKey = SenderKeyDistributionSendJob.KEY,
|
||||
queueKey = "asdf",
|
||||
maxAttempts = -1,
|
||||
lifespan = -1,
|
||||
data = JsonJobData.Builder()
|
||||
.putString("recipient_id", RecipientId.from(1).serialize())
|
||||
.serialize()
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val result = testSubject.migrate(jobData)
|
||||
|
||||
// THEN
|
||||
assertEquals(FailingJob.KEY, result.factoryKey)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val GROUP_ID: GroupId = GroupId.pushOrThrow(Util.getSecretBytes(32))
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package org.thoughtcrime.securesms.payments;
|
||||
|
||||
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.thoughtcrime.securesms.util.RemoteConfig;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public final class GeographicalRestrictionsTest {
|
||||
|
||||
@Rule
|
||||
public MockitoRule rule = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private MockedStatic<RemoteConfig> remoteConfigMockedStatic;
|
||||
|
||||
@Test
|
||||
public void e164Allowed_general() {
|
||||
when(RemoteConfig.paymentsCountryBlocklist()).thenReturn("");
|
||||
assertTrue(GeographicalRestrictions.e164Allowed("+15551234567"));
|
||||
|
||||
when(RemoteConfig.paymentsCountryBlocklist()).thenReturn("1");
|
||||
assertFalse(GeographicalRestrictions.e164Allowed("+15551234567"));
|
||||
|
||||
when(RemoteConfig.paymentsCountryBlocklist()).thenReturn("1,44");
|
||||
assertFalse(GeographicalRestrictions.e164Allowed("+15551234567"));
|
||||
assertFalse(GeographicalRestrictions.e164Allowed("+445551234567"));
|
||||
assertTrue(GeographicalRestrictions.e164Allowed("+525551234567"));
|
||||
|
||||
when(RemoteConfig.paymentsCountryBlocklist()).thenReturn("1 234,44");
|
||||
assertFalse(GeographicalRestrictions.e164Allowed("+12341234567"));
|
||||
assertTrue(GeographicalRestrictions.e164Allowed("+15551234567"));
|
||||
assertTrue(GeographicalRestrictions.e164Allowed("+525551234567"));
|
||||
assertTrue(GeographicalRestrictions.e164Allowed("+2345551234567"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void e164Allowed_nullNotAllowed() {
|
||||
assertFalse(GeographicalRestrictions.e164Allowed(null));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package org.thoughtcrime.securesms.payments
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockkStatic
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
|
||||
class GeographicalRestrictionsTest {
|
||||
@Test
|
||||
fun e164Allowed_general() {
|
||||
mockkStatic(RemoteConfig::class) {
|
||||
every { RemoteConfig.paymentsCountryBlocklist } returns ""
|
||||
assertTrue(GeographicalRestrictions.e164Allowed("+15551234567"))
|
||||
|
||||
every { RemoteConfig.paymentsCountryBlocklist } returns "1"
|
||||
assertFalse(GeographicalRestrictions.e164Allowed("+15551234567"))
|
||||
|
||||
every { RemoteConfig.paymentsCountryBlocklist } returns "1,44"
|
||||
assertFalse(GeographicalRestrictions.e164Allowed("+15551234567"))
|
||||
assertFalse(GeographicalRestrictions.e164Allowed("+445551234567"))
|
||||
assertTrue(GeographicalRestrictions.e164Allowed("+525551234567"))
|
||||
|
||||
every { RemoteConfig.paymentsCountryBlocklist } returns "1 234,44"
|
||||
assertFalse(GeographicalRestrictions.e164Allowed("+12341234567"))
|
||||
assertTrue(GeographicalRestrictions.e164Allowed("+15551234567"))
|
||||
assertTrue(GeographicalRestrictions.e164Allowed("+525551234567"))
|
||||
assertTrue(GeographicalRestrictions.e164Allowed("+2345551234567"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun e164Allowed_nullNotAllowed() {
|
||||
assertFalse(GeographicalRestrictions.e164Allowed(null))
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.registration.fcm;
|
||||
|
||||
import android.app.Application;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
import static org.hamcrest.Matchers.lessThan;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE, application = Application.class)
|
||||
public final class PushChallengeRequestTest {
|
||||
|
||||
@Test
|
||||
public void getPushChallengeBlocking_returns_absent_if_times_out() {
|
||||
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
|
||||
|
||||
Optional<String> challenge = PushChallengeRequest.getPushChallengeBlocking(signal, "session ID", Optional.of("token"), 50L);
|
||||
|
||||
assertFalse(challenge.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPushChallengeBlocking_waits_for_specified_period() {
|
||||
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
PushChallengeRequest.getPushChallengeBlocking(signal, "session ID", Optional.of("token"), 250L);
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
|
||||
assertThat(duration, greaterThanOrEqualTo(250L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPushChallengeBlocking_completes_fast_if_posted_to_event_bus() throws IOException {
|
||||
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
|
||||
doAnswer(invocation -> {
|
||||
AsyncTask.execute(() -> PushChallengeRequest.postChallengeResponse("CHALLENGE"));
|
||||
return null;
|
||||
}).when(signal).requestRegistrationPushChallenge("session ID", "token");
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
Optional<String> challenge = PushChallengeRequest.getPushChallengeBlocking(signal, "session ID", Optional.of("token"), 500L);
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
|
||||
assertThat(duration, lessThan(500L));
|
||||
verify(signal).requestRegistrationPushChallenge("session ID", "token");
|
||||
verifyNoMoreInteractions(signal);
|
||||
|
||||
assertTrue(challenge.isPresent());
|
||||
assertEquals("CHALLENGE", challenge.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPushChallengeBlocking_returns_fast_if_no_fcm_token_supplied() {
|
||||
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
PushChallengeRequest.getPushChallengeBlocking(signal, "session ID", Optional.empty(), 500L);
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
|
||||
assertThat(duration, lessThan(500L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPushChallengeBlocking_returns_absent_if_no_fcm_token_supplied() {
|
||||
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
|
||||
|
||||
Optional<String> challenge = PushChallengeRequest.getPushChallengeBlocking(signal, "session ID", Optional.empty(), 500L);
|
||||
|
||||
verifyNoInteractions(signal);
|
||||
assertFalse(challenge.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPushChallengeBlocking_returns_absent_if_any_IOException_is_thrown() throws IOException {
|
||||
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
|
||||
|
||||
doThrow(new IOException()).when(signal).requestRegistrationPushChallenge(any(), any());
|
||||
|
||||
Optional<String> challenge = PushChallengeRequest.getPushChallengeBlocking(signal, "session ID", Optional.of("token"), 500L);
|
||||
|
||||
assertFalse(challenge.isPresent());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
package org.thoughtcrime.securesms.registration.fcm
|
||||
|
||||
import android.app.Application
|
||||
import android.os.AsyncTask
|
||||
import io.mockk.called
|
||||
import io.mockk.confirmVerified
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.Matchers.greaterThanOrEqualTo
|
||||
import org.hamcrest.Matchers.lessThan
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager
|
||||
import java.io.IOException
|
||||
import java.util.Optional
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE, application = Application::class)
|
||||
class PushChallengeRequestTest {
|
||||
@Test
|
||||
fun pushChallengeBlocking_returns_absent_if_times_out() {
|
||||
val signal = mockk<SignalServiceAccountManager>(relaxUnitFun = true)
|
||||
|
||||
val challenge = PushChallengeRequest.getPushChallengeBlocking(signal, "session ID", Optional.of("token"), 50L)
|
||||
|
||||
assertFalse(challenge.isPresent)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pushChallengeBlocking_waits_for_specified_period() {
|
||||
val signal = mockk<SignalServiceAccountManager>(relaxUnitFun = true)
|
||||
|
||||
val startTime = System.currentTimeMillis()
|
||||
PushChallengeRequest.getPushChallengeBlocking(signal, "session ID", Optional.of("token"), 250L)
|
||||
val duration = System.currentTimeMillis() - startTime
|
||||
|
||||
assertThat(duration, greaterThanOrEqualTo(250L))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pushChallengeBlocking_completes_fast_if_posted_to_event_bus() {
|
||||
val signal = mockk<SignalServiceAccountManager> {
|
||||
every {
|
||||
requestRegistrationPushChallenge("session ID", "token")
|
||||
} answers {
|
||||
AsyncTask.execute { PushChallengeRequest.postChallengeResponse("CHALLENGE") }
|
||||
}
|
||||
}
|
||||
|
||||
val startTime = System.currentTimeMillis()
|
||||
val challenge = PushChallengeRequest.getPushChallengeBlocking(signal, "session ID", Optional.of("token"), 500L)
|
||||
val duration = System.currentTimeMillis() - startTime
|
||||
|
||||
assertThat(duration, lessThan(500L))
|
||||
verify { signal.requestRegistrationPushChallenge("session ID", "token") }
|
||||
confirmVerified(signal)
|
||||
|
||||
assertTrue(challenge.isPresent)
|
||||
assertEquals("CHALLENGE", challenge.get())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pushChallengeBlocking_returns_fast_if_no_fcm_token_supplied() {
|
||||
val signal = mockk<SignalServiceAccountManager>()
|
||||
|
||||
val startTime = System.currentTimeMillis()
|
||||
PushChallengeRequest.getPushChallengeBlocking(signal, "session ID", Optional.empty(), 500L)
|
||||
val duration = System.currentTimeMillis() - startTime
|
||||
|
||||
assertThat(duration, lessThan(500L))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pushChallengeBlocking_returns_absent_if_no_fcm_token_supplied() {
|
||||
val signal = mockk<SignalServiceAccountManager>()
|
||||
|
||||
val challenge = PushChallengeRequest.getPushChallengeBlocking(signal, "session ID", Optional.empty(), 500L)
|
||||
|
||||
verify { signal wasNot called }
|
||||
assertFalse(challenge.isPresent)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun pushChallengeBlocking_returns_absent_if_any_IOException_is_thrown() {
|
||||
val signal = mockk<SignalServiceAccountManager> {
|
||||
every { requestRegistrationPushChallenge(any(), any()) } throws IOException()
|
||||
}
|
||||
|
||||
val challenge = PushChallengeRequest.getPushChallengeBlocking(signal, "session ID", Optional.of("token"), 500L)
|
||||
|
||||
assertFalse(challenge.isPresent)
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
package org.thoughtcrime.securesms.registration.v2;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.signal.core.util.StreamUtil;
|
||||
import org.signal.libsignal.svr2.PinHash;
|
||||
import org.thoughtcrime.securesms.registration.testdata.KbsTestVector;
|
||||
import org.whispersystems.signalservice.api.crypto.InvalidCiphertextException;
|
||||
import org.whispersystems.signalservice.api.kbs.KbsData;
|
||||
import org.whispersystems.signalservice.api.kbs.MasterKey;
|
||||
import org.whispersystems.signalservice.api.kbs.PinHashUtil;
|
||||
import org.whispersystems.signalservice.internal.util.JsonUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.thoughtcrime.securesms.testutil.SecureRandomTestUtil.mockRandom;
|
||||
|
||||
public final class PinHashKbsDataTest {
|
||||
|
||||
@Test
|
||||
public void vectors_createNewKbsData() throws IOException {
|
||||
for (KbsTestVector vector : getKbsTestVectorList()) {
|
||||
PinHash pinHash = fromArgon2Hash(vector.getArgon2Hash());
|
||||
|
||||
KbsData kbsData = PinHashUtil.createNewKbsData(pinHash, MasterKey.createNew(mockRandom(vector.getMasterKey())));
|
||||
|
||||
assertArrayEquals(vector.getMasterKey(), kbsData.getMasterKey().serialize());
|
||||
assertArrayEquals(vector.getIvAndCipher(), kbsData.getCipherText());
|
||||
assertArrayEquals(vector.getKbsAccessKey(), kbsData.getKbsAccessKey());
|
||||
assertEquals(vector.getRegistrationLock(), kbsData.getMasterKey().deriveRegistrationLock());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vectors_decryptKbsDataIVCipherText() throws IOException, InvalidCiphertextException {
|
||||
for (KbsTestVector vector : getKbsTestVectorList()) {
|
||||
PinHash hashedPin = fromArgon2Hash(vector.getArgon2Hash());
|
||||
|
||||
KbsData kbsData = PinHashUtil.decryptSvrDataIVCipherText(hashedPin, vector.getIvAndCipher());
|
||||
|
||||
assertArrayEquals(vector.getMasterKey(), kbsData.getMasterKey().serialize());
|
||||
assertArrayEquals(vector.getIvAndCipher(), kbsData.getCipherText());
|
||||
assertArrayEquals(vector.getKbsAccessKey(), kbsData.getKbsAccessKey());
|
||||
assertEquals(vector.getRegistrationLock(), kbsData.getMasterKey().deriveRegistrationLock());
|
||||
}
|
||||
}
|
||||
|
||||
private static KbsTestVector[] getKbsTestVectorList() throws IOException {
|
||||
try (InputStream resourceAsStream = ClassLoader.getSystemClassLoader().getResourceAsStream("data/kbs_vectors.json")) {
|
||||
|
||||
KbsTestVector[] data = JsonUtil.fromJson(StreamUtil.readFullyAsString(resourceAsStream), KbsTestVector[].class);
|
||||
|
||||
assertTrue(data.length > 0);
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public static PinHash fromArgon2Hash(byte[] argon2Hash64) {
|
||||
if (argon2Hash64.length != 64) throw new AssertionError();
|
||||
|
||||
byte[] K = Arrays.copyOfRange(argon2Hash64, 0, 32);
|
||||
byte[] kbsAccessKey = Arrays.copyOfRange(argon2Hash64, 32, 64);
|
||||
|
||||
PinHash mocked = mock(PinHash.class);
|
||||
when(mocked.encryptionKey()).thenReturn(K);
|
||||
when(mocked.accessKey()).thenReturn(kbsAccessKey);
|
||||
|
||||
return mocked;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package org.thoughtcrime.securesms.registration.v2
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.Assert.assertArrayEquals
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.signal.core.util.StreamUtil
|
||||
import org.signal.libsignal.svr2.PinHash
|
||||
import org.thoughtcrime.securesms.registration.v2.testdata.KbsTestVector
|
||||
import org.thoughtcrime.securesms.testutil.SecureRandomTestUtil
|
||||
import org.whispersystems.signalservice.api.kbs.MasterKey
|
||||
import org.whispersystems.signalservice.api.kbs.PinHashUtil.createNewKbsData
|
||||
import org.whispersystems.signalservice.api.kbs.PinHashUtil.decryptSvrDataIVCipherText
|
||||
import org.whispersystems.signalservice.internal.util.JsonUtil
|
||||
|
||||
class PinHashKbsDataTest {
|
||||
@Test
|
||||
fun vectors_createNewKbsData() {
|
||||
for (vector in kbsTestVectorList) {
|
||||
val pinHash = fromArgon2Hash(vector.argon2Hash)
|
||||
|
||||
val kbsData = createNewKbsData(pinHash, MasterKey.createNew(SecureRandomTestUtil.mockRandom(vector.masterKey)))
|
||||
|
||||
assertArrayEquals(vector.masterKey, kbsData.masterKey.serialize())
|
||||
assertArrayEquals(vector.ivAndCipher, kbsData.cipherText)
|
||||
assertArrayEquals(vector.kbsAccessKey, kbsData.kbsAccessKey)
|
||||
assertEquals(vector.registrationLock, kbsData.masterKey.deriveRegistrationLock())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun vectors_decryptKbsDataIVCipherText() {
|
||||
for (vector in kbsTestVectorList) {
|
||||
val hashedPin = fromArgon2Hash(vector.argon2Hash)
|
||||
|
||||
val kbsData = decryptSvrDataIVCipherText(hashedPin, vector.ivAndCipher)
|
||||
|
||||
assertArrayEquals(vector.masterKey, kbsData.masterKey.serialize())
|
||||
assertArrayEquals(vector.ivAndCipher, kbsData.cipherText)
|
||||
assertArrayEquals(vector.kbsAccessKey, kbsData.kbsAccessKey)
|
||||
assertEquals(vector.registrationLock, kbsData.masterKey.deriveRegistrationLock())
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val kbsTestVectorList: Array<KbsTestVector>
|
||||
get() {
|
||||
ClassLoader.getSystemClassLoader().getResourceAsStream("data/kbs_vectors.json").use { resourceAsStream ->
|
||||
val data: Array<KbsTestVector> = JsonUtil.fromJson(
|
||||
StreamUtil.readFullyAsString(resourceAsStream),
|
||||
Array<KbsTestVector>::class.java
|
||||
)
|
||||
assertTrue(data.isNotEmpty())
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
fun fromArgon2Hash(argon2Hash64: ByteArray): PinHash {
|
||||
if (argon2Hash64.size != 64) throw AssertionError()
|
||||
|
||||
val k = argon2Hash64.copyOfRange(0, 32)
|
||||
val kbsAccessKey = argon2Hash64.copyOfRange(32, 64)
|
||||
|
||||
return mockk<PinHash> {
|
||||
every { encryptionKey() } returns k
|
||||
every { accessKey() } returns kbsAccessKey
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package org.thoughtcrime.securesms.registration.testdata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
|
||||
import org.thoughtcrime.securesms.testutil.HexDeserializer;
|
||||
|
||||
public final class KbsTestVector {
|
||||
|
||||
@JsonProperty("backup_id")
|
||||
@JsonDeserialize(using = HexDeserializer.class)
|
||||
private byte[] backupId;
|
||||
|
||||
@JsonProperty("argon2_hash")
|
||||
@JsonDeserialize(using = HexDeserializer.class)
|
||||
private byte[] argon2Hash;
|
||||
|
||||
@JsonProperty("pin")
|
||||
private String pin;
|
||||
|
||||
@JsonProperty("registration_lock")
|
||||
private String registrationLock;
|
||||
|
||||
@JsonProperty("master_key")
|
||||
@JsonDeserialize(using = HexDeserializer.class)
|
||||
private byte[] masterKey;
|
||||
|
||||
@JsonProperty("kbs_access_key")
|
||||
@JsonDeserialize(using = HexDeserializer.class)
|
||||
private byte[] kbsAccessKey;
|
||||
|
||||
@JsonProperty("iv_and_cipher")
|
||||
@JsonDeserialize(using = HexDeserializer.class)
|
||||
private byte[] ivAndCipher;
|
||||
|
||||
public byte[] getBackupId() {
|
||||
return backupId;
|
||||
}
|
||||
|
||||
public byte[] getArgon2Hash() {
|
||||
return argon2Hash;
|
||||
}
|
||||
|
||||
public String getPin() {
|
||||
return pin;
|
||||
}
|
||||
|
||||
public String getRegistrationLock() {
|
||||
return registrationLock;
|
||||
}
|
||||
|
||||
public byte[] getMasterKey() {
|
||||
return masterKey;
|
||||
}
|
||||
|
||||
public byte[] getKbsAccessKey() {
|
||||
return kbsAccessKey;
|
||||
}
|
||||
|
||||
public byte[] getIvAndCipher() {
|
||||
return ivAndCipher;
|
||||
}
|
||||
}
|
62
app/src/test/java/org/thoughtcrime/securesms/registration/v2/testdata/KbsTestVector.kt
vendored
Normal file
62
app/src/test/java/org/thoughtcrime/securesms/registration/v2/testdata/KbsTestVector.kt
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
package org.thoughtcrime.securesms.registration.v2.testdata
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
||||
import org.thoughtcrime.securesms.testutil.HexDeserializer
|
||||
|
||||
data class KbsTestVector(
|
||||
@JsonProperty("backup_id")
|
||||
@JsonDeserialize(using = HexDeserializer::class)
|
||||
val backupId: ByteArray,
|
||||
|
||||
@JsonProperty("argon2_hash")
|
||||
@JsonDeserialize(using = HexDeserializer::class)
|
||||
val argon2Hash: ByteArray,
|
||||
|
||||
@JsonProperty("pin")
|
||||
val pin: String? = null,
|
||||
|
||||
@JsonProperty("registration_lock")
|
||||
val registrationLock: String? = null,
|
||||
|
||||
@JsonProperty("master_key")
|
||||
@JsonDeserialize(using = HexDeserializer::class)
|
||||
val masterKey: ByteArray,
|
||||
|
||||
@JsonProperty("kbs_access_key")
|
||||
@JsonDeserialize(using = HexDeserializer::class)
|
||||
val kbsAccessKey: ByteArray,
|
||||
|
||||
@JsonProperty("iv_and_cipher")
|
||||
@JsonDeserialize(using = HexDeserializer::class)
|
||||
val ivAndCipher: ByteArray
|
||||
) {
|
||||
// equals() and hashCode() are still recommended on data class because of ByteArray usage
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as KbsTestVector
|
||||
|
||||
if (!backupId.contentEquals(other.backupId)) return false
|
||||
if (!argon2Hash.contentEquals(other.argon2Hash)) return false
|
||||
if (pin != other.pin) return false
|
||||
if (registrationLock != other.registrationLock) return false
|
||||
if (!masterKey.contentEquals(other.masterKey)) return false
|
||||
if (!kbsAccessKey.contentEquals(other.kbsAccessKey)) return false
|
||||
if (!ivAndCipher.contentEquals(other.ivAndCipher)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = backupId.contentHashCode()
|
||||
result = 31 * result + argon2Hash.contentHashCode()
|
||||
result = 31 * result + (pin?.hashCode() ?: 0)
|
||||
result = 31 * result + (registrationLock?.hashCode() ?: 0)
|
||||
result = 31 * result + masterKey.contentHashCode()
|
||||
result = 31 * result + kbsAccessKey.contentHashCode()
|
||||
result = 31 * result + ivAndCipher.contentHashCode()
|
||||
return result
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue