Home | History | Annotate | Download | only in action
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.messaging.datamodel.action;
     18 
     19 import android.content.ContentProvider;
     20 import android.content.pm.ProviderInfo;
     21 import android.database.Cursor;
     22 import android.net.Uri;
     23 import android.test.suitebuilder.annotation.SmallTest;
     24 import android.text.TextUtils;
     25 
     26 import com.android.messaging.BugleTestCase;
     27 import com.android.messaging.FakeContext;
     28 import com.android.messaging.FakeFactory;
     29 import com.android.messaging.datamodel.BugleDatabaseOperations;
     30 import com.android.messaging.datamodel.DataModel;
     31 import com.android.messaging.datamodel.DatabaseHelper;
     32 import com.android.messaging.datamodel.DatabaseHelper.ConversationColumns;
     33 import com.android.messaging.datamodel.DatabaseWrapper;
     34 import com.android.messaging.datamodel.FakeDataModel;
     35 import com.android.messaging.datamodel.MediaScratchFileProvider;
     36 import com.android.messaging.datamodel.MessagingContentProvider;
     37 import com.android.messaging.datamodel.action.ActionTestHelpers.StubActionService;
     38 import com.android.messaging.datamodel.action.ActionTestHelpers.StubActionService.StubActionServiceCallLog;
     39 import com.android.messaging.datamodel.action.ActionTestHelpers.StubConnectivityUtil;
     40 import com.android.messaging.datamodel.action.ReadDraftDataAction.ReadDraftDataActionListener;
     41 import com.android.messaging.datamodel.data.MessageData;
     42 import com.android.messaging.datamodel.data.MessagePartData;
     43 import com.android.messaging.datamodel.data.ParticipantData;
     44 import com.android.messaging.util.ContentType;
     45 
     46 import org.mockito.Mock;
     47 
     48 import java.io.FileNotFoundException;
     49 import java.io.IOException;
     50 import java.io.InputStream;
     51 import java.io.OutputStream;
     52 import java.util.ArrayList;
     53 
     54 @SmallTest
     55 public class ReadWriteDraftMessageActionTest extends BugleTestCase {
     56 
     57     @Mock ReadDraftDataActionListener mockListener;
     58 
     59     // TODO: Add test cases
     60     //  1. Make sure drafts can include attachments and multiple parts
     61     //  2. Make sure attachments get cleaned up appropriately
     62     //  3. Make sure messageId and partIds not reused (currently each draft is a new message).
     63     public void testWriteDraft() {
     64         final String draftMessage = "draftMessage";
     65         final long threadId = 1234567;
     66         final boolean senderBlocked = false;
     67         final String participantNumber = "5551234567";
     68 
     69         final DatabaseWrapper db = DataModel.get().getDatabase();
     70 
     71         final String conversationId = getOrCreateConversation(db, participantNumber, threadId,
     72                 senderBlocked);
     73         final String selfId = getOrCreateSelfId(db);
     74 
     75         // Should clear/stub DB
     76         final ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
     77 
     78         final MessageData message = MessageData.createDraftSmsMessage(conversationId, selfId,
     79                 draftMessage);
     80 
     81         WriteDraftMessageAction.writeDraftMessage(conversationId, message);
     82 
     83         assertEquals("Failed to start service once for action", calls.size(), 1);
     84         assertTrue("Action not SaveDraftMessageAction",
     85                 calls.get(0).action instanceof WriteDraftMessageAction);
     86 
     87         final Action save = calls.get(0).action;
     88 
     89         final Object result = save.executeAction();
     90 
     91         assertTrue("Expect row number string as result", result instanceof String);
     92         final String messageId = (String) result;
     93 
     94         // Should check DB
     95         final MessageData actual = BugleDatabaseOperations.readMessage(db, messageId);
     96         assertNotNull("Database missing draft", actual);
     97         assertEquals("Draft text changed", draftMessage, actual.getMessageText());
     98     }
     99 
    100     private static String getOrCreateSelfId(final DatabaseWrapper db) {
    101         db.beginTransaction();
    102         final String selfId = BugleDatabaseOperations.getOrCreateParticipantInTransaction(db,
    103                 ParticipantData.getSelfParticipant(ParticipantData.DEFAULT_SELF_SUB_ID));
    104         db.setTransactionSuccessful();
    105         db.endTransaction();
    106         return selfId;
    107     }
    108 
    109     private static String getOrCreateConversation(final DatabaseWrapper db,
    110             final String participantNumber, final long threadId, final boolean senderBlocked) {
    111         final ArrayList<ParticipantData> participants =
    112                 new ArrayList<ParticipantData>();
    113         participants.add(ParticipantData.getFromRawPhoneBySystemLocale(participantNumber));
    114 
    115         final String conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
    116                 senderBlocked, participants, false, false, null);
    117         assertNotNull("No conversation", conversationId);
    118         return conversationId;
    119     }
    120 
    121     public void testReadDraft() {
    122         final Object data = "data";
    123         final String draftMessage = "draftMessage";
    124         final long threadId = 1234567;
    125         final boolean senderBlocked = false;
    126         final String participantNumber = "5552345678";
    127 
    128         final DatabaseWrapper db = DataModel.get().getDatabase();
    129 
    130         final String conversationId = getOrCreateConversation(db, participantNumber, threadId,
    131                 senderBlocked);
    132         final String selfId = getOrCreateSelfId(db);
    133 
    134         // Should clear/stub DB
    135         final ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
    136 
    137         final MessageData message = MessageData.createDraftSmsMessage(conversationId, selfId,
    138                 draftMessage);
    139 
    140         BugleDatabaseOperations.updateDraftMessageData(db, conversationId, message,
    141                 BugleDatabaseOperations.UPDATE_MODE_ADD_DRAFT);
    142 
    143         final ActionMonitor monitor =
    144                 ReadDraftDataAction.readDraftData(conversationId, null, data, mockListener);
    145 
    146         assertEquals("Unexpected number of calls to service", 1, calls.size());
    147         assertTrue("Action not of type ReadDraftMessageAction",
    148                 calls.get(0).action instanceof ReadDraftDataAction);
    149 
    150         final Action read = calls.get(0).action;
    151 
    152         final Object result = read.executeAction();
    153 
    154         assertTrue(result instanceof ReadDraftDataAction.DraftData);
    155         final ReadDraftDataAction.DraftData draft = (ReadDraftDataAction.DraftData) result;
    156 
    157         assertEquals("Draft message text differs", draftMessage, draft.message.getMessageText());
    158         assertEquals("Draft self differs", selfId, draft.message.getSelfId());
    159         assertEquals("Draft conversation differs", conversationId,
    160                 draft.conversation.getConversationId());
    161     }
    162 
    163     public void testReadDraftForNewConversation() {
    164         final Object data = "data";
    165         long threadId = 1234567;
    166         final boolean senderBlocked = false;
    167         long phoneNumber = 5557654567L;
    168         final String notConversationId = "ThisIsNotValidConversationId";
    169 
    170         final DatabaseWrapper db = DataModel.get().getDatabase();
    171         final String selfId = getOrCreateSelfId(db);
    172 
    173         // Unless set a new conversation should have a null draft message
    174         final MessageData blank = BugleDatabaseOperations.readDraftMessageData(db,
    175                 notConversationId, selfId);
    176         assertNull(blank);
    177 
    178         String conversationId = null;
    179         do {
    180             conversationId = BugleDatabaseOperations.getExistingConversation(db,
    181                     threadId, senderBlocked);
    182             threadId++;
    183             phoneNumber++;
    184         }
    185         while(!TextUtils.isEmpty(conversationId));
    186 
    187         final ArrayList<ParticipantData> participants =
    188                 new ArrayList<ParticipantData>();
    189         participants.add(ParticipantData.getFromRawPhoneBySystemLocale(Long.toString(phoneNumber)));
    190 
    191         conversationId = BugleDatabaseOperations.getOrCreateConversation(db, threadId,
    192                 senderBlocked, participants, false, false, null);
    193         assertNotNull("No conversation", conversationId);
    194 
    195         final MessageData actual = BugleDatabaseOperations.readDraftMessageData(db, conversationId,
    196                 selfId);
    197         assertNull(actual);
    198 
    199         // Should clear/stub DB
    200         final ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
    201 
    202         final ActionMonitor monitor =
    203                 ReadDraftDataAction.readDraftData(conversationId, null, data, mockListener);
    204 
    205         assertEquals("Unexpected number of calls to service", 1, calls.size());
    206         assertTrue("Action not of type ReadDraftMessageAction",
    207                 calls.get(0).action instanceof ReadDraftDataAction);
    208 
    209         final Action read = calls.get(0).action;
    210 
    211         final Object result = read.executeAction();
    212 
    213         assertTrue(result instanceof ReadDraftDataAction.DraftData);
    214         final ReadDraftDataAction.DraftData draft = (ReadDraftDataAction.DraftData) result;
    215 
    216         assertEquals("Draft message text differs", "", draft.message.getMessageText());
    217         assertEquals("Draft self differs", selfId, draft.message.getSelfId());
    218         assertEquals("Draft conversation differs", conversationId,
    219                 draft.conversation.getConversationId());
    220     }
    221 
    222     public void testWriteAndReadDraft() {
    223         final Object data = "data";
    224         final String draftMessage = "draftMessage";
    225 
    226         final DatabaseWrapper db = DataModel.get().getDatabase();
    227         final Cursor conversations = db.query(DatabaseHelper.CONVERSATIONS_TABLE,
    228                 new String[] { ConversationColumns._ID, ConversationColumns.CURRENT_SELF_ID }, null,
    229                 null, null /* groupBy */, null /* having */, null /* orderBy */);
    230 
    231         if (conversations.moveToFirst()) {
    232             final String conversationId = conversations.getString(0);
    233             final String selfId = getOrCreateSelfId(db);
    234 
    235             // Should clear/stub DB
    236             final ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
    237 
    238             final MessageData message = MessageData.createDraftSmsMessage(conversationId, selfId,
    239                     draftMessage);
    240 
    241             WriteDraftMessageAction.writeDraftMessage(conversationId, message);
    242 
    243             assertEquals("Failed to start service once for action", calls.size(), 1);
    244             assertTrue("Action not SaveDraftMessageAction",
    245                     calls.get(0).action instanceof WriteDraftMessageAction);
    246 
    247             final Action save = calls.get(0).action;
    248 
    249             Object result = save.executeAction();
    250 
    251             assertTrue("Expect row number string as result", result instanceof String);
    252 
    253             // Should check DB
    254 
    255             final ActionMonitor monitor =
    256                     ReadDraftDataAction.readDraftData(conversationId, null, data,
    257                             mockListener);
    258 
    259             assertEquals("Expect two calls queued", 2, calls.size());
    260             assertTrue("Expect action", calls.get(1).action instanceof ReadDraftDataAction);
    261 
    262             final Action read = calls.get(1).action;
    263 
    264             result = read.executeAction();
    265 
    266             assertTrue(result instanceof ReadDraftDataAction.DraftData);
    267             final ReadDraftDataAction.DraftData draft = (ReadDraftDataAction.DraftData) result;
    268 
    269             assertEquals("Draft message text differs", draftMessage, draft.message.getMessageText());
    270             // The conversation's self id is used as the draft's self id.
    271             assertEquals("Draft self differs", conversations.getString(1),
    272                     draft.message.getSelfId());
    273             assertEquals("Draft conversation differs", conversationId,
    274                     draft.conversation.getConversationId());
    275         } else {
    276             fail("No conversations in database");
    277         }
    278     }
    279 
    280     public void testUpdateDraft() {
    281         final String initialMessage = "initialMessage";
    282         final String draftMessage = "draftMessage";
    283         final long threadId = 1234567;
    284         final boolean senderBlocked = false;
    285         final String participantNumber = "5553456789";
    286 
    287         final DatabaseWrapper db = DataModel.get().getDatabase();
    288 
    289         final String conversationId = getOrCreateConversation(db, participantNumber, threadId,
    290                 senderBlocked);
    291         final String selfId = getOrCreateSelfId(db);
    292 
    293         final ArrayList<StubActionServiceCallLog> calls = mService.getCalls();
    294 
    295         // Insert initial message
    296         MessageData initial = MessageData.createDraftSmsMessage(conversationId, selfId,
    297                 initialMessage);
    298 
    299         BugleDatabaseOperations.updateDraftMessageData(db, conversationId, initial,
    300                 BugleDatabaseOperations.UPDATE_MODE_ADD_DRAFT);
    301 
    302         initial = BugleDatabaseOperations.readDraftMessageData(db,
    303                 conversationId, selfId);
    304         assertEquals("Initial text mismatch", initialMessage, initial.getMessageText());
    305 
    306         // Now update the draft
    307         final MessageData message = MessageData.createDraftSmsMessage(conversationId, selfId,
    308                 draftMessage);
    309         WriteDraftMessageAction.writeDraftMessage(conversationId, message);
    310 
    311         assertEquals("Failed to start service once for action", calls.size(), 1);
    312         assertTrue("Action not SaveDraftMessageAction",
    313                 calls.get(0).action instanceof WriteDraftMessageAction);
    314 
    315         final Action save = calls.get(0).action;
    316 
    317         final Object result = save.executeAction();
    318 
    319         assertTrue("Expect row number string as result", result instanceof String);
    320 
    321         // Check DB
    322         final MessageData actual =  BugleDatabaseOperations.readDraftMessageData(db,
    323                 conversationId, selfId);
    324         assertNotNull("Database missing draft", actual);
    325         assertEquals("Draft text mismatch", draftMessage, actual.getMessageText());
    326         assertNull("Draft messageId should be null", actual.getMessageId());
    327     }
    328 
    329     public void testBugleDatabaseDraftOperations() {
    330         final String initialMessage = "initialMessage";
    331         final String draftMessage = "draftMessage";
    332         final long threadId = 1234599;
    333         final boolean senderBlocked = false;
    334         final String participantNumber = "5553456798";
    335         final String subject = "subject here";
    336 
    337         final DatabaseWrapper db = DataModel.get().getDatabase();
    338 
    339         final String conversationId = getOrCreateConversation(db, participantNumber, threadId,
    340                 senderBlocked);
    341         final String selfId = getOrCreateSelfId(db);
    342 
    343         final String text = "This is some text";
    344         final Uri mOutputUri = MediaScratchFileProvider.buildMediaScratchSpaceUri("txt");
    345         OutputStream outputStream = null;
    346         try {
    347             outputStream = mContext.getContentResolver().openOutputStream(mOutputUri);
    348             outputStream.write(text.getBytes());
    349         } catch (final FileNotFoundException e) {
    350             fail("Cannot open output file");
    351         } catch (final IOException e) {
    352             fail("Cannot write output file");
    353         }
    354 
    355         final MessageData initial =
    356                 MessageData.createDraftMmsMessage(conversationId, selfId, initialMessage, subject);
    357         initial.addPart(MessagePartData.createMediaMessagePart(ContentType.MULTIPART_MIXED,
    358                 mOutputUri, 0, 0));
    359 
    360         final String initialMessageId = BugleDatabaseOperations.updateDraftMessageData(db,
    361                 conversationId, initial, BugleDatabaseOperations.UPDATE_MODE_ADD_DRAFT);
    362         assertNotNull(initialMessageId);
    363 
    364         final MessageData initialDraft = BugleDatabaseOperations.readMessage(db, initialMessageId);
    365         assertNotNull(initialDraft);
    366         int cnt = 0;
    367         for(final MessagePartData part : initialDraft.getParts()) {
    368             if (part.isAttachment()) {
    369                 assertEquals(part.getContentUri(), mOutputUri);
    370             } else {
    371                 assertEquals(part.getText(), initialMessage);
    372             }
    373             cnt++;
    374         }
    375         assertEquals("Wrong number of parts", 2, cnt);
    376 
    377         InputStream inputStream = null;
    378         try {
    379             inputStream = mContext.getContentResolver().openInputStream(mOutputUri);
    380             final byte[] buffer = new byte[256];
    381             final int read = inputStream.read(buffer);
    382             assertEquals(read, text.getBytes().length);
    383         } catch (final FileNotFoundException e) {
    384             fail("Cannot open input file");
    385         } catch (final IOException e) {
    386             fail("Cannot read input file");
    387         }
    388 
    389         final String moreText = "This is some more text";
    390         final Uri mAnotherUri = MediaScratchFileProvider.buildMediaScratchSpaceUri("txt");
    391         outputStream = null;
    392         try {
    393             outputStream = mContext.getContentResolver().openOutputStream(mAnotherUri);
    394             outputStream.write(moreText.getBytes());
    395         } catch (final FileNotFoundException e) {
    396             fail("Cannot open output file");
    397         } catch (final IOException e) {
    398             fail("Cannot write output file");
    399         }
    400 
    401         final MessageData another =
    402                 MessageData.createDraftMmsMessage(conversationId, selfId, draftMessage, subject);
    403         another.addPart(MessagePartData.createMediaMessagePart(ContentType.MMS_MULTIPART_MIXED,
    404                 mAnotherUri, 0, 0));
    405 
    406         final String anotherMessageId = BugleDatabaseOperations.updateDraftMessageData(db,
    407                 conversationId, another, BugleDatabaseOperations.UPDATE_MODE_ADD_DRAFT);
    408         assertNotNull(anotherMessageId);
    409 
    410         final MessageData anotherDraft = BugleDatabaseOperations.readMessage(db, anotherMessageId);
    411         assertNotNull(anotherDraft);
    412         cnt = 0;
    413         for(final MessagePartData part : anotherDraft.getParts()) {
    414             if (part.isAttachment()) {
    415                 assertEquals(part.getContentUri(), mAnotherUri);
    416             } else {
    417                 assertEquals(part.getText(), draftMessage);
    418             }
    419             cnt++;
    420         }
    421         assertEquals("Wrong number of parts", 2, cnt);
    422 
    423         inputStream = null;
    424         try {
    425             inputStream = mContext.getContentResolver().openInputStream(mOutputUri);
    426             assertNull("Original draft content should have been deleted", inputStream);
    427         } catch (final FileNotFoundException e) {
    428         }
    429         inputStream = null;
    430         try {
    431             inputStream = mContext.getContentResolver().openInputStream(mAnotherUri);
    432             final byte[] buffer = new byte[256];
    433             final int read = inputStream.read(buffer);
    434             assertEquals(read, moreText.getBytes().length);
    435         } catch (final FileNotFoundException e) {
    436             fail("Cannot open input file");
    437         } catch (final IOException e) {
    438             fail("Cannot read input file");
    439         }
    440 
    441         final MessageData last = null;
    442         final String lastPartId = BugleDatabaseOperations.updateDraftMessageData(db,
    443                 conversationId, last, BugleDatabaseOperations.UPDATE_MODE_ADD_DRAFT);
    444         assertNull(lastPartId);
    445 
    446         inputStream = null;
    447         try {
    448             inputStream = mContext.getContentResolver().openInputStream(mAnotherUri);
    449             assertNull("Original draft content should have been deleted", inputStream);
    450         } catch (final FileNotFoundException e) {
    451         }
    452 
    453     }
    454 
    455     private StubActionService mService;
    456 
    457     @Override
    458     public void setUp() throws Exception {
    459         super.setUp();
    460 
    461         final FakeContext context = new FakeContext(getTestContext());
    462 
    463         final ContentProvider bugleProvider = new MessagingContentProvider();
    464         final ProviderInfo bugleProviderInfo = new ProviderInfo();
    465         bugleProviderInfo.authority = MessagingContentProvider.AUTHORITY;
    466         bugleProvider.attachInfo(mContext, bugleProviderInfo);
    467         context.addContentProvider(MessagingContentProvider.AUTHORITY, bugleProvider);
    468         final ContentProvider mediaProvider = new MediaScratchFileProvider();
    469         final ProviderInfo mediaProviderInfo = new ProviderInfo();
    470         mediaProviderInfo.authority = MediaScratchFileProvider.AUTHORITY;
    471         mediaProvider.attachInfo(mContext, mediaProviderInfo);
    472         context.addContentProvider(MediaScratchFileProvider.AUTHORITY, mediaProvider);
    473 
    474         mService = new StubActionService();
    475         final FakeDataModel fakeDataModel = new FakeDataModel(context)
    476                 .withActionService(mService)
    477                 .withConnectivityUtil(new StubConnectivityUtil(context));
    478         FakeFactory.registerWithFakeContext(getTestContext(), context)
    479                 .withDataModel(fakeDataModel);
    480 
    481     }
    482 }
    483