Skip to content

Commit

Permalink
[S3] Fix issue aws-amplify#616: fix the error handling for transfers …
Browse files Browse the repository at this point in the history
…when network disconnects (aws-amplify#865)
  • Loading branch information
Karthikeyan authored Apr 4, 2019
1 parent 84026b0 commit e2177d9
Show file tree
Hide file tree
Showing 8 changed files with 1,209 additions and 72 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Change Log - AWS SDK for Android

## [Release 2.13.1](https://github.com/aws/aws-sdk-android/releases/tag/release_v2.13.1)

## Bug Fixes

* **Amazon S3**
* Fix an issue where the transfer state is not set to `WAITING_FOR_NETWORK` when the network disconnects. See [issue #616](https://github.com/aws-amplify/aws-sdk-android/issues/616)

## [Release 2.13.0](https://github.com/aws/aws-sdk-android/releases/tag/release_v2.13.0)

### Enhancements
Expand Down
24 changes: 19 additions & 5 deletions aws-android-sdk-s3-test/build.gradle
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
apply plugin: 'com.android.library'
apply plugin: 'devicefarm'

android {
compileSdkVersion 27



defaultConfig {
minSdkVersion 21
targetSdkVersion 27
versionCode 1
versionName "1.0"

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

}

buildTypes {
Expand All @@ -31,15 +29,31 @@ android {

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
api (project(":aws-android-sdk-s3")){

api (project(":aws-android-sdk-s3")) {
exclude group: "com.google.android", module: "android"
}
api (project(":aws-android-sdk-sns")){

api (project(":aws-android-sdk-sns")) {
exclude group: "com.google.android", module: "android"
}

testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support:appcompat-v7:27.0.0'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation project(":aws-android-sdk-testutils")
androidTestImplementation 'org.apache.commons:commons-io:1.3.2'
androidTestImplementation 'org.robolectric:robolectric:2.4'
}

devicefarm {

// Required. The Project must already exist. You can create a project in the AWS console.
projectName "AWSAndroidKeyStoreTester"

// Required. You must specify either accessKey and secretKey OR roleArn. roleArn takes precedence.
authentication {
accessKey "$System.env.DEVICEFARM_ACCESS_KEY"
secretKey "$System.env.DEVICEFARM_SECRET_KEY"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/**
* Copyright 2019-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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.amazonaws.mobileconnectors.s3.transferutility;

import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;

import java.io.File;
import java.util.concurrent.CountDownLatch;

import static com.amazonaws.services.s3.internal.Constants.MB;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;

/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class TransferServiceNetworkInstrumentedTest extends TransferUtilityTestBase {

private static final String LOG_TAG = TransferServiceNetworkInstrumentedTest.class.getSimpleName();

@Rule
public TemporaryFolder temp = new TemporaryFolder();

private static TransferObserver transferObserver;
private final static long TIMEOUT = 45 * 1000;
private final static long MULTIPART_FILE_SIZE = 50 * MB;
private final static long SINGLEPART_FILE_SIZE = 4 * MB;

@Before
public void setUp() {
setWifiNetwork(appContext, true);

appContext.startService(new Intent(appContext, TransferService.class));
}

@After
public void tearDown() {
transferObserver = null;

setWifiNetwork(appContext, true);
}

@Test
public void testMultiPartUploadWithNetworkReconnect() throws Exception {
Log.d(LOG_TAG, "testUploadWithNetworkDisconnect " + MULTIPART_FILE_SIZE + " begin.");


final File tempFile = temp.newFile();
fillFile(tempFile, MULTIPART_FILE_SIZE);

transferObserver =
transferUtility.upload(
tempFile.getName(),
tempFile);

networkReconnectHelper();

Log.d(LOG_TAG, "testUploadWithNetworkDisconnect " + MULTIPART_FILE_SIZE + " end.");
}

@Test
public void testDownloadWithNetworkReconnect() throws Exception {
Log.d(LOG_TAG, "testDownloadWithNetworkReconnect " + MULTIPART_FILE_SIZE + " begin.");


final File tempFile = temp.newFile();
fillFile(tempFile, MULTIPART_FILE_SIZE);

transferObserver =
transferUtility.upload(
tempFile.getName(),
tempFile);

networkReconnectHelper();

transferObserver =
transferUtility.download(
tempFile.getName(),
tempFile);

networkReconnectHelper();

Log.d(LOG_TAG, "testDownloadWithNetworkReconnect " + MULTIPART_FILE_SIZE + " end.");
}

private void networkReconnectHelper() {
final CountDownLatch countDownLatch = new CountDownLatch(1);

// Attach a listener to the observer to get state update and progress notifications
transferObserver.setTransferListener(new TransferListener() {
@Override
public void onStateChanged(int id, TransferState state) {
Log.i(LOG_TAG, "onStateChanged = " + state);

if (TransferState.COMPLETED == state) {
// Handle a completed upload.
Log.i(LOG_TAG, "Upload successful");
countDownLatch.countDown();
} else if (TransferState.FAILED == state) {
Log.i(LOG_TAG, "Upload failed");
countDownLatch.countDown();
}
}

@Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
float percentDonef = ((float) bytesCurrent / (float) bytesTotal) * 100;
int percentDone = (int)percentDonef;

Log.i(LOG_TAG, "ID:" + id + " bytesCurrent: " + bytesCurrent
+ " bytesTotal: " + bytesTotal + " " + percentDone + "%");
}

@Override
public void onError(int id, Exception ex) {
// Handle errors
ex.printStackTrace();
countDownLatch.countDown();
}
});


waitUntilStateReached(TransferState.IN_PROGRESS, TIMEOUT);
waitUntilProgressPercentageReached(25, TIMEOUT);
setWifiNetwork(appContext, false);
waitUntilStateReached(TransferState.WAITING_FOR_NETWORK, TIMEOUT);
setWifiNetwork(appContext, true);
waitUntilStateReached(TransferState.IN_PROGRESS, TIMEOUT);

try {
countDownLatch.await();
} catch (InterruptedException ie) {
ie.printStackTrace();
}

transferObserver.refresh();
Log.d(LOG_TAG, transferObserver.toString());
assertEquals(TransferState.COMPLETED, transferObserver.getState());
}

private void setWifiNetwork(Context context, boolean enabled) {
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
assertTrue(wifiManager.setWifiEnabled(enabled));

// Wait for
try {
Thread.sleep(2000);
} catch (Exception ex) {
ex.printStackTrace();
}
}

private void waitUntilStateReached(final TransferState transferState, final long timeout) {
long waitTimeTillNow = 0;
while (!transferObserver.getState().equals(transferState) &&
waitTimeTillNow <= timeout) {
try {
waitTimeTillNow += 2000;
Log.d(LOG_TAG, "Checking for state = " + transferState + "; Sleeping for 2000 ms");
Thread.sleep(2000);
} catch (Exception ex) {
ex.printStackTrace();
}
transferObserver.refresh();
}
transferObserver.refresh();
assertEquals(transferState, transferObserver.getState());
}

private void waitUntilProgressPercentageReached(final int progressPercentage,
final long timeout) {
long waitTimeTillNow = 0;
while (!(getProgressPercentage() >= progressPercentage) &&
waitTimeTillNow <= timeout) {
try {
Log.d(LOG_TAG, "Waiting until " + progressPercentage +
"% of progress is made. Sleeping for 2000 ms");
Thread.sleep(2000);
waitTimeTillNow += 2000;
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

private int getProgressPercentage() {
transferObserver.refresh();
float percentDonef = ((float) transferObserver.getBytesTransferred() / (float) transferObserver.getBytesTotal()) * 100;
return (int)percentDonef;
}
}
Loading

0 comments on commit e2177d9

Please sign in to comment.