From 09bfb912afb6936344429a486dc20fa2ce8e1827 Mon Sep 17 00:00:00 2001 From: Brian Attwell Date: Thu, 18 Dec 2014 20:11:17 -0800 Subject: Move TestLoaderManager into /tests. Unbundling. TestLoaderManager is injected into ContactDeletionInteraction for the sake of one (flakey) unit test class. It is breaking the Contacts build by using a hidden API. Move this into /tests and reference an abstract base class inside ContactDeletionInteraction. Bug: 18777272 Change-Id: Icffa0256b418a319347f1f58f0415341be9d8054 --- .../contacts/interactions/TestLoaderManager.java | 176 +++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 tests/src/com/android/contacts/interactions/TestLoaderManager.java (limited to 'tests') diff --git a/tests/src/com/android/contacts/interactions/TestLoaderManager.java b/tests/src/com/android/contacts/interactions/TestLoaderManager.java new file mode 100644 index 000000000..3e0db63ec --- /dev/null +++ b/tests/src/com/android/contacts/interactions/TestLoaderManager.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2010 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.contacts.interactions; + +import android.app.LoaderManager; +import android.content.AsyncTaskLoader; +import android.content.Loader; +import android.os.Bundle; +import android.util.Log; + +import com.google.common.annotations.VisibleForTesting; + +import junit.framework.Assert; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +/** + * This implementation of TestLoaderManagerBase uses hidden APIs and must therefore + * be kept outside of the main Contacts apk. + */ +public class TestLoaderManager extends TestLoaderManagerBase { + private static final String TAG = "TestLoaderManager"; + + private final HashSet mFinishedLoaders; + + private LoaderManager mDelegate; + + @VisibleForTesting + public TestLoaderManager() { + mFinishedLoaders = new HashSet(); + } + + /** + * Sets the object to which we delegate the actual work. + *

+ * It can not be set to null. Once set, it cannot be changed (but it allows setting it to the + * same value again). + */ + public void setDelegate(LoaderManager delegate) { + if (delegate == null || (mDelegate != null && mDelegate != delegate)) { + throw new IllegalArgumentException("TestLoaderManager cannot be shared"); + } + + mDelegate = delegate; + } + + public LoaderManager getDelegate() { + return mDelegate; + } + + public void reset() { + mFinishedLoaders.clear(); + } + + /** + * Waits for the specified loaders to complete loading. + *

+ * If one of the loaders has already completed since the last call to {@link #reset()}, it will + * not wait for it to complete again. + */ + @VisibleForTesting + public synchronized void waitForLoaders(int... loaderIds) { + List> loaders = new ArrayList>(loaderIds.length); + for (int loaderId : loaderIds) { + if (mFinishedLoaders.contains(loaderId)) { + // This loader has already completed since the last reset, do not wait for it. + continue; + } + + final AsyncTaskLoader loader = + (AsyncTaskLoader) mDelegate.getLoader(loaderId); + if (loader == null) { + Assert.fail("Loader does not exist: " + loaderId); + return; + } + + loaders.add(loader); + } + + waitForLoaders(loaders.toArray(new Loader[0])); + } + + /** + * Waits for the specified loaders to complete loading. + */ + public static void waitForLoaders(Loader... loaders) { + // We want to wait for each loader using a separate thread, so that we can + // simulate race conditions. + Thread[] waitThreads = new Thread[loaders.length]; + for (int i = 0; i < loaders.length; i++) { + final AsyncTaskLoader loader = (AsyncTaskLoader) loaders[i]; + waitThreads[i] = new Thread("LoaderWaitingThread" + i) { + @Override + public void run() { + try { + loader.waitForLoader(); + } catch (Throwable e) { + Log.e(TAG, "Exception while waiting for loader: " + loader.getId(), e); + Assert.fail("Exception while waiting for loader: " + loader.getId()); + } + } + }; + waitThreads[i].start(); + } + + // Now we wait for all these threads to finish + for (Thread thread : waitThreads) { + try { + thread.join(); + } catch (InterruptedException e) { + // Ignore + } + } + } + + @Override + public Loader initLoader(final int id, Bundle args, final LoaderCallbacks callback) { + return mDelegate.initLoader(id, args, new LoaderManager.LoaderCallbacks() { + @Override + public Loader onCreateLoader(int id, Bundle args) { + return callback.onCreateLoader(id, args); + } + + @Override + public void onLoadFinished(Loader loader, D data) { + callback.onLoadFinished(loader, data); + synchronized (this) { + mFinishedLoaders.add(id); + } + } + + @Override + public void onLoaderReset(Loader loader) { + callback.onLoaderReset(loader); + } + }); + } + + @Override + public Loader restartLoader(int id, Bundle args, LoaderCallbacks callback) { + return mDelegate.restartLoader(id, args, callback); + } + + @Override + public void destroyLoader(int id) { + mDelegate.destroyLoader(id); + } + + @Override + public Loader getLoader(int id) { + return mDelegate.getLoader(id); + } + + @Override + public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { + mDelegate.dump(prefix, fd, writer, args); + } +} -- cgit v1.2.3