• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 
PhotoProviderTest()66     public PhotoProviderTest() {
67         super(PhotoProvider.class, PhotoProvider.AUTHORITY);
68     }
69 
70     @Override
setUp()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
tearDown()104     protected void tearDown() throws Exception {
105         mDBHelper.close();
106         mDBHelper = null;
107         super.tearDown();
108         getMockContext().deleteDatabase(PhotoProvider.DB_NAME);
109     }
110 
testDelete()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 
testDeleteMetadataId()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.
testDeleteAlbumCascade()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.
testDeleteAlbumCascade2()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.
testDeletePhotoCascade()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 
testDeleteAccountCascade()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 
testGetType()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 
testInsert()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 
testUpdate()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 
testQuery()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 
testUpdatePhotoNotification()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 
testUpdateMetadataNotification()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 
testBatchTransaction()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