Skip to content
This repository was archived by the owner on Oct 2, 2024. It is now read-only.

Commit f596fa8

Browse files
authored
chunk upload fix#108 (#111)
* chunk upload fix#108 * add Stateful interface * fix failed UTs
1 parent c00dc12 commit f596fa8

File tree

13 files changed

+1007
-57
lines changed

13 files changed

+1007
-57
lines changed

onedrivesdk/src/androidTest/java/com/onedrive/sdk/http/DefaultHttpProviderTests.java

Lines changed: 114 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,17 @@
2323
package com.onedrive.sdk.http;
2424

2525
import com.onedrive.sdk.concurrency.AsyncMonitorLocation;
26+
import com.onedrive.sdk.concurrency.AsyncMonitorResponseHandler;
27+
import com.onedrive.sdk.concurrency.ChunkedUploadResponseHandler;
2628
import com.onedrive.sdk.concurrency.IProgressCallback;
2729
import com.onedrive.sdk.concurrency.MockExecutors;
2830
import com.onedrive.sdk.core.ClientException;
2931
import com.onedrive.sdk.core.OneDriveErrorCodes;
3032
import com.onedrive.sdk.extensions.AsyncOperationStatus;
33+
import com.onedrive.sdk.extensions.ChunkedUploadResult;
3134
import com.onedrive.sdk.extensions.Drive;
3235
import com.onedrive.sdk.extensions.Item;
36+
import com.onedrive.sdk.extensions.UploadSession;
3337
import com.onedrive.sdk.logger.MockLogger;
3438
import com.onedrive.sdk.serializer.MockSerializer;
3539

