Skip to content

Commit e2161ba

Browse files
committed
refactor to include pre-generated thumbnails being passed in
1 parent 3e7ad1c commit e2161ba

12 files changed

Lines changed: 296 additions & 217 deletions

File tree

Lines changed: 88 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,94 @@
11
package org.thoughtcrime.securesms.database;
22

3+
import android.content.Context;
34
import android.net.Uri;
45
import android.test.AndroidTestCase;
6+
import android.test.InstrumentationTestCase;
57

68
import org.thoughtcrime.securesms.crypto.MasterSecret;
79
import org.thoughtcrime.securesms.jobs.ThumbnailGenerateJob;
810

11+
import java.io.FileNotFoundException;
912
import java.io.InputStream;
1013
import java.util.HashSet;
1114
import java.util.Set;
1215

16+
import dagger.Module;
17+
import dagger.ObjectGraph;
18+
import dagger.Provides;
1319
import ws.com.google.android.mms.pdu.PduPart;
1420

1521
import static org.mockito.Matchers.any;
1622
import static org.mockito.Matchers.anyFloat;
1723
import static org.mockito.Matchers.anyLong;
1824
import static org.mockito.Matchers.eq;
1925
import static org.mockito.Mockito.doCallRealMethod;
26+
import static org.mockito.Mockito.doReturn;
2027
import static org.mockito.Mockito.mock;
2128
import static org.mockito.Mockito.never;
29+
import static org.mockito.Mockito.spy;
2230
import static org.mockito.Mockito.times;
2331
import static org.mockito.Mockito.verify;
2432
import static org.mockito.Mockito.when;
25-
import static org.thoughtcrime.securesms.jobs.ThumbnailGenerateJobTest.getThumbnailGenerateJob;
2633

