Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(408)

Side by Side Diff: components/cronet/android/test/javatests/src/org/chromium/net/TestDataProvider.java

Issue 849903002: [Cronet] Upload support for async APIs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Move delegate destructor to implementation file to avoid chromium style error Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698