1 /* 2 * Copyright (C) 2011 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.browser.tests.utils; 18 19 import com.android.browser.provider.BrowserProvider2; 20 21 import java.io.File; 22 import java.io.FilenameFilter; 23 24 import android.content.ContentValues; 25 import android.database.ContentObserver; 26 import android.net.Uri; 27 import android.provider.Browser; 28 import android.provider.BrowserContract; 29 import android.provider.BrowserContract.Bookmarks; 30 import android.provider.BrowserContract.History; 31 import android.util.Log; 32 33 /** 34 * This is a replacement for ProviderTestCase2 that can handle notifyChange testing. 35 * It also has helper methods specifically for testing BrowserProvider2 36 */ 37 public abstract class BP2TestCaseHelper extends ProviderTestCase3<BrowserProvider2> { 38 39 // Tag for potential performance impacts 40 private static final String PERFTAG = "BP2-PerfCheck"; 41 42 private TriggeredObserver mLegacyObserver; 43 private TriggeredObserver mRootObserver; 44 private TriggeredObserver mBookmarksObserver; 45 private TriggeredObserver mHistoryObserver; 46 private TriggeredObserver mWidgetObserver; 47 48 @Override 49 protected void setUp() throws Exception { 50 super.setUp(); 51 mLegacyObserver = new TriggeredObserver(Browser.BOOKMARKS_URI); 52 mRootObserver = new TriggeredObserver(BrowserContract.AUTHORITY_URI); 53 mBookmarksObserver = new TriggeredObserver(Bookmarks.CONTENT_URI); 54 mHistoryObserver = new TriggeredObserver(History.CONTENT_URI); 55 mWidgetObserver = new TriggeredObserver(); 56 // We don't need to worry about setting this back to null since this 57 // is a private instance local to the MockContentResolver 58 getProvider().setWidgetObserver(mWidgetObserver); 59 } 60 61 public BP2TestCaseHelper() { 62 super(BrowserProvider2.class, 63 BrowserContract.AUTHORITY, BrowserProvider2.LEGACY_AUTHORITY); 64 } 65 66 public void perfIdeallyUntriggered(TriggeredObserver... obs) { 67 for (TriggeredObserver ob : obs) { 68 if (ob.checkTriggered()) { 69 // Not ideal, unnecessary notification 70 Log.i(PERFTAG, ob.mUri + " onChange called but content unaltered!"); 71 } 72 } 73 } 74 75 public void assertObserversTriggered(boolean triggered, 76 TriggeredObserver... observers) { 77 for (TriggeredObserver obs : observers) { 78 assertEquals(obs.mUri + ", descendents:" + obs.mNotifyForDescendents, 79 triggered, obs.checkTriggered()); 80 } 81 } 82 83 public class TriggeredObserver extends ContentObserver { 84 private boolean mTriggered; 85 Uri mUri; 86 boolean mNotifyForDescendents; 87 88 /** 89 * Creates an unmanaged TriggeredObserver 90 */ 91 public TriggeredObserver() { 92 super(null); 93 } 94 95 /** 96 * Same as TriggeredObserver(uri, true); 97 */ 98 public TriggeredObserver(Uri uri) { 99 this(uri, true); 100 } 101 102 /** 103 * Creates a managed TriggeredObserver that self-registers with the 104 * mock ContentResolver 105 */ 106 public TriggeredObserver(Uri uri, boolean notifyForDescendents) { 107 super(null); 108 mUri = uri; 109 mNotifyForDescendents = notifyForDescendents; 110 registerContentObserver(uri, notifyForDescendents, this); 111 } 112 113 @Override 114 public void onChange(boolean selfChange) { 115 super.onChange(selfChange); 116 mTriggered = true; 117 } 118 119 public boolean checkTriggered() { 120 boolean ret = mTriggered; 121 mTriggered = false; 122 return ret; 123 } 124 } 125 126 Uri mockInsert(Uri uri, ContentValues values) { 127 assertObserversTriggered(false, mLegacyObserver, mRootObserver); 128 Uri ret = getMockContentResolver().insert(uri, values); 129 assertObserversTriggered(true, mLegacyObserver, mRootObserver); 130 return ret; 131 } 132 133 int mockUpdate(Uri uri, ContentValues values, String where, 134 String[] selectionArgs) { 135 assertObserversTriggered(false, mLegacyObserver, mRootObserver); 136 int ret = getMockContentResolver().update(uri, values, where, selectionArgs); 137 if (ret > 0) { 138 assertObserversTriggered(true, mLegacyObserver, mRootObserver); 139 } else { 140 perfIdeallyUntriggered(mLegacyObserver); 141 perfIdeallyUntriggered(mRootObserver); 142 } 143 return ret; 144 } 145 146 public Uri insertBookmark(String url, String title) { 147 ContentValues values = new ContentValues(); 148 values.put(BrowserContract.Bookmarks.TITLE, title); 149 values.put(BrowserContract.Bookmarks.URL, url); 150 values.put(BrowserContract.Bookmarks.IS_FOLDER, 0); 151 return insertBookmark(values); 152 } 153 154 public Uri insertBookmark(ContentValues values) { 155 assertObserversTriggered(false, mBookmarksObserver, mWidgetObserver); 156 Uri ret = mockInsert(Bookmarks.CONTENT_URI, values); 157 assertObserversTriggered(true, mBookmarksObserver, mWidgetObserver); 158 perfIdeallyUntriggered(mHistoryObserver); 159 return ret; 160 } 161 162 public boolean updateBookmark(Uri uri, String url, String title) { 163 ContentValues values = new ContentValues(); 164 values.put(BrowserContract.Bookmarks.TITLE, title); 165 values.put(BrowserContract.Bookmarks.URL, url); 166 return updateBookmark(uri, values); 167 } 168 169 public boolean updateBookmark(Uri uri, ContentValues values) { 170 assertObserversTriggered(false, mBookmarksObserver, mWidgetObserver); 171 int modifyCount = mockUpdate(uri, values, null, null); 172 assertTrue("UpdatedBookmark modified too much! " + uri, modifyCount <= 1); 173 boolean updated = modifyCount == 1; 174 if (updated) { 175 assertObserversTriggered(updated, mBookmarksObserver, mWidgetObserver); 176 } else { 177 perfIdeallyUntriggered(mBookmarksObserver, mWidgetObserver); 178 } 179 perfIdeallyUntriggered(mHistoryObserver); 180 return updated; 181 } 182 183 public Uri insertHistory(String url, String title) { 184 ContentValues values = new ContentValues(); 185 values.put(BrowserContract.History.TITLE, title); 186 values.put(BrowserContract.History.URL, url); 187 assertObserversTriggered(false, mHistoryObserver); 188 Uri ret = mockInsert(History.CONTENT_URI, values); 189 assertObserversTriggered(true, mHistoryObserver); 190 perfIdeallyUntriggered(mBookmarksObserver, mWidgetObserver); 191 return ret; 192 } 193 194 public boolean updateHistory(Uri uri, String url, String title) { 195 ContentValues values = new ContentValues(); 196 values.put(BrowserContract.History.TITLE, title); 197 values.put(BrowserContract.History.URL, url); 198 return updateHistory(uri, values); 199 } 200 201 public boolean updateHistory(Uri uri, ContentValues values) { 202 assertObserversTriggered(false, mHistoryObserver); 203 int modifyCount = mockUpdate(uri, values, null, null); 204 assertTrue("UpdatedHistory modified too much! " + uri, modifyCount <= 1); 205 boolean updated = modifyCount == 1; 206 if (updated) { 207 assertObserversTriggered(updated, mHistoryObserver); 208 } else { 209 perfIdeallyUntriggered(mHistoryObserver); 210 } 211 perfIdeallyUntriggered(mBookmarksObserver, mWidgetObserver); 212 return updated; 213 } 214 215 @Override 216 protected void tearDown() throws Exception { 217 super.tearDown(); 218 // Delete the test databases so that subsequent runs have a clean slate 219 File f = getMockContext().getDatabasePath("test"); 220 File dir = f.getParentFile(); 221 File testFiles[] = dir.listFiles(new FilenameFilter() { 222 223 @Override 224 public boolean accept(File dir, String filename) { 225 return filename.startsWith(ProviderTestCase3.FILENAME_PREFIX); 226 } 227 }); 228 for (File testFile : testFiles) { 229 testFile.delete(); 230 } 231 } 232 } 233