Chromium Code Reviews| Index: components/cronet/android/test/javatests/src/org/chromium/cronet_test_apk/TestDrivenDataProvider.java |
| diff --git a/components/cronet/android/test/javatests/src/org/chromium/cronet_test_apk/TestDrivenDataProvider.java b/components/cronet/android/test/javatests/src/org/chromium/cronet_test_apk/TestDrivenDataProvider.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..bee219098e7b9fe6ede15f8f40b27d1557354815 |
| --- /dev/null |
| +++ b/components/cronet/android/test/javatests/src/org/chromium/cronet_test_apk/TestDrivenDataProvider.java |
| @@ -0,0 +1,193 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +package org.chromium.cronet_test_apk; |
| + |
| +import android.os.ConditionVariable; |
| + |
| +import org.chromium.net.UploadDataProvider; |
| +import org.chromium.net.UploadDataSink; |
| + |
| +import java.nio.ByteBuffer; |
| +import java.util.List; |
| +import java.util.concurrent.Executor; |
| + |
| +/** |
| + * An UploadDataProvider that allows tests to invoke {@code onReadSucceeded} |
| + * and {@code onRewindSucceeded} on the UploadDataSink directly. |
| + */ |
| +class TestDrivenDataProvider implements UploadDataProvider { |
| + private final Executor mExecutor; |
| + private final List<byte[]> mReads; |
| + private final ConditionVariable mWaitForReadRequest = |
| + new ConditionVariable(); |
| + private final ConditionVariable mWaitForRewindRequest = |
| + new ConditionVariable(); |
| + // Lock used to synchronize access to mReadPending and mRewindPending. |
| + private final Object mLock = new Object(); |
| + |
| + private int mNumRewindCalls = 0; |
| + private int mNumReadCalls = 0; |
| + private int mNextRead = 0; |
| + |
| + // Only accessible when holding mLock. |
| + private boolean mReadPending = false; |
| + private boolean mRewindPending = false; |
| + |
| + /** |
| + * Constructor. |
| + * @param Executor executor. Executor to run callbacks of UploadDataSink. |
| + * @param List<byte[]> reads. Results to be returned by successful read |
| + * requests. Returned bytes must all fit within the read buffer |
| + * provided by Cronet. After a rewind, if there is one, all reads |
| + * will be repeated. |
| + */ |
| + TestDrivenDataProvider(Executor executor, List<byte[]> reads) { |
| + mExecutor = executor; |
| + mReads = reads; |
| + } |
| + |
| + @Override |
| + // Called by UploadDataSink on the main thread. |
| + public long getLength() { |
| + long length = 0; |
| + for (byte[] read : mReads) { |
| + length += read.length; |
| + } |
| + return length; |
| + } |
| + |
| + @Override |
| + // Called by UploadDataSink on the executor thread. |
| + public void read(final UploadDataSink uploadDataSink, |
| + final ByteBuffer byteBuffer) { |
| + synchronized (mLock) { |
| + int currentReadCall = mNumReadCalls; |
| + ++mNumReadCalls; |
| + assertIdle(); |
| + |
| + mReadPending = true; |
| + if (mNextRead != mReads.size()) { |
| + if (byteBuffer.capacity() < mReads.get(mNextRead).length) { |
| + throw new IllegalStateException("Read buffer smaller than expected"); |
| + } |
| + byteBuffer.put(mReads.get(mNextRead)); |
| + byteBuffer.flip(); |
| + ++mNextRead; |
| + } else { |
| + throw new IllegalStateException("Too many reads: " + mNextRead); |
| + } |
| + mWaitForReadRequest.open(); |
| + } |
| + } |
| + |
| + @Override |
| + // Called by UploadDataSink on the executor thread. |
| + public void rewind(final UploadDataSink uploadDataSink) { |
| + synchronized (mLock) { |
| + ++mNumRewindCalls; |
| + assertIdle(); |
| + |
| + if (mNextRead == 0) { |
| + // Should never try and rewind when rewinding does nothing. |
| + throw new IllegalStateException( |
| + "Unexpected rewind when already at beginning"); |
| + } |
| + mRewindPending = true; |
| + mNextRead = 0; |
| + mWaitForRewindRequest.open(); |
| + } |
| + } |
| + |
| + // Called by test fixture on the main thread. |
| + public void onReadSucceeded(final UploadDataSink uploadDataSink) { |
| + Runnable completeRunnable = new Runnable() { |
| + @Override |
| + public void run() { |
| + synchronized (mLock) { |
| + if (!mReadPending) { |
| + throw new IllegalStateException("No read pending."); |
| + } |
| + mReadPending = false; |
| + uploadDataSink.onReadSucceeded(false); |
| + } |
| + } |
| + }; |
| + mExecutor.execute(completeRunnable); |
| + } |
| + |
| + |
| + // Called by test fixture on the main thread. |
| + public void onRewindSucceeded(final UploadDataSink uploadDataSink) { |
| + Runnable completeRunnable = new Runnable() { |
| + @Override |
| + public void run() { |
| + synchronized (mLock) { |
| + if (!mRewindPending) { |
| + throw new IllegalStateException("No rewind pending."); |
| + } |
| + mRewindPending = false; |
| + uploadDataSink.onRewindSucceeded(); |
| + } |
| + } |
| + }; |
| + mExecutor.execute(completeRunnable); |
| + } |
| + |
| + // Called by test fixture on the main thread. |
| + public int getNumReadCalls() { |
| + return mNumReadCalls; |
|
mmenke
2015/02/02 18:26:12
Suggest a "synchronized (mLock)" here and in the n
xunjieli
2015/02/02 19:12:25
Done.
|
| + } |
| + |
| + // Called by test fixture on the main thread. |
| + public int getNumRewindCalls() { |
| + return mNumRewindCalls; |
| + } |
| + |
| + // Called by test fixture on the main thread. |
| + public void waitForReadRequest() { |
| + mWaitForReadRequest.block(); |
| + } |
| + |
| + // Called by test fixture on the main thread. |
| + public void resetWaitForReadRequest() { |
| + mWaitForReadRequest.close(); |
| + } |
| + |
| + // Called by test fixture on the main thread. |
| + public void waitForRewindRequest() { |
| + mWaitForRewindRequest.block(); |
| + } |
| + |
| + // Called by test fixture on the main thread. |
| + public void assertReadNotPending() { |
| + synchronized (mLock) { |
| + if (mReadPending) { |
| + throw new IllegalStateException("Read is pending."); |
| + } |
| + } |
| + } |
| + |
| + // Called by test fixture on the main thread. |
| + public void assertRewindNotPending() { |
| + synchronized (mLock) { |
| + if (mRewindPending) { |
| + throw new IllegalStateException("Rewind is pending."); |
| + } |
| + } |
| + } |
| + |
| + /** |
| + * Helper method to ensure no read or rewind is in progress. Caller should |
| + * acquire mLock. |
| + */ |
| + private void assertIdle() { |
|
mmenke
2015/02/02 18:26:12
Think this can now just be:
assertRewindNotPendin
xunjieli
2015/02/02 19:12:25
Done.
|
| + if (mReadPending) { |
| + throw new IllegalStateException("Unexpected operation during read"); |
| + } |
| + if (mRewindPending) { |
| + throw new IllegalStateException("Unexpected operation during rewind"); |
| + } |
| + } |
| +} |