Home | History | Annotate | Download | only in data
      1 /*
      2  * Copyright (C) 2013 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 package com.android.photos.data;
     17 
     18 import android.content.ContentProviderOperation;
     19 import android.content.ContentResolver;
     20 import android.content.ContentUris;
     21 import android.content.ContentValues;
     22 import android.content.OperationApplicationException;
     23 import android.database.Cursor;
     24 import android.database.sqlite.SQLiteDatabase;
     25 import android.database.sqlite.SQLiteOpenHelper;
     26 import android.net.Uri;
     27 import android.os.RemoteException;
     28 import android.provider.BaseColumns;
     29 import android.test.ProviderTestCase2;
     30 
     31 import com.android.photos.data.PhotoProvider.Accounts;
     32 import com.android.photos.data.PhotoProvider.Albums;
     33 import com.android.photos.data.PhotoProvider.Metadata;
     34 import com.android.photos.data.PhotoProvider.Photos;
     35 
     36 import java.util.ArrayList;
     37 
     38 public class PhotoProviderTest extends ProviderTestCase2<PhotoProvider> {
     39     @SuppressWarnings("unused")
     40     private static final String TAG = PhotoProviderTest.class.getSimpleName();
     41 
     42     private static final String MIME_TYPE = "test/test";
     43     private static final String ALBUM_TITLE = "My Album";
     44     private static final long ALBUM_PARENT_ID = 100;
     45     private static final String META_KEY = "mykey";
     46     private static final String META_VALUE = "myvalue";
     47     private static final String ACCOUNT_NAME = "foo (at) bar.com";
     48 
     49     private static final Uri NO_TABLE_URI = PhotoProvider.BASE_CONTENT_URI;
     50     private static final Uri BAD_TABLE_URI = Uri.withAppendedPath(PhotoProvider.BASE_CONTENT_URI,
     51             "bad_table");
     52 
     53     private static final String WHERE_METADATA_PHOTOS_ID = Metadata.PHOTO_ID + " = ?";
     54     private static final String WHERE_METADATA = Metadata.PHOTO_ID + " = ? AND " + Metadata.KEY
     55             + " = ?";
     56 
     57     private long mAlbumId;
     58     private long mPhotoId;
     59     private long mMetadataId;
     60     private long mAccountId;
     61 
     62     private SQLiteOpenHelper mDBHelper;
     63     private ContentResolver mResolver;
     64     private NotificationWatcher mNotifications = new NotificationWatcher();
     65 
     66     public PhotoProviderTest() {
     67         super(PhotoProvider.class, PhotoProvider.AUTHORITY);
     68     }
     69 
     70     @Override
     71     protected void setUp() throws Exception {
     72         super.setUp();
     73         mResolver = getMockContentResolver();
     74         PhotoProvider provider = (PhotoProvider) getProvider();
     75         provider.setMockNotification(mNotifications);
     76         mDBHelper = provider.getDatabaseHelper();
     77         SQLiteDatabase db = mDBHelper.getWritableDatabase();
     78         db.beginTransaction();
     79         try {
     80             PhotoDatabaseUtils.insertAccount(db, ACCOUNT_NAME);
     81             mAccountId = PhotoDatabaseUtils.queryAccountIdFromName(db, ACCOUNT_NAME);
     82             PhotoDatabaseUtils.insertAlbum(db, ALBUM_PARENT_ID, ALBUM_TITLE,
     83                     Albums.VISIBILITY_PRIVATE, mAccountId);
     84             mAlbumId = PhotoDatabaseUtils.queryAlbumIdFromParentId(db, ALBUM_PARENT_ID);
     85             PhotoDatabaseUtils.insertPhoto(db, 100, 100, System.currentTimeMillis(), mAlbumId,
     86                     MIME_TYPE, mAccountId);
     87             mPhotoId = PhotoDatabaseUtils.queryPhotoIdFromAlbumId(db, mAlbumId);
     88             PhotoDatabaseUtils.insertMetadata(db, mPhotoId, META_KEY, META_VALUE);
     89             String[] projection = {
     90                     BaseColumns._ID,
     91             };
     92             Cursor cursor = db.query(Metadata.TABLE, projection, null, null, null, null, null);
     93             cursor.moveToNext();
     94             mMetadataId = cursor.getLong(0);
     95             cursor.close();
     96             db.setTransactionSuccessful();
     97             mNotifications.reset();
     98         } finally {
     99             db.endTransaction();
    100         }
    101     }
    102 
    103     @Override
    104     protected void tearDown() throws Exception {
    105         mDBHelper.close();
    106         mDBHelper = null;
    107         super.tearDown();
    108         getMockContext().deleteDatabase(PhotoProvider.DB_NAME);
    109     }
    110 
    111     public void testDelete() {
    112         try {
    113             mResolver.delete(NO_TABLE_URI, null, null);
    114             fail("Exeption should be thrown when no table given");
    115         } catch (Exception e) {
    116             // expected exception
    117         }
    118         try {
    119             mResolver.delete(BAD_TABLE_URI, null, null);
    120             fail("Exeption should be thrown when deleting from a table that doesn't exist");
    121         } catch (Exception e) {
    122             // expected exception
    123         }
    124 
    125         String[] selectionArgs = {
    126             String.valueOf(mPhotoId)
    127         };
    128         // Delete some metadata
    129         assertEquals(1,
    130                 mResolver.delete(Metadata.CONTENT_URI, WHERE_METADATA_PHOTOS_ID, selectionArgs));
    131         Uri photoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
    132         assertEquals(1, mResolver.delete(photoUri, null, null));
    133         Uri albumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId);
    134         assertEquals(1, mResolver.delete(albumUri, null, null));
    135         // now delete something that isn't there
    136         assertEquals(0, mResolver.delete(photoUri, null, null));
    137     }
    138 
    139     public void testDeleteMetadataId() {
    140         Uri metadataUri = ContentUris.withAppendedId(Metadata.CONTENT_URI, mMetadataId);
    141         assertEquals(1, mResolver.delete(metadataUri, null, null));
    142         Cursor cursor = mResolver.query(Metadata.CONTENT_URI, null, null, null, null);
    143         assertEquals(0, cursor.getCount());
    144         cursor.close();
    145     }
    146 
    147     // Delete the album and ensure that the photos referring to the album are
    148     // deleted.
    149     public void testDeleteAlbumCascade() {
    150         Uri albumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId);
    151         mResolver.delete(albumUri, null, null);
    152         assertTrue(mNotifications.isNotified(Photos.CONTENT_URI));
    153         assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI));
    154         assertTrue(mNotifications.isNotified(albumUri));
    155         assertEquals(3, mNotifications.notificationCount());
    156         Cursor cursor = mResolver.query(Photos.CONTENT_URI, PhotoDatabaseUtils.PROJECTION_PHOTOS,
    157                 null, null, null);
    158         assertEquals(0, cursor.getCount());
    159         cursor.close();
    160     }
    161 
    162     // Delete all albums and ensure that photos in any album are deleted.
    163     public void testDeleteAlbumCascade2() {
    164         mResolver.delete(Albums.CONTENT_URI, null, null);
    165         assertTrue(mNotifications.isNotified(Photos.CONTENT_URI));
    166         assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI));
    167         assertTrue(mNotifications.isNotified(Albums.CONTENT_URI));
    168         assertEquals(3, mNotifications.notificationCount());
    169         Cursor cursor = mResolver.query(Photos.CONTENT_URI, PhotoDatabaseUtils.PROJECTION_PHOTOS,
    170                 null, null, null);
    171         assertEquals(0, cursor.getCount());
    172         cursor.close();
    173     }
    174 
    175     // Delete a photo and ensure that the metadata for that photo are deleted.
    176     public void testDeletePhotoCascade() {
    177         Uri photoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
    178         mResolver.delete(photoUri, null, null);
    179         assertTrue(mNotifications.isNotified(photoUri));
    180         assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI));
    181         assertEquals(2, mNotifications.notificationCount());
    182         Cursor cursor = mResolver.query(Metadata.CONTENT_URI,
    183                 PhotoDatabaseUtils.PROJECTION_METADATA, null, null, null);
    184         assertEquals(0, cursor.getCount());
    185         cursor.close();
    186     }
    187 
    188     public void testDeleteAccountCascade() {
    189         Uri accountUri = ContentUris.withAppendedId(Accounts.CONTENT_URI, mAccountId);
    190         SQLiteDatabase db = mDBHelper.getWritableDatabase();
    191         db.beginTransaction();
    192         PhotoDatabaseUtils.insertPhoto(db, 100, 100, System.currentTimeMillis(), null,
    193                 "image/jpeg", mAccountId);
    194         PhotoDatabaseUtils.insertPhoto(db, 100, 100, System.currentTimeMillis(), null,
    195                 "image/jpeg", 0L);
    196         PhotoDatabaseUtils.insertAlbum(db, null, "title", Albums.VISIBILITY_PRIVATE, 10630L);
    197         db.setTransactionSuccessful();
    198         db.endTransaction();
    199         // ensure all pictures are there:
    200         Cursor cursor = mResolver.query(Photos.CONTENT_URI, null, null, null, null);
    201         assertEquals(3, cursor.getCount());
    202         cursor.close();
    203         // delete the account
    204         assertEquals(1, mResolver.delete(accountUri, null, null));
    205         // now ensure that all associated photos were deleted
    206         cursor = mResolver.query(Photos.CONTENT_URI, null, null, null, null);
    207         assertEquals(1, cursor.getCount());
    208         cursor.close();
    209         // now ensure all associated albums were deleted.
    210         cursor = mResolver.query(Albums.CONTENT_URI, null, null, null, null);
    211         assertEquals(1, cursor.getCount());
    212         cursor.close();
    213     }
    214 
    215     public void testGetType() {
    216         // We don't return types for albums
    217         assertNull(mResolver.getType(Albums.CONTENT_URI));
    218 
    219         Uri noImage = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId + 1);
    220         assertNull(mResolver.getType(noImage));
    221 
    222         Uri image = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
    223         assertEquals(MIME_TYPE, mResolver.getType(image));
    224     }
    225 
    226     public void testInsert() {
    227         ContentValues values = new ContentValues();
    228         values.put(Albums.TITLE, "add me");
    229         values.put(Albums.VISIBILITY, Albums.VISIBILITY_PRIVATE);
    230         values.put(Albums.ACCOUNT_ID, 100L);
    231         values.put(Albums.DATE_MODIFIED, 100L);
    232         values.put(Albums.DATE_PUBLISHED, 100L);
    233         values.put(Albums.LOCATION_STRING, "Home");
    234         values.put(Albums.TITLE, "hello world");
    235         values.putNull(Albums.PARENT_ID);
    236         values.put(Albums.SUMMARY, "Nothing much to say about this");
    237         Uri insertedUri = mResolver.insert(Albums.CONTENT_URI, values);
    238         assertNotNull(insertedUri);
    239         Cursor cursor = mResolver.query(insertedUri, PhotoDatabaseUtils.PROJECTION_ALBUMS, null,
    240                 null, null);
    241         assertNotNull(cursor);
    242         assertEquals(1, cursor.getCount());
    243         cursor.close();
    244     }
    245 
    246     public void testUpdate() {
    247         ContentValues values = new ContentValues();
    248         // Normal update -- use an album.
    249         values.put(Albums.TITLE, "foo");
    250         Uri albumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId);
    251         assertEquals(1, mResolver.update(albumUri, values, null, null));
    252         String[] projection = {
    253             Albums.TITLE,
    254         };
    255         Cursor cursor = mResolver.query(albumUri, projection, null, null, null);
    256         assertEquals(1, cursor.getCount());
    257         assertTrue(cursor.moveToNext());
    258         assertEquals("foo", cursor.getString(0));
    259         cursor.close();
    260 
    261         // Update a row that doesn't exist.
    262         Uri noAlbumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId + 1);
    263         values.put(Albums.TITLE, "bar");
    264         assertEquals(0, mResolver.update(noAlbumUri, values, null, null));
    265 
    266         // Update a metadata value that exists.
    267         ContentValues metadata = new ContentValues();
    268         metadata.put(Metadata.PHOTO_ID, mPhotoId);
    269         metadata.put(Metadata.KEY, META_KEY);
    270         metadata.put(Metadata.VALUE, "new value");
    271         assertEquals(1, mResolver.update(Metadata.CONTENT_URI, metadata, null, null));
    272 
    273         projection = new String[] {
    274             Metadata.VALUE,
    275         };
    276 
    277         String[] selectionArgs = {
    278                 String.valueOf(mPhotoId), META_KEY,
    279         };
    280 
    281         cursor = mResolver.query(Metadata.CONTENT_URI, projection, WHERE_METADATA, selectionArgs,
    282                 null);
    283         assertEquals(1, cursor.getCount());
    284         assertTrue(cursor.moveToNext());
    285         assertEquals("new value", cursor.getString(0));
    286         cursor.close();
    287 
    288         // Update a metadata value that doesn't exist.
    289         metadata.put(Metadata.KEY, "other stuff");
    290         assertEquals(1, mResolver.update(Metadata.CONTENT_URI, metadata, null, null));
    291 
    292         selectionArgs[1] = "other stuff";
    293         cursor = mResolver.query(Metadata.CONTENT_URI, projection, WHERE_METADATA, selectionArgs,
    294                 null);
    295         assertEquals(1, cursor.getCount());
    296         assertTrue(cursor.moveToNext());
    297         assertEquals("new value", cursor.getString(0));
    298         cursor.close();
    299 
    300         // Remove a metadata value using update.
    301         metadata.putNull(Metadata.VALUE);
    302         assertEquals(1, mResolver.update(Metadata.CONTENT_URI, metadata, null, null));
    303         cursor = mResolver.query(Metadata.CONTENT_URI, projection, WHERE_METADATA, selectionArgs,
    304                 null);
    305         assertEquals(0, cursor.getCount());
    306         cursor.close();
    307     }
    308 
    309     public void testQuery() {
    310         // Query a photo that exists.
    311         Cursor cursor = mResolver.query(Photos.CONTENT_URI, PhotoDatabaseUtils.PROJECTION_PHOTOS,
    312                 null, null, null);
    313         assertNotNull(cursor);
    314         assertEquals(1, cursor.getCount());
    315         assertTrue(cursor.moveToNext());
    316         assertEquals(mPhotoId, cursor.getLong(0));
    317         cursor.close();
    318 
    319         // Query a photo that doesn't exist.
    320         Uri noPhotoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId + 1);
    321         cursor = mResolver.query(noPhotoUri, PhotoDatabaseUtils.PROJECTION_PHOTOS, null, null,
    322                 null);
    323         assertNotNull(cursor);
    324         assertEquals(0, cursor.getCount());
    325         cursor.close();
    326 
    327         // Query a photo that exists using selection arguments.
    328         String[] selectionArgs = {
    329             String.valueOf(mPhotoId),
    330         };
    331 
    332         cursor = mResolver.query(Photos.CONTENT_URI, PhotoDatabaseUtils.PROJECTION_PHOTOS,
    333                 Photos._ID + " = ?", selectionArgs, null);
    334         assertNotNull(cursor);
    335         assertEquals(1, cursor.getCount());
    336         assertTrue(cursor.moveToNext());
    337         assertEquals(mPhotoId, cursor.getLong(0));
    338         cursor.close();
    339     }
    340 
    341     public void testUpdatePhotoNotification() {
    342         Uri photoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
    343         ContentValues values = new ContentValues();
    344         values.put(Photos.MIME_TYPE, "not-a/mime-type");
    345         mResolver.update(photoUri, values, null, null);
    346         assertTrue(mNotifications.isNotified(photoUri));
    347     }
    348 
    349     public void testUpdateMetadataNotification() {
    350         ContentValues values = new ContentValues();
    351         values.put(Metadata.PHOTO_ID, mPhotoId);
    352         values.put(Metadata.KEY, META_KEY);
    353         values.put(Metadata.VALUE, "hello world");
    354         mResolver.update(Metadata.CONTENT_URI, values, null, null);
    355         assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI));
    356     }
    357 
    358     public void testBatchTransaction() throws RemoteException, OperationApplicationException {
    359         ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
    360         ContentProviderOperation.Builder insert = ContentProviderOperation
    361                 .newInsert(Photos.CONTENT_URI);
    362         insert.withValue(Photos.WIDTH, 200L);
    363         insert.withValue(Photos.HEIGHT, 100L);
    364         insert.withValue(Photos.DATE_TAKEN, System.currentTimeMillis());
    365         insert.withValue(Photos.ALBUM_ID, 1000L);
    366         insert.withValue(Photos.MIME_TYPE, "image/jpg");
    367         insert.withValue(Photos.ACCOUNT_ID, 1L);
    368         operations.add(insert.build());
    369         ContentProviderOperation.Builder update = ContentProviderOperation.newUpdate(Photos.CONTENT_URI);
    370         update.withValue(Photos.DATE_MODIFIED, System.currentTimeMillis());
    371         String[] whereArgs = {
    372             "100",
    373         };
    374         String where = Photos.WIDTH + " = ?";
    375         update.withSelection(where, whereArgs);
    376         operations.add(update.build());
    377         ContentProviderOperation.Builder delete = ContentProviderOperation
    378                 .newDelete(Photos.CONTENT_URI);
    379         delete.withSelection(where, whereArgs);
    380         operations.add(delete.build());
    381         mResolver.applyBatch(PhotoProvider.AUTHORITY, operations);
    382         assertEquals(3, mNotifications.notificationCount());
    383         SQLiteDatabase db = mDBHelper.getReadableDatabase();
    384         long id = PhotoDatabaseUtils.queryPhotoIdFromAlbumId(db, 1000L);
    385         Uri uri = ContentUris.withAppendedId(Photos.CONTENT_URI, id);
    386         assertTrue(mNotifications.isNotified(uri));
    387         assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI));
    388         assertTrue(mNotifications.isNotified(Photos.CONTENT_URI));
    389     }
    390 
    391 }
    392