mobile/android/tests/background/junit3/src/sync/TestStoreTracking.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* Any copyright is dedicated to the Public Domain.
     2    http://creativecommons.org/publicdomain/zero/1.0/ */
     4 package org.mozilla.gecko.background.sync;
     6 import java.util.concurrent.atomic.AtomicBoolean;
     7 import java.util.concurrent.atomic.AtomicLong;
     9 import junit.framework.AssertionFailedError;
    11 import org.mozilla.gecko.background.common.log.Logger;
    12 import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
    13 import org.mozilla.gecko.background.sync.helpers.SimpleSuccessBeginDelegate;
    14 import org.mozilla.gecko.background.sync.helpers.SimpleSuccessCreationDelegate;
    15 import org.mozilla.gecko.background.sync.helpers.SimpleSuccessFetchDelegate;
    16 import org.mozilla.gecko.background.sync.helpers.SimpleSuccessFinishDelegate;
    17 import org.mozilla.gecko.background.sync.helpers.SimpleSuccessStoreDelegate;
    18 import org.mozilla.gecko.background.testhelpers.WBORepository;
    19 import org.mozilla.gecko.sync.CryptoRecord;
    20 import org.mozilla.gecko.sync.ExtendedJSONObject;
    21 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
    22 import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
    23 import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
    24 import org.mozilla.gecko.sync.repositories.RepositorySession;
    25 import org.mozilla.gecko.sync.repositories.RepositorySessionBundle;
    26 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
    27 import org.mozilla.gecko.sync.repositories.domain.BookmarkRecord;
    28 import org.mozilla.gecko.sync.repositories.domain.Record;
    29 import org.mozilla.gecko.sync.synchronizer.Synchronizer;
    30 import org.mozilla.gecko.sync.synchronizer.SynchronizerDelegate;
    32 import android.content.Context;
    34 public class TestStoreTracking extends AndroidSyncTestCase {
    35   public void assertEq(Object expected, Object actual) {
    36     try {
    37       assertEquals(expected, actual);
    38     } catch (AssertionFailedError e) {
    39       performNotify(e);
    40     }
    41   }
    43   public class TrackingWBORepository extends WBORepository {
    44     @Override
    45     public synchronized boolean shouldTrack() {
    46       return true;
    47     }
    48   }
    50   public void doTestStoreRetrieveByGUID(final WBORepository repository,
    51                                         final RepositorySession session,
    52                                         final String expectedGUID,
    53                                         final Record record) {
    55     final SimpleSuccessStoreDelegate storeDelegate = new SimpleSuccessStoreDelegate() {
    57       @Override
    58       public void onRecordStoreSucceeded(String guid) {
    59         Logger.debug(getName(), "Stored " + guid);
    60         assertEq(expectedGUID, guid);
    61       }
    63       @Override
    64       public void onStoreCompleted(long storeEnd) {
    65         Logger.debug(getName(), "Store completed at " + storeEnd + ".");
    66         try {
    67           session.fetch(new String[] { expectedGUID }, new SimpleSuccessFetchDelegate() {
    68             @Override
    69             public void onFetchedRecord(Record record) {
    70               Logger.debug(getName(), "Hurrah! Fetched record " + record.guid);
    71               assertEq(expectedGUID, record.guid);
    72             }
    74             @Override
    75             public void onFetchCompleted(final long fetchEnd) {
    76               Logger.debug(getName(), "Fetch completed at " + fetchEnd + ".");
    78               // But fetching by time returns nothing.
    79               session.fetchSince(0, new SimpleSuccessFetchDelegate() {
    80                 private AtomicBoolean fetched = new AtomicBoolean(false);
    82                 @Override
    83                 public void onFetchedRecord(Record record) {
    84                   Logger.debug(getName(), "Fetched record " + record.guid);
    85                   fetched.set(true);
    86                   performNotify(new AssertionFailedError("Should have fetched no record!"));
    87                 }
    89                 @Override
    90                 public void onFetchCompleted(final long fetchEnd) {
    91                   if (fetched.get()) {
    92                     Logger.debug(getName(), "Not finishing session: record retrieved.");
    93                     return;
    94                   }
    95                   try {
    96                     session.finish(new SimpleSuccessFinishDelegate() {
    97                       @Override
    98                       public void onFinishSucceeded(RepositorySession session,
    99                                                     RepositorySessionBundle bundle) {
   100                         performNotify();
   101                       }
   102                     });
   103                   } catch (InactiveSessionException e) {
   104                     performNotify(e);
   105                   }
   106                 }
   107               });
   108             }
   109           });
   110         } catch (InactiveSessionException e) {
   111           performNotify(e);
   112         }
   113       }
   114     };
   116     session.setStoreDelegate(storeDelegate);
   117     try {
   118       Logger.debug(getName(), "Storing...");
   119       session.store(record);
   120       session.storeDone();
   121     } catch (NoStoreDelegateException e) {
   122       // Should not happen.
   123     }
   124   }
   126   private void doTestNewSessionRetrieveByTime(final WBORepository repository,
   127                                               final String expectedGUID) {
   128     final SimpleSuccessCreationDelegate createDelegate = new SimpleSuccessCreationDelegate() {
   129       @Override
   130       public void onSessionCreated(final RepositorySession session) {
   131         Logger.debug(getName(), "Session created.");
   132         try {
   133           session.begin(new SimpleSuccessBeginDelegate() {
   134             @Override
   135             public void onBeginSucceeded(final RepositorySession session) {
   136               // Now we get a result.
   137               session.fetchSince(0, new SimpleSuccessFetchDelegate() {
   139                 @Override
   140                 public void onFetchedRecord(Record record) {
   141                   assertEq(expectedGUID, record.guid);
   142                 }
   144                 @Override
   145                 public void onFetchCompleted(long end) {
   146                   try {
   147                     session.finish(new SimpleSuccessFinishDelegate() {
   148                       @Override
   149                       public void onFinishSucceeded(RepositorySession session,
   150                                                     RepositorySessionBundle bundle) {
   151                         // Hooray!
   152                         performNotify();
   153                       }
   154                     });
   155                   } catch (InactiveSessionException e) {
   156                     performNotify(e);
   157                   }
   158                 }
   159               });
   160             }
   161           });
   162         } catch (InvalidSessionTransitionException e) {
   163           performNotify(e);
   164         }
   165       }
   166     };
   167     Runnable create = new Runnable() {
   168       @Override
   169       public void run() {
   170         repository.createSession(createDelegate, getApplicationContext());
   171       }
   172     };
   174     performWait(create);
   175   }
   177   /**
   178    * Store a record in one session. Verify that fetching by GUID returns
   179    * the record. Verify that fetching by timestamp fails to return records.
   180    * Start a new session. Verify that fetching by timestamp returns the
   181    * stored record.
   182    *
   183    * Invokes doTestStoreRetrieveByGUID, doTestNewSessionRetrieveByTime.
   184    */
   185   public void testStoreRetrieveByGUID() {
   186     Logger.debug(getName(), "Started.");
   187     final WBORepository r = new TrackingWBORepository();
   188     final long now = System.currentTimeMillis();
   189     final String expectedGUID = "abcdefghijkl";
   190     final Record record = new BookmarkRecord(expectedGUID, "bookmarks", now , false);
   192     final RepositorySessionCreationDelegate createDelegate = new SimpleSuccessCreationDelegate() {
   193       @Override
   194       public void onSessionCreated(RepositorySession session) {
   195         Logger.debug(getName(), "Session created: " + session);
   196         try {
   197           session.begin(new SimpleSuccessBeginDelegate() {
   198             @Override
   199             public void onBeginSucceeded(final RepositorySession session) {
   200               doTestStoreRetrieveByGUID(r, session, expectedGUID, record);
   201             }
   202           });
   203         } catch (InvalidSessionTransitionException e) {
   204           performNotify(e);
   205         }
   206       }
   207     };
   209     final Context applicationContext = getApplicationContext();
   211     // This has to happen on a new thread so that we
   212     // can wait for it!
   213     Runnable create = onThreadRunnable(new Runnable() {
   214       @Override
   215       public void run() {
   216         r.createSession(createDelegate, applicationContext);
   217       }
   218     });
   220     Runnable retrieve = onThreadRunnable(new Runnable() {
   221       @Override
   222       public void run() {
   223         doTestNewSessionRetrieveByTime(r, expectedGUID);
   224         performNotify();
   225       }
   226     });
   228     performWait(create);
   229     performWait(retrieve);
   230   }
   232   private Runnable onThreadRunnable(final Runnable r) {
   233     return new Runnable() {
   234       @Override
   235       public void run() {
   236         new Thread(r).start();
   237       }
   238     };
   239   }
   242   public class CountingWBORepository extends TrackingWBORepository {
   243     public AtomicLong counter = new AtomicLong(0L);
   244     public class CountingWBORepositorySession extends WBORepositorySession {
   245       private static final String LOG_TAG = "CountingRepoSession";
   247       public CountingWBORepositorySession(WBORepository repository) {
   248         super(repository);
   249       }
   251       @Override
   252       public void store(final Record record) throws NoStoreDelegateException {
   253         Logger.debug(LOG_TAG, "Counter now " + counter.incrementAndGet());
   254         super.store(record);
   255       }
   256     }
   258     @Override
   259     public void createSession(RepositorySessionCreationDelegate delegate,
   260                               Context context) {
   261       delegate.deferredCreationDelegate().onSessionCreated(new CountingWBORepositorySession(this));
   262     }
   263   }
   265   public class TestRecord extends Record {
   266     public TestRecord(String guid, String collection, long lastModified,
   267                       boolean deleted) {
   268       super(guid, collection, lastModified, deleted);
   269     }
   271     @Override
   272     public void initFromEnvelope(CryptoRecord payload) {
   273       return;
   274     }
   276     @Override
   277     public CryptoRecord getEnvelope() {
   278       return null;
   279     }
   281     @Override
   282     protected void populatePayload(ExtendedJSONObject payload) {
   283     }
   285     @Override
   286     protected void initFromPayload(ExtendedJSONObject payload) {
   287     }
   289     @Override
   290     public Record copyWithIDs(String guid, long androidID) {
   291       return new TestRecord(guid, this.collection, this.lastModified, this.deleted);
   292     }
   293   }
   295   /**
   296    * Create two repositories, syncing from one to the other. Ensure
   297    * that records stored from one aren't re-uploaded.
   298    */
   299   public void testStoreBetweenRepositories() {
   300     final CountingWBORepository repoA = new CountingWBORepository();    // "Remote". First source.
   301     final CountingWBORepository repoB = new CountingWBORepository();    // "Local". First sink.
   302     long now = System.currentTimeMillis();
   304     TestRecord recordA1 = new TestRecord("aacdefghiaaa", "coll", now - 30, false);
   305     TestRecord recordA2 = new TestRecord("aacdefghibbb", "coll", now - 20, false);
   306     TestRecord recordB1 = new TestRecord("aacdefghiaaa", "coll", now - 10, false);
   307     TestRecord recordB2 = new TestRecord("aacdefghibbb", "coll", now - 40, false);
   309     TestRecord recordA3 = new TestRecord("nncdefghibbb", "coll", now, false);
   310     TestRecord recordB3 = new TestRecord("nncdefghiaaa", "coll", now, false);
   312     // A1 and B1 are the same, but B's version is newer. We expect A1 to be downloaded
   313     // and B1 to be uploaded.
   314     // A2 and B2 are the same, but A's version is newer. We expect A2 to be downloaded
   315     // and B2 to not be uploaded.
   316     // Both A3 and B3 are new. We expect them to go in each direction.
   317     // Expected counts, then:
   318     // Repo A: B1 + B3
   319     // Repo B: A1 + A2 + A3
   320     repoB.wbos.put(recordB1.guid, recordB1);
   321     repoB.wbos.put(recordB2.guid, recordB2);
   322     repoB.wbos.put(recordB3.guid, recordB3);
   323     repoA.wbos.put(recordA1.guid, recordA1);
   324     repoA.wbos.put(recordA2.guid, recordA2);
   325     repoA.wbos.put(recordA3.guid, recordA3);
   327     final Synchronizer s = new Synchronizer();
   328     s.repositoryA = repoA;
   329     s.repositoryB = repoB;
   331     Runnable r = new Runnable() {
   332       @Override
   333       public void run() {
   334         s.synchronize(getApplicationContext(), new SynchronizerDelegate() {
   336           @Override
   337           public void onSynchronized(Synchronizer synchronizer) {
   338             long countA = repoA.counter.get();
   339             long countB = repoB.counter.get();
   340             Logger.debug(getName(), "Counts: " + countA + ", " + countB);
   341             assertEq(2L, countA);
   342             assertEq(3L, countB);
   344             // Testing for store timestamp 'hack'.
   345             // We fetched from A first, and so its bundle timestamp will be the last
   346             // stored time. We fetched from B second, so its bundle timestamp will be
   347             // the last fetched time.
   348             final long timestampA = synchronizer.bundleA.getTimestamp();
   349             final long timestampB = synchronizer.bundleB.getTimestamp();
   350             Logger.debug(getName(), "Repo A timestamp: " + timestampA);
   351             Logger.debug(getName(), "Repo B timestamp: " + timestampB);
   352             Logger.debug(getName(), "Repo A fetch done: " + repoA.stats.fetchCompleted);
   353             Logger.debug(getName(), "Repo A store done: " + repoA.stats.storeCompleted);
   354             Logger.debug(getName(), "Repo B fetch done: " + repoB.stats.fetchCompleted);
   355             Logger.debug(getName(), "Repo B store done: " + repoB.stats.storeCompleted);
   357             assertTrue(timestampB <= timestampA);
   358             assertTrue(repoA.stats.fetchCompleted <= timestampA);
   359             assertTrue(repoA.stats.storeCompleted >= repoA.stats.fetchCompleted);
   360             assertEquals(repoA.stats.storeCompleted, timestampA);
   361             assertEquals(repoB.stats.fetchCompleted, timestampB);
   362             performNotify();
   363           }
   365           @Override
   366           public void onSynchronizeFailed(Synchronizer synchronizer,
   367                                           Exception lastException, String reason) {
   368             Logger.debug(getName(), "Failed.");
   369             performNotify(new AssertionFailedError("Should not fail."));
   370           }
   371         });
   372       }
   373     };
   375     performWait(onThreadRunnable(r));
   376   }
   377 }

mercurial