summaryrefslogtreecommitdiff
path: root/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/IdlingResourceRegistry.java
diff options
context:
space:
mode:
Diffstat (limited to 'espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/IdlingResourceRegistry.java')
-rw-r--r--espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/IdlingResourceRegistry.java289
1 files changed, 0 insertions, 289 deletions
diff --git a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/IdlingResourceRegistry.java b/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/IdlingResourceRegistry.java
deleted file mode 100644
index e390f0f..0000000
--- a/espresso/espresso-lib/src/main/java/com/google/android/apps/common/testing/ui/espresso/base/IdlingResourceRegistry.java
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (C) 2014 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.google.android.apps.common.testing.ui.espresso.base;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
-import com.google.android.apps.common.testing.ui.espresso.IdlingPolicies;
-import com.google.android.apps.common.testing.ui.espresso.IdlingPolicy;
-import com.google.android.apps.common.testing.ui.espresso.IdlingResource;
-import com.google.android.apps.common.testing.ui.espresso.IdlingResource.ResourceCallback;
-import com.google.common.collect.Lists;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
-
-import java.util.BitSet;
-import java.util.List;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * Keeps track of user-registered {@link IdlingResource}s.
- */
-@Singleton
-public final class IdlingResourceRegistry {
- private static final String TAG = IdlingResourceRegistry.class.getSimpleName();
-
- private static final int DYNAMIC_RESOURCE_HAS_IDLED = 1;
- private static final int TIMEOUT_OCCURRED = 2;
- private static final int IDLE_WARNING_REACHED = 3;
- private static final int POSSIBLE_RACE_CONDITION_DETECTED = 4;
- private static final Object TIMEOUT_MESSAGE_TAG = new Object();
-
- private static final IdleNotificationCallback NO_OP_CALLBACK = new IdleNotificationCallback() {
-
- @Override
- public void allResourcesIdle() {}
-
- @Override
- public void resourcesStillBusyWarning(List<String> busys) {}
-
- @Override
- public void resourcesHaveTimedOut(List<String> busys) {}
- };
-
- // resources and idleState should only be accessed on main thread
- private final List<IdlingResource> resources = Lists.newArrayList();
- // idleState.get(i) == true indicates resources.get(i) is idle, false indicates it's busy
- private final BitSet idleState = new BitSet();
- private final Looper looper;
- private final Handler handler;
- private final Dispatcher dispatcher;
- private IdleNotificationCallback idleNotificationCallback = NO_OP_CALLBACK;
-
- @Inject
- public IdlingResourceRegistry(Looper looper) {
- this.looper = looper;
- this.dispatcher = new Dispatcher();
- this.handler = new Handler(looper, dispatcher);
- }
-
- /**
- * Registers the given resource.
- */
- public void register(final IdlingResource resource) {
- checkNotNull(resource);
- if (Looper.myLooper() != looper) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- register(resource);
- }
- });
- } else {
- for (IdlingResource oldResource : resources) {
- if (resource.getName().equals(oldResource.getName())) {
- // This does not throw an error to avoid leaving tests that register resource in test
- // setup in an undeterministic state (we cannot assume that everyone clears vm state
- // between each test run)
- Log.e(TAG, String.format("Attempted to register resource with same names:" +
- " %s. R1: %s R2: %s.\nDuplicate resource registration will be ignored.",
- resource.getName(), resource, oldResource));
- return;
- }
- }
- resources.add(resource);
- final int position = resources.size() - 1;
- registerToIdleCallback(resource, position);
- idleState.set(position, resource.isIdleNow());
- }
- }
-
- public void registerLooper(Looper looper, boolean considerWaitIdle) {
- checkNotNull(looper);
- checkArgument(Looper.getMainLooper() != looper, "Not intended for use with main looper!");
- register(new LooperIdlingResource(looper, considerWaitIdle));
- }
-
- private void registerToIdleCallback(IdlingResource resource, final int position) {
- resource.registerIdleTransitionCallback(new ResourceCallback() {
- @Override
- public void onTransitionToIdle() {
- Message m = handler.obtainMessage(DYNAMIC_RESOURCE_HAS_IDLED);
- m.arg1 = position;
- handler.sendMessage(m);
- }
- });
- }
-
- boolean allResourcesAreIdle() {
- checkState(Looper.myLooper() == looper);
- for (int i = idleState.nextSetBit(0); i >= 0 && i < resources.size();
- i = idleState.nextSetBit(i + 1)) {
- idleState.set(i, resources.get(i).isIdleNow());
- }
- return idleState.cardinality() == resources.size();
- }
-
- interface IdleNotificationCallback {
- public void allResourcesIdle();
-
- public void resourcesStillBusyWarning(List<String> busyResourceNames);
-
- public void resourcesHaveTimedOut(List<String> busyResourceNames);
- }
-
- void notifyWhenAllResourcesAreIdle(IdleNotificationCallback callback) {
- checkNotNull(callback);
- checkState(Looper.myLooper() == looper);
- checkState(idleNotificationCallback == NO_OP_CALLBACK, "Callback has already been registered.");
- if (allResourcesAreIdle()) {
- callback.allResourcesIdle();
- } else {
- idleNotificationCallback = callback;
- scheduleTimeoutMessages();
- }
- }
-
- void cancelIdleMonitor() {
- dispatcher.deregister();
- }
-
- private void scheduleTimeoutMessages() {
- IdlingPolicy warning = IdlingPolicies.getDynamicIdlingResourceWarningPolicy();
- Message timeoutWarning = handler.obtainMessage(IDLE_WARNING_REACHED, TIMEOUT_MESSAGE_TAG);
- handler.sendMessageDelayed(timeoutWarning, warning.getIdleTimeoutUnit().toMillis(
- warning.getIdleTimeout()));
- Message timeoutError = handler.obtainMessage(TIMEOUT_OCCURRED, TIMEOUT_MESSAGE_TAG);
- IdlingPolicy error = IdlingPolicies.getDynamicIdlingResourceErrorPolicy();
-
- handler.sendMessageDelayed(timeoutError, error.getIdleTimeoutUnit().toMillis(
- error.getIdleTimeout()));
- }
-
- private List<String> getBusyResources() {
- List<String> busyResourceNames = Lists.newArrayList();
- List<Integer> racyResources = Lists.newArrayList();
-
- for (int i = 0; i < resources.size(); i++) {
- IdlingResource resource = resources.get(i);
- if (!idleState.get(i)) {
- if (resource.isIdleNow()) {
- // We have not been notified of a BUSY -> IDLE transition, but the resource is telling us
- // its that its idle. Either it's a race condition or is this resource buggy.
- racyResources.add(i);
- } else {
- busyResourceNames.add(resource.getName());
- }
- }
- }
-
- if (!racyResources.isEmpty()) {
- Message raceBuster = handler.obtainMessage(POSSIBLE_RACE_CONDITION_DETECTED,
- TIMEOUT_MESSAGE_TAG);
- raceBuster.obj = racyResources;
- handler.sendMessage(raceBuster);
- return null;
- } else {
- return busyResourceNames;
- }
- }
-
-
- private class Dispatcher implements Handler.Callback {
- @Override
- public boolean handleMessage(Message m) {
- switch (m.what) {
- case DYNAMIC_RESOURCE_HAS_IDLED:
- handleResourceIdled(m);
- break;
- case IDLE_WARNING_REACHED:
- handleTimeoutWarning();
- break;
- case TIMEOUT_OCCURRED:
- handleTimeout();
- break;
- case POSSIBLE_RACE_CONDITION_DETECTED:
- handleRaceCondition(m);
- break;
- default:
- Log.w(TAG, "Unknown message type: " + m);
- return false;
- }
- return true;
- }
-
- private void handleResourceIdled(Message m) {
- idleState.set(m.arg1, true);
- if (idleState.cardinality() == resources.size()) {
- try {
- idleNotificationCallback.allResourcesIdle();
- } finally {
- deregister();
- }
- }
- }
-
- private void handleTimeoutWarning() {
- List<String> busyResources = getBusyResources();
- if (busyResources == null) {
- // null indicates that there is either a race or a programming error
- // a race detector message has been inserted into the q.
- // reinsert the idle_warning_reached message into the q directly after it
- // so we generate warnings if the system is still sane.
- handler.sendMessage(handler.obtainMessage(IDLE_WARNING_REACHED, TIMEOUT_MESSAGE_TAG));
- } else {
- IdlingPolicy warning = IdlingPolicies.getDynamicIdlingResourceWarningPolicy();
- idleNotificationCallback.resourcesStillBusyWarning(busyResources);
- handler.sendMessageDelayed(
- handler.obtainMessage(IDLE_WARNING_REACHED, TIMEOUT_MESSAGE_TAG),
- warning.getIdleTimeoutUnit().toMillis(warning.getIdleTimeout()));
- }
- }
-
- private void handleTimeout() {
- List<String> busyResources = getBusyResources();
- if (busyResources == null) {
- // detected a possible race... we've enqueued a race busting message
- // so either that'll resolve the race or kill the app because it's buggy.
- // if the race resolves, we need to timeout properly.
- handler.sendMessage(handler.obtainMessage(TIMEOUT_OCCURRED, TIMEOUT_MESSAGE_TAG));
- } else {
- try {
- idleNotificationCallback.resourcesHaveTimedOut(busyResources);
- } finally {
- deregister();
- }
- }
- }
-
- @SuppressWarnings("unchecked")
- private void handleRaceCondition(Message m) {
- for (Integer i : (List<Integer>) m.obj) {
- if (idleState.get(i)) {
- // it was a race... i is now idle, everything is fine...
- } else {
- throw new IllegalStateException(String.format(
- "Resource %s isIdleNow() is returning true, but a message indicating that the "
- + "resource has transitioned from busy to idle was never sent.",
- resources.get(i).getName()));
- }
- }
- }
-
- private void deregister() {
- handler.removeCallbacksAndMessages(TIMEOUT_MESSAGE_TAG);
- idleNotificationCallback = NO_OP_CALLBACK;
- }
- }
-}