blob: 48e85427b11cef82c34a1ffa8d445a3c60005145 [file] [log] [blame]
/*
* Copyright (C) 2017 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.exoplayer2.testutil;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.offline.Download;
import com.google.android.exoplayer2.offline.Download.State;
import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.util.Util;
import java.util.HashMap;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** A {@link DownloadManager.Listener} for testing. */
public final class TestDownloadManagerListener implements DownloadManager.Listener {
private static final int TIMEOUT_MS = 1000;
private static final int INITIALIZATION_TIMEOUT_MS = 10_000;
private static final int STATE_REMOVED = -1;
private final DownloadManager downloadManager;
private final DummyMainThread dummyMainThread;
private final HashMap<String, ArrayBlockingQueue<Integer>> downloadStates;
private final CountDownLatch initializedCondition;
private final int timeoutMs;
private @MonotonicNonNull CountDownLatch downloadFinishedCondition;
@Download.FailureReason private int failureReason;
public TestDownloadManagerListener(
DownloadManager downloadManager, DummyMainThread dummyMainThread) {
this(downloadManager, dummyMainThread, TIMEOUT_MS);
}
public TestDownloadManagerListener(
DownloadManager downloadManager, DummyMainThread dummyMainThread, int timeoutMs) {
this.downloadManager = downloadManager;
this.dummyMainThread = dummyMainThread;
this.timeoutMs = timeoutMs;
downloadStates = new HashMap<>();
initializedCondition = new CountDownLatch(1);
downloadManager.addListener(this);
}
@Nullable
public Integer pollStateChange(String taskId, long timeoutMs) throws InterruptedException {
return getStateQueue(taskId).poll(timeoutMs, TimeUnit.MILLISECONDS);
}
@Override
public void onInitialized(DownloadManager downloadManager) {
initializedCondition.countDown();
}
public void waitUntilInitialized() throws InterruptedException {
if (!downloadManager.isInitialized()) {
assertThat(initializedCondition.await(INITIALIZATION_TIMEOUT_MS, TimeUnit.MILLISECONDS))
.isTrue();
}
}
@Override
public void onDownloadChanged(DownloadManager downloadManager, Download download) {
if (download.state == Download.STATE_FAILED) {
failureReason = download.failureReason;
}
getStateQueue(download.request.id).add(download.state);
}
@Override
public void onDownloadRemoved(DownloadManager downloadManager, Download download) {
getStateQueue(download.request.id).add(STATE_REMOVED);
}
@Override
public synchronized void onIdle(DownloadManager downloadManager) {
if (downloadFinishedCondition != null) {
downloadFinishedCondition.countDown();
}
}
/**
* Blocks until all remove and download tasks are complete and throws an exception if there was an
* error.
*/
public void blockUntilTasksCompleteAndThrowAnyDownloadError() throws Throwable {
blockUntilTasksComplete();
if (failureReason != Download.FAILURE_REASON_NONE) {
throw new Exception("Failure reason: " + failureReason);
}
}
/** Blocks until all remove and download tasks are complete. Task errors are ignored. */
public void blockUntilTasksComplete() throws InterruptedException {
synchronized (this) {
downloadFinishedCondition = new CountDownLatch(1);
}
dummyMainThread.runOnMainThread(
() -> {
if (downloadManager.isIdle()) {
Util.castNonNull(downloadFinishedCondition).countDown();
}
});
assertThat(downloadFinishedCondition.await(timeoutMs, TimeUnit.MILLISECONDS)).isTrue();
}
private ArrayBlockingQueue<Integer> getStateQueue(String taskId) {
synchronized (downloadStates) {
@Nullable ArrayBlockingQueue<Integer> stateQueue = downloadStates.get(taskId);
if (stateQueue == null) {
stateQueue = new ArrayBlockingQueue<>(10);
downloadStates.put(taskId, stateQueue);
}
return stateQueue;
}
}
public void assertRemoved(String taskId, int timeoutMs) {
assertStateInternal(taskId, STATE_REMOVED, timeoutMs);
}
public void assertState(String taskId, @State int expectedState, int timeoutMs) {
assertStateInternal(taskId, expectedState, timeoutMs);
}
private void assertStateInternal(String taskId, int expectedState, int timeoutMs) {
while (true) {
@Nullable Integer state = null;
try {
state = pollStateChange(taskId, timeoutMs);
} catch (InterruptedException e) {
fail("Interrupted: " + e.getMessage());
}
if (state != null) {
if (expectedState == state) {
return;
}
} else {
fail("Didn't receive expected state: " + expectedState);
}
}
}
}