@@ -40,6 +44,7 @@
4044
import java.io.IOException;
4145
import java.io.InputStream;
4246
import java.io.OutputStream;
47+
import java.util.Arrays;
4348
import java.util.HashMap;
4449
import java.util.Map;
4550
import java.util.concurrent.atomic.AtomicBoolean;
@@ -76,7 +81,7 @@ public Map<String, String> getHeaders() {
7681
setDefaultHttpProvider(new AsyncOperationStatus());
7782
mProvider.setConnectionFactory(new MockSingleConnectionFactory(new TestDataConnection(data)));
7883

79-
AsyncOperationStatus response = mProvider.send(new MockRequest(), AsyncOperationStatus.class, null);
84+
AsyncOperationStatus response = mProvider.send(new MockRequest(), AsyncOperationStatus.class, null, new AsyncMonitorResponseHandler());
8085

8186
assertEquals(expectedLocation, response.seeOther);
8287
assertEquals(1, mInterceptor.getInterceptionCount());
@@ -105,7 +110,7 @@ public Map<String, String> getHeaders() {
105110
setDefaultHttpProvider(new AsyncOperationStatus());
106111
mProvider.setConnectionFactory(new MockSingleConnectionFactory(new TestDataConnection(data)));
107112

108-
AsyncOperationStatus response = mProvider.send(new MockRequest(), AsyncOperationStatus.class, null);
113+
AsyncOperationStatus response = mProvider.send(new MockRequest(), AsyncOperationStatus.class, null, new AsyncMonitorResponseHandler());
109114

110115
assertEquals(expectedLocation, response.seeOther);
111116
assertEquals("Completed", response.status);
@@ -382,6 +387,113 @@ public Map<String, String> getHeaders() {
382387
assertEquals(1, mInterceptor.getInterceptionCount());
383388
}
384389

390+
public void testUploadReturnNextSession() throws Exception {
391+
final String expectedLocation = "http://localhost/up/uploadlocation";
392+
final byte[] chunk = new byte[100];
393+
final UploadSession<Item> toSerialize = new UploadSession<Item>();
394+
toSerialize.uploadUrl = expectedLocation;
395+
toSerialize.nextExpectedRanges = Arrays.asList("100-199");
396+
setDefaultHttpProvider(toSerialize);
397+
398+
final ChunkedUploadResponseHandler<Item> handler = new ChunkedUploadResponseHandler(Item.class);
399+
400+
final ITestData data = new ITestData() {
401+
@Override
402+
public int getRequestCode() {
403+
return 202;
404+
}
405+
406+
@Override
407+
public String getJsonResponse() {
408+
return "{ }";
409+
}
410+
411+
@Override
412+
public Map<String, String> getHeaders() {
413+
final HashMap<String, String> headers = new HashMap<>();
414+
headers.put("Content-Type", "application/json");
415+
return headers;
416+
}
417+
};
418+
419+
mProvider.setConnectionFactory(new MockSingleConnectionFactory(new TestDataConnection(data)));
420+
ChunkedUploadResult result = mProvider.send(new MockRequest(), ChunkedUploadResult.class, chunk, handler);
421+
422+
assertTrue(result.chunkCompleted());
423+
assertEquals(result.getSession(), toSerialize);
424+
}
425+
426+
public void testUploadReturnUploadedItem() throws Exception {
427+
final String expectedLocation = "http://localhost/up/uploadlocation";
428+
final byte[] chunk = new byte[30];
429+
final Item toSerialize = new Item();
430+
toSerialize.id = "abc!123";
431+
setDefaultHttpProvider(toSerialize);
432+
433+
final ChunkedUploadResponseHandler<Item> handler = new ChunkedUploadResponseHandler(Item.class);
434+
435+
final ITestData data = new ITestData() {
436+
@Override
437+
public int getRequestCode() {
438+
return 201;
439+
}
440+
441+
@Override
442+
public String getJsonResponse() {
443+
return "{ }";
444+
}
445+
446+
@Override
447+
public Map<String, String> getHeaders() {
448+
final HashMap<String, String> headers = new HashMap<>();
449+
headers.put("Content-Type", "application/json");
450+
return headers;
451+
}
452+
};
453+
454+
mProvider.setConnectionFactory(new MockSingleConnectionFactory(new TestDataConnection(data)));
455+
ChunkedUploadResult result = mProvider.send(new MockRequest(), ChunkedUploadResult.class, chunk, handler);
456+
457+
assertTrue(result.uploadCompleted());
458+
assertEquals(toSerialize, result.getItem());
459+
}
460+
461+
public void testUploadReturnError() throws Exception {
462+
final String expectedLocation = "http://localhost/up/uploadlocation";
463+
final byte[] chunk = new byte[30];
464+
final OneDriveErrorCodes errorCode = OneDriveErrorCodes.UploadSessionFailed;
465+
final OneDriveError toSerialize = new OneDriveError();
466+
toSerialize.code = errorCode.toString();
467+
setDefaultHttpProvider(toSerialize);
468+
469+
final ChunkedUploadResponseHandler<Item> handler = new ChunkedUploadResponseHandler(Item.class);
470+
471+
final ITestData data = new ITestData() {
472+
@Override
473+
public int getRequestCode() {
474+
return 500;
475+
}
476+
477+
@Override
478+
public String getJsonResponse() {
479+
return "{ }";
480+
}
481+
482+
@Override
483+
public Map<String, String> getHeaders() {
484+
final HashMap<String, String> headers = new HashMap<>();
485+
headers.put("Content-Type", "application/json");
486+
return headers;
487+
}
488+
};
489+
490+
mProvider.setConnectionFactory(new MockSingleConnectionFactory(new TestDataConnection(data)));
491+
ChunkedUploadResult result = mProvider.send(new MockRequest(), ChunkedUploadResult.class, chunk, handler);
492+
493+
assertFalse(result.chunkCompleted());
494+
assertTrue(result.getError().isError(errorCode));
495+
}
496+
385497
/**
386498
* Mock {@see IConnection} backed with test data
387499
*/

onedrivesdk/src/main/java/com/onedrive/sdk/concurrency/AsyncMonitor.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ public class AsyncMonitor<T> {
5050
*/
5151
private final ResultGetter<T> mResultGetter;
5252

53+
/**
54+
* The monitor response handler.
55+
*/
56+
private final AsyncMonitorResponseHandler mHandler;
57+
5358
/**
5459
* Create a new async monitor.
5560
* @param client The client.
@@ -59,17 +64,18 @@ public class AsyncMonitor<T> {
5964
public AsyncMonitor(final IOneDriveClient client,
6065
final AsyncMonitorLocation monitorLocation,
6166
final ResultGetter<T> resultGetter) {
62-
mClient = client;
63-
mMonitorLocation = monitorLocation;
64-
mResultGetter = resultGetter;
67+
this.mClient = client;
68+
this.mMonitorLocation = monitorLocation;
69+
this.mResultGetter = resultGetter;
70+
this.mHandler = new AsyncMonitorResponseHandler();
6571
}
6672

6773
/**
6874
* Gets the status of the monitor from the service asynchronously.
6975
* @param callback The callback.
7076
*/
7177
public void getStatus(final ICallback<AsyncOperationStatus> callback) {
72-
mClient.getExecutors().performOnBackground(new Runnable() {
78+
this.mClient.getExecutors().performOnBackground(new Runnable() {
7379
@Override
7480
public void run() {
7581
try {
@@ -88,14 +94,15 @@ public void run() {
8894
*/
8995
public AsyncOperationStatus getStatus() throws ClientException {
9096
final BaseRequest monitorStatusRequest = new BaseRequest(mMonitorLocation.getLocation(),
91-
mClient,
97+
this.mClient,
9298
/* options */ null,
9399
/* response class */ null) { };
94100
monitorStatusRequest.setHttpMethod(HttpMethod.GET);
95101

96-
return mClient.getHttpProvider().send(monitorStatusRequest,
97-
AsyncOperationStatus.class,
98-
/* serialization object*/ null);
102+
return this.mClient.getHttpProvider().send(monitorStatusRequest,
103+
AsyncOperationStatus.class,
104+
/* serialization object*/ null,
105+
this.mHandler);
99106
}
100107

101108
/**
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// ------------------------------------------------------------------------------
2+
// Copyright (c) 2015 Microsoft Corporation
3+
//
4+
// Permission is hereby granted, free of charge, to any person obtaining a copy
5+
// of this software and associated documentation files (the "Software"), to deal
6+
// in the Software without restriction, including without limitation the rights
7+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
// copies of the Software, and to permit persons to whom the Software is
9+
// furnished to do so, subject to the following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included in
12+
// all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
// THE SOFTWARE.
21+
// ------------------------------------------------------------------------------
22+
23+
package com.onedrive.sdk.concurrency;
24+
25+
import com.onedrive.sdk.extensions.AsyncOperationStatus;
26+
import com.onedrive.sdk.http.DefaultHttpProvider;
27+
import com.onedrive.sdk.http.HttpResponseCode;
28+
import com.onedrive.sdk.http.IConnection;
29+
import com.onedrive.sdk.http.IHttpRequest;
30+
import com.onedrive.sdk.http.IStatefulResponseHandler;
31+
import com.onedrive.sdk.logger.ILogger;
32+
import com.onedrive.sdk.serializer.ISerializer;
33+
34+
import java.io.BufferedInputStream;
35+
import java.io.InputStream;
36+
37+
/**
38+
* The handler class for async monitor response from server.
39+
*/
40+
public class AsyncMonitorResponseHandler implements IStatefulResponseHandler<AsyncOperationStatus, String> {
41+
42+
/**
43+
* Configure the connection before get response.
44+
*
45+
* @param connection The http connection.
46+
*/
47+
@Override
48+
public void configConnection(final IConnection connection) {
49+
connection.setFollowRedirects(false);
50+
}
51+
52+
/**
53+
* Generate the async operation result based on server response.
54+
*
55+
* @param request The http request.
56+
* @param connection The http connection.
57+
* @param serializer The serializer.
58+
* @param logger The logger.
59+
* @return The async operation status.
60+
* @throws Exception An exception occurs if the request was unable to complete for any reason.
61+
*/
62+
@Override
63+
public AsyncOperationStatus generateResult(final IHttpRequest request,
64+
final IConnection connection,
65+
final ISerializer serializer,
66+
final ILogger logger)
67+
throws Exception {
68+
if (connection.getResponseCode() == HttpResponseCode.HTTP_SEE_OTHER) {
69+
logger.logDebug("Item copy job has completed.");
70+
return AsyncOperationStatus.createdCompleted(connection.getHeaders().get("Location"));
71+
}
72+
73+
InputStream in = null;
74+
75+
try {
76+
in = new BufferedInputStream(connection.getInputStream());
77+
final AsyncOperationStatus result = serializer.deserializeObject(
78+
DefaultHttpProvider.streamToString(in), AsyncOperationStatus.class);
79+
result.seeOther = connection.getHeaders().get("Location");
80+
return result;
81+
} finally {
82+
if (in != null) {
83+
in.close();
84+
}
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)