blob: 685946ef0ea2585c774c972e1ca3bd40e7e302de [file] [log] [blame]
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.photos.data;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.os.RemoteException;
import android.provider.BaseColumns;
import android.test.ProviderTestCase2;
import com.android.photos.data.PhotoProvider.Accounts;
import com.android.photos.data.PhotoProvider.Albums;
import com.android.photos.data.PhotoProvider.Metadata;
import com.android.photos.data.PhotoProvider.Photos;
import java.util.ArrayList;
public class PhotoProviderTest extends ProviderTestCase2<PhotoProvider> {
@SuppressWarnings("unused")
private static final String TAG = PhotoProviderTest.class.getSimpleName();
private static final String MIME_TYPE = "test/test";
private static final String ALBUM_TITLE = "My Album";
private static final long ALBUM_PARENT_ID = 100;
private static final String META_KEY = "mykey";
private static final String META_VALUE = "myvalue";
private static final String ACCOUNT_NAME = "foo@bar.com";
private static final Uri NO_TABLE_URI = PhotoProvider.BASE_CONTENT_URI;
private static final Uri BAD_TABLE_URI = Uri.withAppendedPath(PhotoProvider.BASE_CONTENT_URI,
"bad_table");
private static final String WHERE_METADATA_PHOTOS_ID = Metadata.PHOTO_ID + " = ?";
private static final String WHERE_METADATA = Metadata.PHOTO_ID + " = ? AND " + Metadata.KEY
+ " = ?";
private long mAlbumId;
private long mPhotoId;
private long mMetadataId;
private long mAccountId;
private SQLiteOpenHelper mDBHelper;
private ContentResolver mResolver;
private NotificationWatcher mNotifications = new NotificationWatcher();
public PhotoProviderTest() {
super(PhotoProvider.class, PhotoProvider.AUTHORITY);
}
@Override
protected void setUp() throws Exception {
super.setUp();
mResolver = getMockContentResolver();
PhotoProvider provider = (PhotoProvider) getProvider();
provider.setMockNotification(mNotifications);
mDBHelper = provider.getDatabaseHelper();
SQLiteDatabase db = mDBHelper.getWritableDatabase();
db.beginTransaction();
try {
PhotoDatabaseUtils.insertAccount(db, ACCOUNT_NAME);
mAccountId = PhotoDatabaseUtils.queryAccountIdFromName(db, ACCOUNT_NAME);
PhotoDatabaseUtils.insertAlbum(db, ALBUM_PARENT_ID, ALBUM_TITLE,
Albums.VISIBILITY_PRIVATE, mAccountId);
mAlbumId = PhotoDatabaseUtils.queryAlbumIdFromParentId(db, ALBUM_PARENT_ID);
PhotoDatabaseUtils.insertPhoto(db, 100, 100, System.currentTimeMillis(), mAlbumId,
MIME_TYPE, mAccountId);
mPhotoId = PhotoDatabaseUtils.queryPhotoIdFromAlbumId(db, mAlbumId);
PhotoDatabaseUtils.insertMetadata(db, mPhotoId, META_KEY, META_VALUE);
String[] projection = {
BaseColumns._ID,
};
Cursor cursor = db.query(Metadata.TABLE, projection, null, null, null, null, null);
cursor.moveToNext();
mMetadataId = cursor.getLong(0);
cursor.close();
db.setTransactionSuccessful();
mNotifications.reset();
} finally {
db.endTransaction();
}
}
@Override
protected void tearDown() throws Exception {
mDBHelper.close();
mDBHelper = null;
super.tearDown();
getMockContext().deleteDatabase(PhotoProvider.DB_NAME);
}
public void testDelete() {
try {
mResolver.delete(NO_TABLE_URI, null, null);
fail("Exeption should be thrown when no table given");
} catch (Exception e) {
// expected exception
}
try {
mResolver.delete(BAD_TABLE_URI, null, null);
fail("Exeption should be thrown when deleting from a table that doesn't exist");
} catch (Exception e) {
// expected exception
}
String[] selectionArgs = {
String.valueOf(mPhotoId)
};
// Delete some metadata
assertEquals(1,
mResolver.delete(Metadata.CONTENT_URI, WHERE_METADATA_PHOTOS_ID, selectionArgs));
Uri photoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
assertEquals(1, mResolver.delete(photoUri, null, null));
Uri albumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId);
assertEquals(1, mResolver.delete(albumUri, null, null));
// now delete something that isn't there
assertEquals(0, mResolver.delete(photoUri, null, null));
}
public void testDeleteMetadataId() {
Uri metadataUri = ContentUris.withAppendedId(Metadata.CONTENT_URI, mMetadataId);
assertEquals(1, mResolver.delete(metadataUri, null, null));
Cursor cursor = mResolver.query(Metadata.CONTENT_URI, null, null, null, null);
assertEquals(0, cursor.getCount());
cursor.close();
}
// Delete the album and ensure that the photos referring to the album are
// deleted.
public void testDeleteAlbumCascade() {
Uri albumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId);
mResolver.delete(albumUri, null, null);
assertTrue(mNotifications.isNotified(Photos.CONTENT_URI));
assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI));
assertTrue(mNotifications.isNotified(albumUri));
assertEquals(3, mNotifications.notificationCount());
Cursor cursor = mResolver.query(Photos.CONTENT_URI, PhotoDatabaseUtils.PROJECTION_PHOTOS,
null, null, null);
assertEquals(0, cursor.getCount());
cursor.close();
}
// Delete all albums and ensure that photos in any album are deleted.
public void testDeleteAlbumCascade2() {
mResolver.delete(Albums.CONTENT_URI, null, null);
assertTrue(mNotifications.isNotified(Photos.CONTENT_URI));
assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI));
assertTrue(mNotifications.isNotified(Albums.CONTENT_URI));
assertEquals(3, mNotifications.notificationCount());
Cursor cursor = mResolver.query(Photos.CONTENT_URI, PhotoDatabaseUtils.PROJECTION_PHOTOS,
null, null, null);
assertEquals(0, cursor.getCount());
cursor.close();
}
// Delete a photo and ensure that the metadata for that photo are deleted.
public void testDeletePhotoCascade() {
Uri photoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
mResolver.delete(photoUri, null, null);
assertTrue(mNotifications.isNotified(photoUri));
assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI));
assertEquals(2, mNotifications.notificationCount());
Cursor cursor = mResolver.query(Metadata.CONTENT_URI,
PhotoDatabaseUtils.PROJECTION_METADATA, null, null, null);
assertEquals(0, cursor.getCount());
cursor.close();
}
public void testDeleteAccountCascade() {
Uri accountUri = ContentUris.withAppendedId(Accounts.CONTENT_URI, mAccountId);
SQLiteDatabase db = mDBHelper.getWritableDatabase();
db.beginTransaction();
PhotoDatabaseUtils.insertPhoto(db, 100, 100, System.currentTimeMillis(), null,
"image/jpeg", mAccountId);
PhotoDatabaseUtils.insertPhoto(db, 100, 100, System.currentTimeMillis(), null,
"image/jpeg", 0L);
PhotoDatabaseUtils.insertAlbum(db, null, "title", Albums.VISIBILITY_PRIVATE, 10630L);
db.setTransactionSuccessful();
db.endTransaction();
// ensure all pictures are there:
Cursor cursor = mResolver.query(Photos.CONTENT_URI, null, null, null, null);
assertEquals(3, cursor.getCount());
cursor.close();
// delete the account
assertEquals(1, mResolver.delete(accountUri, null, null));
// now ensure that all associated photos were deleted
cursor = mResolver.query(Photos.CONTENT_URI, null, null, null, null);
assertEquals(1, cursor.getCount());
cursor.close();
// now ensure all associated albums were deleted.
cursor = mResolver.query(Albums.CONTENT_URI, null, null, null, null);
assertEquals(1, cursor.getCount());
cursor.close();
}
public void testGetType() {
// We don't return types for albums
assertNull(mResolver.getType(Albums.CONTENT_URI));
Uri noImage = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId + 1);
assertNull(mResolver.getType(noImage));
Uri image = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
assertEquals(MIME_TYPE, mResolver.getType(image));
}
public void testInsert() {
ContentValues values = new ContentValues();
values.put(Albums.TITLE, "add me");
values.put(Albums.VISIBILITY, Albums.VISIBILITY_PRIVATE);
values.put(Albums.ACCOUNT_ID, 100L);
values.put(Albums.DATE_MODIFIED, 100L);
values.put(Albums.DATE_PUBLISHED, 100L);
values.put(Albums.LOCATION_STRING, "Home");
values.put(Albums.TITLE, "hello world");
values.putNull(Albums.PARENT_ID);
values.put(Albums.SUMMARY, "Nothing much to say about this");
Uri insertedUri = mResolver.insert(Albums.CONTENT_URI, values);
assertNotNull(insertedUri);
Cursor cursor = mResolver.query(insertedUri, PhotoDatabaseUtils.PROJECTION_ALBUMS, null,
null, null);
assertNotNull(cursor);
assertEquals(1, cursor.getCount());
cursor.close();
}
public void testUpdate() {
ContentValues values = new ContentValues();
// Normal update -- use an album.
values.put(Albums.TITLE, "foo");
Uri albumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId);
assertEquals(1, mResolver.update(albumUri, values, null, null));
String[] projection = {
Albums.TITLE,
};
Cursor cursor = mResolver.query(albumUri, projection, null, null, null);
assertEquals(1, cursor.getCount());
assertTrue(cursor.moveToNext());
assertEquals("foo", cursor.getString(0));
cursor.close();
// Update a row that doesn't exist.
Uri noAlbumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId + 1);
values.put(Albums.TITLE, "bar");
assertEquals(0, mResolver.update(noAlbumUri, values, null, null));
// Update a metadata value that exists.
ContentValues metadata = new ContentValues();
metadata.put(Metadata.PHOTO_ID, mPhotoId);
metadata.put(Metadata.KEY, META_KEY);
metadata.put(Metadata.VALUE, "new value");
assertEquals(1, mResolver.update(Metadata.CONTENT_URI, metadata, null, null));
projection = new String[] {
Metadata.VALUE,
};
String[] selectionArgs = {
String.valueOf(mPhotoId), META_KEY,
};
cursor = mResolver.query(Metadata.CONTENT_URI, projection, WHERE_METADATA, selectionArgs,
null);
assertEquals(1, cursor.getCount());
assertTrue(cursor.moveToNext());
assertEquals("new value", cursor.getString(0));
cursor.close();
// Update a metadata value that doesn't exist.
metadata.put(Metadata.KEY, "other stuff");
assertEquals(1, mResolver.update(Metadata.CONTENT_URI, metadata, null, null));
selectionArgs[1] = "other stuff";
cursor = mResolver.query(Metadata.CONTENT_URI, projection, WHERE_METADATA, selectionArgs,
null);
assertEquals(1, cursor.getCount());
assertTrue(cursor.moveToNext());
assertEquals("new value", cursor.getString(0));
cursor.close();
// Remove a metadata value using update.
metadata.putNull(Metadata.VALUE);
assertEquals(1, mResolver.update(Metadata.CONTENT_URI, metadata, null, null));
cursor = mResolver.query(Metadata.CONTENT_URI, projection, WHERE_METADATA, selectionArgs,
null);
assertEquals(0, cursor.getCount());
cursor.close();
}
public void testQuery() {
// Query a photo that exists.
Cursor cursor = mResolver.query(Photos.CONTENT_URI, PhotoDatabaseUtils.PROJECTION_PHOTOS,
null, null, null);
assertNotNull(cursor);
assertEquals(1, cursor.getCount());
assertTrue(cursor.moveToNext());
assertEquals(mPhotoId, cursor.getLong(0));
cursor.close();
// Query a photo that doesn't exist.
Uri noPhotoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId + 1);
cursor = mResolver.query(noPhotoUri, PhotoDatabaseUtils.PROJECTION_PHOTOS, null, null,
null);
assertNotNull(cursor);
assertEquals(0, cursor.getCount());
cursor.close();
// Query a photo that exists using selection arguments.
String[] selectionArgs = {
String.valueOf(mPhotoId),
};
cursor = mResolver.query(Photos.CONTENT_URI, PhotoDatabaseUtils.PROJECTION_PHOTOS,
Photos._ID + " = ?", selectionArgs, null);
assertNotNull(cursor);
assertEquals(1, cursor.getCount());
assertTrue(cursor.moveToNext());
assertEquals(mPhotoId, cursor.getLong(0));
cursor.close();
}
public void testUpdatePhotoNotification() {
Uri photoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
ContentValues values = new ContentValues();
values.put(Photos.MIME_TYPE, "not-a/mime-type");
mResolver.update(photoUri, values, null, null);
assertTrue(mNotifications.isNotified(photoUri));
}
public void testUpdateMetadataNotification() {
ContentValues values = new ContentValues();
values.put(Metadata.PHOTO_ID, mPhotoId);
values.put(Metadata.KEY, META_KEY);
values.put(Metadata.VALUE, "hello world");
mResolver.update(Metadata.CONTENT_URI, values, null, null);
assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI));
}
public void testBatchTransaction() throws RemoteException, OperationApplicationException {
ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
ContentProviderOperation.Builder insert = ContentProviderOperation
.newInsert(Photos.CONTENT_URI);
insert.withValue(Photos.WIDTH, 200L);
insert.withValue(Photos.HEIGHT, 100L);
insert.withValue(Photos.DATE_TAKEN, System.currentTimeMillis());
insert.withValue(Photos.ALBUM_ID, 1000L);
insert.withValue(Photos.MIME_TYPE, "image/jpg");
insert.withValue(Photos.ACCOUNT_ID, 1L);
operations.add(insert.build());
ContentProviderOperation.Builder update = ContentProviderOperation.newUpdate(Photos.CONTENT_URI);
update.withValue(Photos.DATE_MODIFIED, System.currentTimeMillis());
String[] whereArgs = {
"100",
};
String where = Photos.WIDTH + " = ?";
update.withSelection(where, whereArgs);
operations.add(update.build());
ContentProviderOperation.Builder delete = ContentProviderOperation
.newDelete(Photos.CONTENT_URI);
delete.withSelection(where, whereArgs);
operations.add(delete.build());
mResolver.applyBatch(PhotoProvider.AUTHORITY, operations);
assertEquals(3, mNotifications.notificationCount());
SQLiteDatabase db = mDBHelper.getReadableDatabase();
long id = PhotoDatabaseUtils.queryPhotoIdFromAlbumId(db, 1000L);
Uri uri = ContentUris.withAppendedId(Photos.CONTENT_URI, id);
assertTrue(mNotifications.isNotified(uri));
assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI));
assertTrue(mNotifications.isNotified(Photos.CONTENT_URI));
}
}