1 /* 2 * Copyright (C) 2007 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.server.content; 18 19 import android.accounts.Account; 20 import android.content.ComponentName; 21 import android.content.ContentResolver; 22 import android.content.Context; 23 import android.content.ContextWrapper; 24 import android.content.Intent; 25 import android.content.res.Resources; 26 import android.os.Bundle; 27 import android.test.AndroidTestCase; 28 import android.test.RenamingDelegatingContext; 29 import android.test.mock.MockContentResolver; 30 import android.test.mock.MockContext; 31 import android.test.suitebuilder.annotation.LargeTest; 32 import android.test.suitebuilder.annotation.MediumTest; 33 import android.test.suitebuilder.annotation.SmallTest; 34 35 import com.android.internal.os.AtomicFile; 36 37 import java.io.File; 38 import java.io.FileOutputStream; 39 40 /** 41 * Test for SyncStorageEngine. 42 * 43 * bit FrameworksServicesTests:com.android.server.content.SyncStorageEngineTest 44 * 45 * TODO Broken. Fix it. b/62485315 46 */ 47 public class SyncStorageEngineTest extends AndroidTestCase { 48 49 protected Account account1; 50 protected Account account2; 51 protected ComponentName syncService1; 52 protected String authority1 = "testprovider"; 53 protected Bundle defaultBundle; 54 protected final int DEFAULT_USER = 0; 55 56 /* Some default poll frequencies. */ 57 final long dayPoll = (60 * 60 * 24); 58 final long dayFuzz = 60; 59 final long thousandSecs = 1000; 60 final long thousandSecsFuzz = 100; 61 62 MockContentResolver mockResolver; 63 SyncStorageEngine engine; 64 65 private File getSyncDir() { 66 return new File(new File(getContext().getFilesDir(), "system"), "sync"); 67 } 68 69 @Override 70 public void setUp() { 71 account1 = new Account("a (at) example.com", "example.type"); 72 account2 = new Account("b (at) example.com", "example.type"); 73 syncService1 = new ComponentName("com.example", "SyncService"); 74 // Default bundle. 75 defaultBundle = new Bundle(); 76 defaultBundle.putInt("int_key", 0); 77 defaultBundle.putString("string_key", "hello"); 78 // Set up storage engine. 79 mockResolver = new MockContentResolver(); 80 engine = SyncStorageEngine.newTestInstance( 81 new TestContext(mockResolver, getContext())); 82 } 83 84 /** 85 * Test that we handle the case of a history row being old enough to purge before the 86 * corresponding sync is finished. This can happen if the clock changes while we are syncing. 87 * 88 */ 89 // TODO: this test causes AidlTest to fail. Omit for now 90 // @SmallTest 91 public void testPurgeActiveSync() throws Exception { 92 final Account account = new Account("a (at) example.com", "example.type"); 93 final String authority = "testprovider"; 94 95 MockContentResolver mockResolver = new MockContentResolver(); 96 97 SyncStorageEngine engine = SyncStorageEngine.newTestInstance( 98 new TestContext(mockResolver, getContext())); 99 long time0 = 1000; 100 SyncOperation op = new SyncOperation(account, 0, 0, "foo", 101 SyncOperation.REASON_PERIODIC, 102 SyncStorageEngine.SOURCE_LOCAL, 103 authority, 104 Bundle.EMPTY, true); 105 long historyId = engine.insertStartSyncEvent(op, time0); 106 long time1 = time0 + SyncStorageEngine.MILLIS_IN_4WEEKS * 2; 107 engine.stopSyncEvent(historyId, time1 - time0, "yay", 0, 0); 108 } 109 110 @LargeTest 111 public void testAuthorityPersistence() throws Exception { 112 final Account account1 = new Account("a (at) example.com", "example.type"); 113 final Account account2 = new Account("b (at) example.com", "example.type.2"); 114 final String authority1 = "testprovider1"; 115 final String authority2 = "testprovider2"; 116 117 engine.setMasterSyncAutomatically(false, 0); 118 119 engine.setIsSyncable(account1, 0, authority1, 1); 120 engine.setSyncAutomatically(account1, 0, authority1, true); 121 122 engine.setIsSyncable(account2, 0, authority1, 1); 123 engine.setSyncAutomatically(account2, 0, authority1, true); 124 125 engine.setIsSyncable(account1, 0, authority2, 1); 126 engine.setSyncAutomatically(account1, 0, authority2, false); 127 128 engine.setIsSyncable(account2, 0, authority2, 0); 129 engine.setSyncAutomatically(account2, 0, authority2, true); 130 131 engine.writeAllState(); 132 engine.clearAndReadState(); 133 134 assertEquals(true, engine.getSyncAutomatically(account1, 0, authority1)); 135 assertEquals(true, engine.getSyncAutomatically(account2, 0, authority1)); 136 assertEquals(false, engine.getSyncAutomatically(account1, 0, authority2)); 137 assertEquals(true, engine.getSyncAutomatically(account2, 0, authority2)); 138 139 assertEquals(1, engine.getIsSyncable(account1, 0, authority1)); 140 assertEquals(1, engine.getIsSyncable(account2, 0, authority1)); 141 assertEquals(1, engine.getIsSyncable(account1, 0, authority2)); 142 assertEquals(0, engine.getIsSyncable(account2, 0, authority2)); 143 } 144 145 @MediumTest 146 public void testListenForTicklesParsing() throws Exception { 147 byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 148 + "<accounts>\n" 149 + "<listenForTickles user=\"0\" enabled=\"false\" />" 150 + "<listenForTickles user=\"1\" enabled=\"true\" />" 151 + "<authority id=\"0\" user=\"0\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n" 152 + "<authority id=\"1\" user=\"1\" account=\"account1\" type=\"type1\" authority=\"auth1\" />\n" 153 + "</accounts>\n").getBytes(); 154 155 MockContentResolver mockResolver = new MockContentResolver(); 156 final TestContext testContext = new TestContext(mockResolver, getContext()); 157 158 File syncDir = getSyncDir(); 159 syncDir.mkdirs(); 160 AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); 161 FileOutputStream fos = accountInfoFile.startWrite(); 162 fos.write(accountsFileData); 163 accountInfoFile.finishWrite(fos); 164 165 SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext); 166 167 assertEquals(false, engine.getMasterSyncAutomatically(0)); 168 assertEquals(true, engine.getMasterSyncAutomatically(1)); 169 assertEquals(true, engine.getMasterSyncAutomatically(2)); 170 171 } 172 173 @MediumTest 174 public void testAuthorityRenaming() throws Exception { 175 final Account account1 = new Account("acc1", "type1"); 176 final Account account2 = new Account("acc2", "type2"); 177 final String authorityContacts = "contacts"; 178 final String authorityCalendar = "calendar"; 179 final String authorityOther = "other"; 180 final String authorityContactsNew = "com.android.contacts"; 181 final String authorityCalendarNew = "com.android.calendar"; 182 183 MockContentResolver mockResolver = new MockContentResolver(); 184 185 final TestContext testContext = new TestContext(mockResolver, getContext()); 186 187 byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 188 + "<accounts>\n" 189 + "<authority id=\"0\" account=\"acc1\" type=\"type1\" authority=\"contacts\" />\n" 190 + "<authority id=\"1\" account=\"acc1\" type=\"type1\" authority=\"calendar\" />\n" 191 + "<authority id=\"2\" account=\"acc1\" type=\"type1\" authority=\"other\" />\n" 192 + "<authority id=\"3\" account=\"acc2\" type=\"type2\" authority=\"contacts\" />\n" 193 + "<authority id=\"4\" account=\"acc2\" type=\"type2\" authority=\"calendar\" />\n" 194 + "<authority id=\"5\" account=\"acc2\" type=\"type2\" authority=\"other\" />\n" 195 + "<authority id=\"6\" account=\"acc2\" type=\"type2\" enabled=\"false\"" 196 + " authority=\"com.android.calendar\" />\n" 197 + "<authority id=\"7\" account=\"acc2\" type=\"type2\" enabled=\"false\"" 198 + " authority=\"com.android.contacts\" />\n" 199 + "</accounts>\n").getBytes(); 200 201 File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync"); 202 syncDir.mkdirs(); 203 AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); 204 FileOutputStream fos = accountInfoFile.startWrite(); 205 fos.write(accountsFileData); 206 accountInfoFile.finishWrite(fos); 207 208 SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext); 209 210 assertEquals(false, engine.getSyncAutomatically(account1, 0, authorityContacts)); 211 assertEquals(false, engine.getSyncAutomatically(account1, 0, authorityCalendar)); 212 assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityOther)); 213 assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityContactsNew)); 214 assertEquals(true, engine.getSyncAutomatically(account1, 0, authorityCalendarNew)); 215 216 assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityContacts)); 217 assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityCalendar)); 218 assertEquals(true, engine.getSyncAutomatically(account2, 0, authorityOther)); 219 assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityContactsNew)); 220 assertEquals(false, engine.getSyncAutomatically(account2, 0, authorityCalendarNew)); 221 } 222 223 @SmallTest 224 public void testSyncableMigration() throws Exception { 225 final Account account = new Account("acc", "type"); 226 227 MockContentResolver mockResolver = new MockContentResolver(); 228 229 final TestContext testContext = new TestContext(mockResolver, getContext()); 230 231 byte[] accountsFileData = ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" 232 + "<accounts>\n" 233 + "<authority id=\"0\" account=\"acc\" authority=\"other1\" />\n" 234 + "<authority id=\"1\" account=\"acc\" type=\"type\" authority=\"other2\" />\n" 235 + "<authority id=\"2\" account=\"acc\" type=\"type\" syncable=\"false\"" 236 + " authority=\"other3\" />\n" 237 + "<authority id=\"3\" account=\"acc\" type=\"type\" syncable=\"true\"" 238 + " authority=\"other4\" />\n" 239 + "</accounts>\n").getBytes(); 240 241 File syncDir = new File(new File(testContext.getFilesDir(), "system"), "sync"); 242 syncDir.mkdirs(); 243 AtomicFile accountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml")); 244 FileOutputStream fos = accountInfoFile.startWrite(); 245 fos.write(accountsFileData); 246 accountInfoFile.finishWrite(fos); 247 248 SyncStorageEngine engine = SyncStorageEngine.newTestInstance(testContext); 249 250 assertEquals(-1, engine.getIsSyncable(account, 0, "other1")); 251 assertEquals(1, engine.getIsSyncable(account, 0, "other2")); 252 assertEquals(0, engine.getIsSyncable(account, 0, "other3")); 253 assertEquals(1, engine.getIsSyncable(account, 0, "other4")); 254 } 255 256 /** 257 * Verify that the API cannot cause a run-time reboot by passing in the empty string as an 258 * authority. The problem here is that 259 * {@link SyncStorageEngine#getOrCreateAuthorityLocked(account, provider)} would register 260 * an empty authority which causes a RTE in {@link SyncManager#scheduleReadyPeriodicSyncs()}. 261 * This is not strictly a SSE test, but it does depend on the SSE data structures. 262 */ 263 @SmallTest 264 public void testExpectedIllegalArguments() throws Exception { 265 try { 266 ContentResolver.setSyncAutomatically(account1, "", true); 267 fail("empty provider string should throw IllegalArgumentException"); 268 } catch (IllegalArgumentException expected) {} 269 270 try { 271 ContentResolver.addPeriodicSync(account1, "", Bundle.EMPTY, 84000L); 272 fail("empty provider string should throw IllegalArgumentException"); 273 } catch (IllegalArgumentException expected) {} 274 275 try { 276 ContentResolver.removePeriodicSync(account1, "", Bundle.EMPTY); 277 fail("empty provider string should throw IllegalArgumentException"); 278 } catch (IllegalArgumentException expected) {} 279 280 try { 281 ContentResolver.cancelSync(account1, ""); 282 fail("empty provider string should throw IllegalArgumentException"); 283 } catch (IllegalArgumentException expected) {} 284 285 try { 286 ContentResolver.setIsSyncable(account1, "", 0); 287 fail("empty provider string should throw IllegalArgumentException"); 288 } catch (IllegalArgumentException expected) {} 289 290 try { 291 ContentResolver.cancelSync(account1, ""); 292 fail("empty provider string should throw IllegalArgumentException"); 293 } catch (IllegalArgumentException expected) {} 294 295 try { 296 ContentResolver.requestSync(account1, "", Bundle.EMPTY); 297 fail("empty provider string should throw IllegalArgumentException"); 298 } catch (IllegalArgumentException expected) {} 299 300 try { 301 ContentResolver.getSyncStatus(account1, ""); 302 fail("empty provider string should throw IllegalArgumentException"); 303 } catch (IllegalArgumentException expected) {} 304 305 // Make sure we aren't blocking null account/provider for those functions that use it 306 // to specify ALL accounts/providers. 307 ContentResolver.requestSync(null, null, Bundle.EMPTY); 308 ContentResolver.cancelSync(null, null); 309 } 310 } 311 312 class TestContext extends ContextWrapper { 313 314 ContentResolver mResolver; 315 316 private final Context mRealContext; 317 318 public TestContext(ContentResolver resolver, Context realContext) { 319 super(new RenamingDelegatingContext(new MockContext(), realContext, "test.")); 320 mRealContext = realContext; 321 mResolver = resolver; 322 } 323 324 @Override 325 public Resources getResources() { 326 return mRealContext.getResources(); 327 } 328 329 @Override 330 public File getFilesDir() { 331 return mRealContext.getFilesDir(); 332 } 333 334 @Override 335 public void enforceCallingOrSelfPermission(String permission, String message) { 336 } 337 338 @Override 339 public void sendBroadcast(Intent intent) { 340 } 341 342 @Override 343 public ContentResolver getContentResolver() { 344 return mResolver; 345 } 346 } 347