| OLD | NEW | 
| (Empty) |  | 
 |    1 // Copyright 2015 The Chromium Authors. All rights reserved. | 
 |    2 // Use of this source code is governed by a BSD-style license that can be | 
 |    3 // found in the LICENSE file. | 
 |    4  | 
 |    5 package org.chromium.net; | 
 |    6  | 
 |    7 import java.io.IOException; | 
 |    8 import java.nio.ByteBuffer; | 
 |    9 import java.util.ArrayList; | 
 |   10 import java.util.concurrent.Executor; | 
 |   11  | 
 |   12 /** | 
 |   13  * An UploadDataProvider implementation used in tests. | 
 |   14  */ | 
 |   15 class TestUploadDataProvider implements UploadDataProvider { | 
 |   16     // Indicates whether all success callbacks are synchronous or asynchronous. | 
 |   17     // Doesn't apply to errors. | 
 |   18     enum SuccessCallbackMode { | 
 |   19         SYNC, | 
 |   20         ASYNC | 
 |   21     }; | 
 |   22  | 
 |   23     // Indicates whether failures should throw exceptions, invoke callbacks | 
 |   24     // synchronously, or invoke callback asynchronously. | 
 |   25     enum FailMode { | 
 |   26         NONE, | 
 |   27         THROWN, | 
 |   28         CALLBACK_SYNC, | 
 |   29         CALLBACK_ASYNC | 
 |   30     }; | 
 |   31  | 
 |   32     private ArrayList<byte[]> mReads = new ArrayList<byte[]>(); | 
 |   33     private final SuccessCallbackMode mSuccessCallbackMode; | 
 |   34     private final Executor mExecutor; | 
 |   35  | 
 |   36     private boolean mChunked = false; | 
 |   37  | 
 |   38     // Index of read to fail on. | 
 |   39     private int mReadFailIndex = -1; | 
 |   40     // Indicates how to fail on a read. | 
 |   41     private FailMode mReadFailMode = FailMode.NONE; | 
 |   42  | 
 |   43     private FailMode mRewindFailMode = FailMode.NONE; | 
 |   44  | 
 |   45     private int mNumReadCalls = 0; | 
 |   46     private int mNumRewindCalls = 0; | 
 |   47  | 
 |   48     private int mNextRead = 0; | 
 |   49     private boolean mStarted = false; | 
 |   50     private boolean mReadPending = false; | 
 |   51     private boolean mRewindPending = false; | 
 |   52     // Used to ensure there are no read/rewind requests after a failure. | 
 |   53     private boolean mFailed = false; | 
 |   54  | 
 |   55     TestUploadDataProvider(SuccessCallbackMode successCallbackMode, | 
 |   56             Executor executor) { | 
 |   57         mSuccessCallbackMode = successCallbackMode; | 
 |   58         mExecutor = executor; | 
 |   59     } | 
 |   60  | 
 |   61     // Adds the result to be returned by a successful read request.  The | 
 |   62     // returned bytes must all fit within the read buffer provided by Cronet. | 
 |   63     // After a rewind, if there is one, all reads will be repeated. | 
 |   64     public void addRead(byte[] read) { | 
 |   65         if (mStarted) { | 
 |   66             throw new IllegalStateException("Adding bytes after read"); | 
 |   67         } | 
 |   68         mReads.add(read); | 
 |   69     } | 
 |   70  | 
 |   71     public void setReadFailure(int readFailIndex, FailMode readFailMode) { | 
 |   72         mReadFailIndex = readFailIndex; | 
 |   73         mReadFailMode = readFailMode; | 
 |   74     } | 
 |   75  | 
 |   76     public void setRewindFailure(FailMode rewindFailMode) { | 
 |   77         mRewindFailMode = rewindFailMode; | 
 |   78     } | 
 |   79  | 
 |   80     public void setChunked(boolean chunked) { | 
 |   81         mChunked = chunked; | 
 |   82     } | 
 |   83  | 
 |   84     public int getNumReadCalls() { | 
 |   85         return mNumReadCalls; | 
 |   86     } | 
 |   87  | 
 |   88     public int getNumRewindCalls() { | 
 |   89         return mNumRewindCalls; | 
 |   90     } | 
 |   91  | 
 |   92     /** | 
 |   93      * Returns the cumulative length of all data added by calls to addRead. | 
 |   94      */ | 
 |   95     @Override | 
 |   96     public long getLength() { | 
 |   97         if (mChunked) { | 
 |   98             return -1; | 
 |   99         } | 
 |  100         long length = 0; | 
 |  101         for (byte[] read : mReads) { | 
 |  102             length += read.length; | 
 |  103         } | 
 |  104         return length; | 
 |  105     } | 
 |  106  | 
 |  107     @Override | 
 |  108     public void read(final UploadDataSink uploadDataSink, | 
 |  109             final ByteBuffer byteBuffer) throws IOException { | 
 |  110         int currentReadCall = mNumReadCalls; | 
 |  111         ++mNumReadCalls; | 
 |  112         assertIdle(); | 
 |  113  | 
 |  114         if (maybeFailRead(currentReadCall, uploadDataSink)) { | 
 |  115             mFailed = true; | 
 |  116             return; | 
 |  117         } | 
 |  118  | 
 |  119         mReadPending = true; | 
 |  120         mStarted = true; | 
 |  121  | 
 |  122         final boolean finalChunk = (mChunked && mNextRead == mReads.size()); | 
 |  123         if (mNextRead < mReads.size()) { | 
 |  124             if ((byteBuffer.limit() - byteBuffer.position()) | 
 |  125                     < mReads.get(mNextRead).length) { | 
 |  126                 throw new IllegalStateException( | 
 |  127                         "Read buffer smaller than expected."); | 
 |  128             } | 
 |  129             byteBuffer.put(mReads.get(mNextRead)); | 
 |  130             ++mNextRead; | 
 |  131         } else if (!finalChunk) { | 
 |  132             throw new IllegalStateException( | 
 |  133                     "Too many reads: " + mNextRead); | 
 |  134         } | 
 |  135  | 
 |  136         Runnable completeRunnable = new Runnable() { | 
 |  137             @Override | 
 |  138             public void run() { | 
 |  139                 mReadPending = false; | 
 |  140                 uploadDataSink.onReadSucceeded(finalChunk); | 
 |  141             } | 
 |  142         }; | 
 |  143         if (mSuccessCallbackMode == SuccessCallbackMode.SYNC) { | 
 |  144             completeRunnable.run(); | 
 |  145         } else { | 
 |  146             mExecutor.execute(completeRunnable); | 
 |  147         } | 
 |  148     } | 
 |  149  | 
 |  150     public void rewind(final UploadDataSink uploadDataSink) throws IOException { | 
 |  151         ++mNumRewindCalls; | 
 |  152         assertIdle(); | 
 |  153  | 
 |  154         if (maybeFailRewind(uploadDataSink)) { | 
 |  155             mFailed = true; | 
 |  156             return; | 
 |  157         } | 
 |  158  | 
 |  159         if (mNextRead == 0) { | 
 |  160             // Should never try and rewind when rewinding does nothing. | 
 |  161             throw new IllegalStateException( | 
 |  162                     "Unexpected rewind when already at beginning"); | 
 |  163         } | 
 |  164  | 
 |  165         mRewindPending = true; | 
 |  166         mNextRead = 0; | 
 |  167  | 
 |  168         Runnable completeRunnable = new Runnable() { | 
 |  169             @Override | 
 |  170             public void run() { | 
 |  171                 mRewindPending = false; | 
 |  172                 uploadDataSink.onRewindSucceeded(); | 
 |  173             } | 
 |  174         }; | 
 |  175         if (mSuccessCallbackMode == SuccessCallbackMode.SYNC) { | 
 |  176             completeRunnable.run(); | 
 |  177         } else { | 
 |  178             mExecutor.execute(completeRunnable); | 
 |  179         } | 
 |  180     } | 
 |  181  | 
 |  182     private void assertIdle() { | 
 |  183         if (mReadPending) { | 
 |  184             throw new IllegalStateException("Unexpected operation during read"); | 
 |  185         } | 
 |  186         if (mRewindPending) { | 
 |  187             throw new IllegalStateException( | 
 |  188                     "Unexpected operation during rewind"); | 
 |  189         } | 
 |  190         if (mFailed) { | 
 |  191             throw new IllegalStateException( | 
 |  192                     "Unexpected operation after failure"); | 
 |  193         } | 
 |  194     } | 
 |  195  | 
 |  196     private boolean maybeFailRead(int readIndex, | 
 |  197             final UploadDataSink uploadDataSink) { | 
 |  198         if (readIndex != mReadFailIndex) | 
 |  199             return false; | 
 |  200  | 
 |  201         switch (mReadFailMode) { | 
 |  202             case THROWN: | 
 |  203                 throw new IllegalStateException("Thrown read failure"); | 
 |  204             case CALLBACK_SYNC: | 
 |  205                 uploadDataSink.onReadError( | 
 |  206                         new IllegalStateException("Sync read failure")); | 
 |  207                 return true; | 
 |  208             case CALLBACK_ASYNC: | 
 |  209                 Runnable errorRunnable = new Runnable() { | 
 |  210                     @Override | 
 |  211                     public void run() { | 
 |  212                         uploadDataSink.onReadError( | 
 |  213                                 new IllegalStateException("Async read failure"))
     ; | 
 |  214                     } | 
 |  215                 }; | 
 |  216                 mExecutor.execute(errorRunnable); | 
 |  217                 return true; | 
 |  218             default: | 
 |  219                 return false; | 
 |  220         } | 
 |  221     } | 
 |  222  | 
 |  223     private boolean maybeFailRewind(final UploadDataSink uploadDataSink) { | 
 |  224         switch (mRewindFailMode) { | 
 |  225             case THROWN: | 
 |  226                 throw new IllegalStateException("Thrown rewind failure"); | 
 |  227             case CALLBACK_SYNC: | 
 |  228                 uploadDataSink.onRewindError( | 
 |  229                         new IllegalStateException("Sync rewind failure")); | 
 |  230                 return true; | 
 |  231             case CALLBACK_ASYNC: | 
 |  232                 Runnable errorRunnable = new Runnable() { | 
 |  233                     @Override | 
 |  234                     public void run() { | 
 |  235                         uploadDataSink.onRewindError(new IllegalStateException( | 
 |  236                                 "Async rewind failure")); | 
 |  237                     } | 
 |  238                 }; | 
 |  239                 mExecutor.execute(errorRunnable); | 
 |  240                 return true; | 
 |  241             default: | 
 |  242                 return false; | 
 |  243         } | 
 |  244     } | 
 |  245 } | 
| OLD | NEW |