Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Up download file #117

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ hs_err_pid*
*.settings
*.classpath
**/.vscode
*.project
*.project
appium-examples/src/test/java/com/realdevice/up_download_file/samsung_real_device/downloaded-sauce-bot-coding.png
7 changes: 7 additions & 0 deletions appium-examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@
<artifactId>assertj-core</artifactId>
<version>3.10.0</version>
</dependency>

<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>

</dependencies>
<build>
<plugins>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package com.realdevice.up_download_file;

import io.appium.java_client.android.AndroidDriver;
import org.apache.commons.io.FileUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.openqa.selenium.MutableCapabilities;
import org.springframework.util.FileSystemUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import static helpers.Constants.region;
import static org.assertj.core.api.Assertions.assertThat;

public class DownloadImageFromAndroidRealDevice {

@Rule
public TestName name = new TestName();

protected AndroidDriver driver;

int currentPhotos = 0;
String deviceFilePath = "/storage/self/primary/sauce-bot-coding.png";
String downloadFolder = "src/test/java/com/realdevice/up_download_file/samsung_real_device";


@Before
public void setup() throws IOException {

System.out.println("Sauce - BeforeEach hook");

String username = System.getenv("SAUCE_USERNAME");
String accesskey = System.getenv("SAUCE_ACCESS_KEY");

String sauceUrl;
if (region.equalsIgnoreCase("eu")) {
sauceUrl = "@ondemand.eu-central-1.saucelabs.com:443";
} else {
sauceUrl = "@ondemand.us-west-1.saucelabs.com:443";
}
String SAUCE_REMOTE_URL = "https://" + username + ":" + accesskey + sauceUrl +"/wd/hub";
URL url = new URL(SAUCE_REMOTE_URL);

MutableCapabilities capabilities = new MutableCapabilities();
// This is a specific device type so I can control the state of it
capabilities.setCapability("deviceName", "Samsung Galaxy S9");
capabilities.setCapability("platformVersion", "10");
capabilities.setCapability("platformName", "Android");
capabilities.setCapability("automationName", "UiAutomator2");
capabilities.setCapability("name", name.getMethodName());
capabilities.setCapability("browserName", "chrome");
capabilities.setCapability("autoGrantPermissions", true);

// Launch remote browser and set it as the current thread
driver = new AndroidDriver(url, capabilities);
}

@Test
public void downloadFileFromRealDevice() throws InterruptedException, IOException {
System.out.println("Sauce - start test downloadFileFromRealDevice");
driver.context("NATIVE_APP");


// Make sure the download dir we are going to use is empty
File downloadFolderDir = new File(downloadFolder);
FileUtils.deleteDirectory(downloadFolderDir);
// Create the directory
FileUtils.forceMkdir(downloadFolderDir);

// Start the Gallery on the device
SamsungGallery samsungGallery = new SamsungGallery(driver);
samsungGallery.open();
currentPhotos = samsungGallery.amountOfPhotos();
System.out.println("Sauce - number of photos before upload: " + currentPhotos );

// The file we want to upload
String codingBot = "src/test/java/com/realdevice/up_download_file/sauce-bot-coding.png";
File codingBotFile = new File(codingBot);
// Push the file to the device
// This is the `tricky` part, you need to know the file structure of the device and where you can download the file from.
// We checked this structure with the VUSB offering of Sauce Labs for private devices.
driver.pushFile(deviceFilePath, codingBotFile);

// wait till it is uploaded
boolean bPhotoUpload = samsungGallery.waitUploadPhoto(currentPhotos, 5);

// This is not need only for the video
waiting(2);

// Pull the file from the device, it was uploaded in the before step
byte[] downloadedBase64Image = driver.pullFile(deviceFilePath);

// Before continue with the downloaded file -> delete the file from the device
samsungGallery.deletePhoto("last");

BufferedImage image = ImageIO.read(new ByteArrayInputStream(downloadedBase64Image));
String downloadFile = downloadFolder + "/downloaded-sauce-bot-coding.png";
File f = new File(downloadFile);

// write the image
ImageIO.write(image, "png", f);

// Now verify that the file does exist locally
assertThat(f.exists()).as("The file we downloaded from the device, doesm't exist locally").isTrue();
// This is not need only for the video
waiting(2);
}

public static void waiting(int sec){
try
{
Thread.sleep(sec*1000);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
}

@Rule
public TestWatcher watchman= new TestWatcher() {
nadvolod marked this conversation as resolved.
Show resolved Hide resolved
@Override
protected void failed(Throwable e, Description description) {
try {
System.out.println("Test Failed! ");
driver.executeScript("sauce:job-result=failed");
} catch (Exception ignored) {
} finally {
driver.quit();
}
}

@Override
protected void succeeded(Description description) {
try {
System.out.println("Test Passed!");
driver.executeScript("sauce:job-result=passed");
} catch (Exception ignored) {
} finally {
driver.quit();
}
}
};

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Using Uploading and Downloading Files from Sauce Labs Android Real Devices
This folder contains examples for using up / download files from:

- [Android real devices on Sauce Labs Platform](#run-tests-on-sauce-labs-android-real-devices)

> **NOTE:**\
> Up/downloading files to iOS real devices is not supported by Appium!\
> Up/downloading files to Sauce Labs iOS Simulators is currently not supported by Sauce Labs

> **NOTE:**\
> Make sure you are in the folder `appium-examples` when you execute the commands to run the tests

## Important information
### Up/downloading files to and or from Android real devices
The market of Android is being controlled by a lot of different vendors, this also means a lot of different file structures
where to upload your file to or download the file from. This makes it a challenge to determine which folder on the device you
need to have.
You can check the location if you are using the Virtual USB offering of Sauce Labs for Private devices,
see also [this video](https://youtu.be/hUaVj6WmqRA).

The advice is that you use a dedicated device, so you always know the file structure and don't need to over complicate
the up/downloading script.

### Apps to verify up/downloads
For Android real devices we use the Samsung Gallery. The purpose
is not to show you how to automate these apps, but more to show you how you can verify if an upload was successful.

### Environment variables for Sauce Labs
The examples in this repository that can run on Sauce Labs use environment variables, make sure you've added the following

# For Sauce Labs Real devices in the New UI
export SAUCE_USERNAME=********
export SAUCE_ACCESS_KEY=*******

## Uploading files
### Android Real devices
The script on how to use this can be found [here](./UploadImageToAndroidRealDevice.java) and the execution
will look like this

![Upload Android real device](assets/upload-real-device.gif)

## Run tests on Sauce Labs Android real devices
If you want to run the tests on Sauce Labs real Android devices then you can run the Android test with

// If using the US DC
mvn clean test -Dtest=DownloadImageFromAndroidRealDevice -Dregion=us
mvn clean test -Dtest=UploadImageToAndroidRealDevice -Dregion=us

// If using the EU DC
mvn clean test -Dtest=DownloadImageFromAndroidRealDevice -Dregion=eu
mvn clean test -Dtest=UploadImageToAndroidRealDevice -Dregion=eu
The tests will be executed on a Samsung Galaxy S9.

## Credits
This example is based on [this webdriverio example](https://github.com/saucelabs-training/demo-js/tree/main/webdriverio/appium-app/examples/up-download-file)
from Wim Selles.
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.realdevice.up_download_file;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileBy;
import io.appium.java_client.android.Activity;
import io.appium.java_client.android.AndroidDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.util.List;


public class SamsungGallery {

private AndroidDriver driver;

private String photos = "com.sec.android.gallery3d:id/recycler_view_item";
private String deleteButton ="com.sec.android.gallery3d:id/btn_delete";
private String confirmDeleteButton = "com.sec.android.gallery3d:id/button1";

public SamsungGallery(AndroidDriver driver) {
this.driver = driver;
}

public void open() {
driver.startActivity(new Activity("com.sec.android.gallery3d", "com.samsung.android.gallery.app.activity.GalleryActivity"));

}

public void openPhoto(String which){
int whichPhoto = (which == "first" ? 0 : this.amountOfPhotos()-1);

// open the photo
List<WebElement> photosList = driver.findElementsById(photos);
photosList.get(whichPhoto).click();
}

/**
*
* @param which which photo to delete: first or last
*/
public void deletePhoto(String which){

this.openPhoto(which);

WebDriverWait wait = new WebDriverWait(driver, 10);

final WebElement deleteImgBtn = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id(deleteButton)));
deleteImgBtn.click();
// driver.findElementById(deleteButton).click();
driver.findElementById(confirmDeleteButton).click();

// this.confirmDeleteButton.waitForDisplayed();
// this.confirmDeleteButton.click();
// // Wait for it to disappear
// this.confirmDeleteButton.waitForDisplayed({reverse: true});

}

public int amountOfPhotos(){
return (driver.findElementsById(photos).size());
}

/**
*
* @param currentPhotos - how many photos are currently in the gallery
* @param waitingTimeSec - how long to wait for the upload
* @return true if photo was uploaded and false if there the photo was not uploaded
*/
public boolean waitUploadPhoto(int currentPhotos, int waitingTimeSec){
int waitingTime = waitingTimeSec;
boolean bPhotoUpload = false;
for (int i = waitingTimeSec; i > 0; i--) {
if (this.amountOfPhotos() > currentPhotos){
bPhotoUpload = true;
break;
}
try
{
Thread.sleep(1000);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
}
return bPhotoUpload;
}

}
Loading