/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ package org.mozilla.android.sync.test; import java.util.ArrayList; import java.util.concurrent.ExecutorService; import org.mozilla.android.sync.test.helpers.WBORepository; import org.mozilla.gecko.sync.Logger; import org.mozilla.gecko.sync.repositories.FetchFailedException; import org.mozilla.gecko.sync.repositories.InactiveSessionException; import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException; import org.mozilla.gecko.sync.repositories.NoStoreDelegateException; import org.mozilla.gecko.sync.repositories.StoreFailedException; import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate; import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate; import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate; import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate; import org.mozilla.gecko.sync.repositories.domain.Record; import android.content.Context; public class SynchronizerHelpers { public static final String FAIL_SENTINEL = "Fail"; /** * Store one at a time, failing if the guid contains FAIL_SENTINEL. */ public static class FailFetchWBORepository extends WBORepository { @Override public void createSession(RepositorySessionCreationDelegate delegate, Context context) { delegate.deferredCreationDelegate().onSessionCreated(new WBORepositorySession(this) { @Override public void fetchSince(long timestamp, final RepositorySessionFetchRecordsDelegate delegate) { super.fetchSince(timestamp, new RepositorySessionFetchRecordsDelegate() { @Override public void onFetchedRecord(Record record) { if (record.guid.contains(FAIL_SENTINEL)) { delegate.onFetchFailed(new FetchFailedException(), record); } else { delegate.onFetchedRecord(record); } } @Override public void onFetchFailed(Exception ex, Record record) { delegate.onFetchFailed(ex, record); } @Override public void onFetchCompleted(long fetchEnd) { delegate.onFetchCompleted(fetchEnd); } @Override public RepositorySessionFetchRecordsDelegate deferredFetchDelegate(ExecutorService executor) { return this; } }); } }); } } /** * Store one at a time, failing if the guid contains FAIL_SENTINEL. */ public static class SerialFailStoreWBORepository extends WBORepository { @Override public void createSession(RepositorySessionCreationDelegate delegate, Context context) { delegate.deferredCreationDelegate().onSessionCreated(new WBORepositorySession(this) { @Override public void store(final Record record) throws NoStoreDelegateException { if (delegate == null) { throw new NoStoreDelegateException(); } if (record.guid.contains(FAIL_SENTINEL)) { delegate.onRecordStoreFailed(new StoreFailedException(), record.guid); } else { super.store(record); } } }); } } /** * Store in batches, failing if any of the batch guids contains "Fail". * <p> * This will drop the final batch. */ public static class BatchFailStoreWBORepository extends WBORepository { public final int batchSize; public ArrayList<Record> batch = new ArrayList<Record>(); public boolean batchShouldFail = false; public class BatchFailStoreWBORepositorySession extends WBORepositorySession { public BatchFailStoreWBORepositorySession(WBORepository repository) { super(repository); } public void superStore(final Record record) throws NoStoreDelegateException { super.store(record); } @Override public void store(final Record record) throws NoStoreDelegateException { if (delegate == null) { throw new NoStoreDelegateException(); } synchronized (batch) { batch.add(record); if (record.guid.contains("Fail")) { batchShouldFail = true; } if (batch.size() >= batchSize) { flush(); } } } public void flush() { final ArrayList<Record> thisBatch = new ArrayList<Record>(batch); final boolean thisBatchShouldFail = batchShouldFail; batchShouldFail = false; batch.clear(); storeWorkQueue.execute(new Runnable() { @Override public void run() { Logger.trace("XXX", "Notifying about batch. Failure? " + thisBatchShouldFail); for (Record batchRecord : thisBatch) { if (thisBatchShouldFail) { delegate.onRecordStoreFailed(new StoreFailedException(), batchRecord.guid); } else { try { superStore(batchRecord); } catch (NoStoreDelegateException e) { delegate.onRecordStoreFailed(e, batchRecord.guid); } } } } }); } @Override public void storeDone() { synchronized (batch) { flush(); // Do this in a Runnable so that the timestamp is grabbed after any upload. final Runnable r = new Runnable() { @Override public void run() { synchronized (batch) { Logger.trace("XXX", "Calling storeDone."); storeDone(now()); } } }; storeWorkQueue.execute(r); } } } public BatchFailStoreWBORepository(int batchSize) { super(); this.batchSize = batchSize; } @Override public void createSession(RepositorySessionCreationDelegate delegate, Context context) { delegate.deferredCreationDelegate().onSessionCreated(new BatchFailStoreWBORepositorySession(this)); } } public static class TrackingWBORepository extends WBORepository { @Override public synchronized boolean shouldTrack() { return true; } } public static class BeginFailedException extends Exception { private static final long serialVersionUID = -2349459755976915096L; } public static class FinishFailedException extends Exception { private static final long serialVersionUID = -4644528423867070934L; } public static class BeginErrorWBORepository extends TrackingWBORepository { @Override public void createSession(RepositorySessionCreationDelegate delegate, Context context) { delegate.deferredCreationDelegate().onSessionCreated(new BeginErrorWBORepositorySession(this)); } public class BeginErrorWBORepositorySession extends WBORepositorySession { public BeginErrorWBORepositorySession(WBORepository repository) { super(repository); } @Override public void begin(RepositorySessionBeginDelegate delegate) throws InvalidSessionTransitionException { delegate.onBeginFailed(new BeginFailedException()); } } } public static class FinishErrorWBORepository extends TrackingWBORepository { @Override public void createSession(RepositorySessionCreationDelegate delegate, Context context) { delegate.deferredCreationDelegate().onSessionCreated(new FinishErrorWBORepositorySession(this)); } public class FinishErrorWBORepositorySession extends WBORepositorySession { public FinishErrorWBORepositorySession(WBORepository repository) { super(repository); } @Override public void finish(final RepositorySessionFinishDelegate delegate) throws InactiveSessionException { delegate.onFinishFailed(new FinishFailedException()); } } } }