27-
public class PartDatabaseTest extends AndroidTestCase {
34+
public class PartDatabaseTest extends InstrumentationTestCase {
2835
private static final long PART_ID = 1L;
2936

3037
private PartDatabase database;
31-
private Set<Long> tasks = new HashSet<>();
38+
private Set<Long> tasks;
3239

3340
@Override
3441
public void setUp() {
35-
database = mock(PartDatabase.class);
42+
database = spy(DatabaseFactory.getPartDatabase(getInstrumentation().getTargetContext()));
43+
tasks = spy(new HashSet<Long>());
3644
}
3745

46+
public void testTaskNotRunWhenThumbnailExists() throws Exception {
47+
ThumbnailGenerateJob job = getThumbnailGenerateJob(getInstrumentation().getTargetContext(), database);
48+
when(database.getPart(eq(PART_ID))).thenReturn(getPduPartSkeleton("x/x"));
49+
doReturn(true).when(database).isThumbnailInDatabase(anyLong());
50+
51+
job.onRun(null);
52+
53+
verify(database, never()).generatePartThumbnail(any(MasterSecret.class), anyLong());
54+
verify(database, never()).updatePartThumbnail(any(MasterSecret.class), anyLong(), any(PduPart.class), any(InputStream.class), anyFloat());
55+
verify(database, never()).markThumbnailTaskEnded(eq(PART_ID));
56+
}
57+
58+
public void testTaskResizesImage() throws Exception {
59+
ThumbnailGenerateJob job = getThumbnailGenerateJob(getInstrumentation().getTargetContext(), database);
60+
doReturn(getPduPartSkeleton("image/png")).when(database).getPart(PART_ID);
61+
doReturn(true).when(database).markThumbnailTaskStartedIfAbsent(PART_ID);
62+
63+
try {
64+
job.onRun(null);
65+
throw new AssertionError("should have thrown FNFE as it tried to resize an image");
66+
} catch (FileNotFoundException fnfe) {
67+
// success
68+
}
69+
70+
verify(database, times(1)).markThumbnailTaskStartedIfAbsent(eq(PART_ID));
71+
verify(database, times(1)).markThumbnailTaskEnded(eq(PART_ID));
72+
}
73+
74+
// public void testDoubleJob() throws Exception {
75+
// ThumbnailGenerateJob job = getThumbnailGenerateJob(getContext(), database);
76+
// when(database.getPart(PART_ID)).thenReturn(getPduPartSkeleton("image/png"));
77+
// doReturn(false).when(database).isThumbnailInDatabase(anyLong());
78+
//
79+
// try {
80+
// job.onRun(null);
81+
// throw new AssertionError("should have thrown FNFE as it tried to resize an image");
82+
// } catch (FileNotFoundException fnfe) {
83+
// // success
84+
// }
85+
//
86+
// verify(database, times(1)).markThumbnailTaskStarted(eq(PART_ID));
87+
// verify(database, times(1)).markThumbnailTaskEnded(eq(PART_ID));
88+
// }
89+
3890
public void testThumbnailStreamExistsCase() throws Exception {
39-
when(database.getDataStream(any(MasterSecret.class), anyLong(), eq("thumbnail"))).thenReturn(mock(InputStream.class));
91+
doReturn(mock(InputStream.class)).when(database).getDataStream(any(MasterSecret.class), anyLong(), eq("thumbnail"));
4092
doCallRealMethod().when(database).getThumbnailStream(any(MasterSecret.class), anyLong());
4193

4294
assertNotNull(database.getThumbnailStream(null, PART_ID));
@@ -47,23 +99,16 @@ public void testThumbnailStreamExistsCase() throws Exception {
4799
}
48100

49101
public void testThumbnailStreamBlocksOnRunningJob() throws Exception {
50-
when(database.getPart(eq(PART_ID))).thenReturn(getPduPartSkeleton("x/x"));
51-
52-
when(database.getDataStream(any(MasterSecret.class), anyLong(), eq("thumbnail"))).thenReturn(null);
53-
when(database.getThumbnailTasks()).thenReturn(tasks);
102+
doReturn(getPduPartSkeleton("x/x")).when(database).getPart(PART_ID);
103+
doReturn(null).when(database).getDataStream(any(MasterSecret.class), anyLong(), eq("thumbnail"));
54104

55-
doCallRealMethod().when(database).markThumbnailTaskStarted(anyLong());
56-
doCallRealMethod().when(database).markThumbnailTaskEnded(anyLong());
57-
doCallRealMethod().when(database).getThumbnailStream(any(MasterSecret.class), anyLong());
58-
59-
final ThumbnailGenerateJob job = getThumbnailGenerateJob(getContext(), database);
60-
job.onAdded();
105+
database.markThumbnailTaskStarted(PART_ID);
61106
new Thread(new Runnable() {
62107
@Override
63108
public void run() {
64109
try {
65110
Thread.sleep(1000L);
66-
job.onRun(null);
111+
database.markThumbnailTaskEnded(PART_ID);
67112
} catch (Exception e) {
68113
throw new AssertionError("interrupted");
69114
}
@@ -79,14 +124,9 @@ public void run() {
79124
}
80125

81126
public void testThumbnailStreamGeneratesWhenMissing() throws Exception {
82-
final PartDatabase database = mock(PartDatabase.class);
83-
final Set<Long> tasks = new HashSet<>();
84-
85-
when(database.getPart(PART_ID)).thenReturn(getPduPartSkeleton("x/x"));
86-
87-
when(database.getThumbnailGenerateJob(anyLong())).thenReturn(getThumbnailGenerateJob(getContext(), database));
88-
when(database.getDataStream(any(MasterSecret.class), anyLong(), eq("thumbnail"))).thenReturn(null);
89-
when(database.getThumbnailTasks()).thenReturn(tasks);
127+
doReturn(getPduPartSkeleton("x/x")).when(database).getPart(PART_ID);
128+
doReturn(getThumbnailGenerateJob(getInstrumentation().getTargetContext(), database)).when(database).getThumbnailGenerateJob(anyLong());
129+
doReturn(null).when(database).getDataStream(any(MasterSecret.class), anyLong(), eq("thumbnail"));
90130

91131
doCallRealMethod().when(database).markThumbnailTaskStarted(anyLong());
92132
doCallRealMethod().when(database).markThumbnailTaskEnded(anyLong());
@@ -95,7 +135,6 @@ public void testThumbnailStreamGeneratesWhenMissing() throws Exception {
95135
database.getThumbnailStream(null, PART_ID);
96136

97137
verify(database, times(3)).getDataStream(any(MasterSecret.class), anyLong(), eq("thumbnail"));
98-
verify(database, times(1)).getThumbnailGenerateJob(anyLong());
99138
verify(database, times(1)).markThumbnailTaskStarted(eq(PART_ID));
100139
verify(database, times(1)).markThumbnailTaskEnded(eq(PART_ID));
101140
}
@@ -106,4 +145,28 @@ private PduPart getPduPartSkeleton(String contentType) {
106145
part.setDataUri(Uri.EMPTY);
107146
return part;
108147
}
148+
149+
public static ThumbnailGenerateJob getThumbnailGenerateJob(Context context, PartDatabase database) {
150+
ThumbnailGenerateJob job = new ThumbnailGenerateJob(context, PART_ID);
151+
ObjectGraph objectGraph = ObjectGraph.create(new DatabaseModule(database));
152+
objectGraph.inject(job);
153+
return job;
154+
}
155+
156+
@SuppressWarnings("unused")
157+
@Module(injects = ThumbnailGenerateJob.class)
158+
public static class DatabaseModule {
159+
160+
private final PartDatabase partDatabase;
161+
162+
public DatabaseModule(PartDatabase partDatabase) {
163+
this.partDatabase = partDatabase;
164+
}
165+
166+
@Provides
167+
PartDatabase providePartDatabase() {
168+
return partDatabase;
169+
}
170+
}
171+
109172
}

androidTest/java/org/thoughtcrime/securesms/jobs/ThumbnailGenerateJobTest.java

Lines changed: 0 additions & 94 deletions
This file was deleted.

src/org/thoughtcrime/securesms/database/MmsDatabase.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import android.database.Cursor;
2222
import android.database.sqlite.SQLiteDatabase;
2323
import android.database.sqlite.SQLiteOpenHelper;
24+
import android.graphics.Bitmap;
2425
import android.net.Uri;
2526
import android.telephony.TelephonyManager;
2627
import android.text.TextUtils;
@@ -52,7 +53,6 @@
5253
import org.thoughtcrime.securesms.util.LRUCache;
5354
import org.thoughtcrime.securesms.util.ListenableFutureTask;
5455
import org.thoughtcrime.securesms.util.TextSecurePreferences;
55-
import org.thoughtcrime.securesms.util.Trimmer;
5656
import org.thoughtcrime.securesms.util.Util;
5757
import org.whispersystems.jobqueue.JobManager;
5858
import org.whispersystems.libaxolotl.InvalidMessageException;
@@ -527,7 +527,7 @@ public long copyMessageInbox(MasterSecret masterSecret, long messageId) throws M
527527
contentValues.put(DATE_RECEIVED, contentValues.getAsLong(DATE_SENT));
528528

529529
return insertMediaMessage(masterSecret, request.getPduHeaders(),
530-
request.getBody(), contentValues);
530+
request.getBody(), contentValues, null);
531531
} catch (NoSuchMessageException e) {
532532
throw new MmsException(e);
533533
}
@@ -564,7 +564,7 @@ private Pair<Long, Long> insertMessageInbox(MasterSecret masterSecret, IncomingM
564564
}
565565

566566
long messageId = insertMediaMessage(masterSecret, retrieved.getPduHeaders(),
567-
retrieved.getBody(), contentValues);
567+
retrieved.getBody(), contentValues, null);
568568

569569
if (unread) {
570570
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
@@ -695,7 +695,7 @@ public long insertMessageOutbox(MasterSecret masterSecret, OutgoingMediaMessage
695695
contentValues.remove(ADDRESS);
696696

697697
long messageId = insertMediaMessage(masterSecret, sendRequest.getPduHeaders(),
698-
sendRequest.getBody(), contentValues);
698+
sendRequest.getBody(), contentValues, message.getThumbnailMap());
699699
jobManager.add(new TrimThreadJob(context, threadId));
700700

701701
return messageId;
@@ -704,7 +704,8 @@ public long insertMessageOutbox(MasterSecret masterSecret, OutgoingMediaMessage
704704
private long insertMediaMessage(MasterSecret masterSecret,
705705
PduHeaders headers,
706706
PduBody body,
707-
ContentValues contentValues)
707+
ContentValues contentValues,
708+
Map<PduPart, Bitmap> thumbnailMap)
708709
throws MmsException
709710
{
710711
SQLiteDatabase db = databaseHelper.getWritableDatabase();
@@ -713,7 +714,7 @@ private long insertMediaMessage(MasterSecret masterSecret,
713714

714715
if (Types.isSymmetricEncryption(contentValues.getAsLong(MESSAGE_BOX))) {
715716
String messageText = PartParser.getMessageText(body);
716-
body = PartParser.getNonTextParts(body);
717+
body = PartParser.getDisplayableParts(body);
717718

718719
if (!TextUtils.isEmpty(messageText)) {
719720
contentValues.put(BODY, new MasterCipher(masterSecret).encryptBody(messageText));
@@ -725,7 +726,7 @@ private long insertMediaMessage(MasterSecret masterSecret,
725726
long messageId = db.insert(TABLE_NAME, null, contentValues);
726727

727728
addressDatabase.insertAddressesForId(messageId, headers);
728-
partsDatabase.insertParts(masterSecret, messageId, body);
729+
partsDatabase.insertParts(masterSecret, messageId, body, thumbnailMap);
729730

730731
notifyConversationListeners(contentValues.getAsLong(THREAD_ID));
731732
DatabaseFactory.getThreadDatabase(context).update(contentValues.getAsLong(THREAD_ID));

0 commit comments

Comments
 (0)