Appium

Tuesday, 24 January 2017

Connect SSH tunnel and upload the files through JSch shell channel

Recently, I came across the problem where tunnel is key-based authentication so I did some workaround and finally able to logged into the tunnel.

It was really challenging task for me to connect the tunnel where the private key is loaded on to the client machine and all the communication would be user based. So decided to use JSch library, it allows us to connect the SSH to the remote host.

Maven dependency for JSch (check the updated version in maven site):

<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.54</version>
</dependency>

To connect the tunnel programmatically, first we need to make the connection with remote host. here is the code to connect the session:

public static Session getSession(String host, String user, int port,String privateKey,String passphrase)
{
try {
JSch jsch = new JSch();
jsch.addIdentity(privateKey, passphrase);
session = jsch.getSession(user, host, port);
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");//if you want to skip host-key check
session.setConfig(config);
session.connect();
} catch (Exception e) {
                       System.out.println("Issue in creating the Session---->"+e);
}
return session;
}

once connected to the session, we need to open the 'shell' channel using connected session and then execute the command in the shell to connect to the tunnel.

The following function can be used to connect the tunnel and upload the files:

public static void tunnelConnectionAndFileUpload(Session sshSession,String tunnelConCmd,String localLocation, String tunnelLocation, String[] fileName) throws IOException, JSchException{
try {
String tunnelCommand=tunnelConCmd+"\r";
String localLoc="lcd "+localLocation+"\r";
String tunnelLoc="cd "+tunnelLocation+"\r";
for(String value:fileName){
String fName="put "+value+"\r";
Channel channel = sshSession.openChannel("shell");
        OutputStream inputstream_for_the_channel = channel.getOutputStream();
PrintStream commander = new PrintStream(inputstream_for_the_channel, true);
ByteArrayOutputStream out = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(out);
channel.setOutputStream(ps);
channel.connect();
System.out.println("-----------Connecting to the tunnel--------------");
commander.write(tunnelCommand.getBytes());
waitForText(out,"authorized");//you can change the condition 
System.out.println(out.toString());
out.reset();
System.out.println("-------Navigating to the local folder---------");
commander.write(localLoc.getBytes());
waitForText(out,"lcd");
System.out.println(out.toString());
out.reset();
System.out.println("-------Navigating to the tunnel folder---------");
commander.write(tunnelLoc.getBytes());   
waitForText(out,"cd");
System.out.println(out.toString());
out.reset();
System.out.println("-------Uploading file to the tunnel---------");
commander.write(fName.getBytes());  
waitForText(out,"100%");
System.out.println(out.toString());
out.reset();
}
}
catch (Exception e) {
System.out.println("Issue in creating the tunnel Session---->"+e);
}


In the above function we need to provide the following parameters:

sshSession: pass the active session
tunnelConCmd: pass the command to connect tunnel session
localLocation: pass the location from where we need to upload the file (it will be first session location)
tunnelLocation: pass the tunnel Location
fileName: provide the files name to be uploaded

The another very important task that we need to make sure whether tunnel command execution completed or not, for this we need to implement the wait for until command completely executed.

The following function can be used to wait for command execution:

public static void waitForText(ByteArrayOutputStream text, String condition) throws InterruptedException{
while (System.nanoTime() < System.nanoTime()+TimeUnit.NANOSECONDS.convert(5L, TimeUnit.MINUTES)){
 Thread.sleep(2000);
 if(text.toString().contains(condition)){
 break;
 }
}
}

this function will wait for maximum 5 min to make sure whether command is completely executed or not.
At last we need to terminate the session:

public static void terminateSession(Session session){
try {
if(session.isConnected()){
   session.disconnect();
}
} catch (Exception e) {
System.out.println("Exception in disconnecting the Session---->"+e);
}
}

Now, we can easily upload the files to the tunnel (Y)
Above functions can be used like this:

public static void main(String[] args) throws IOException, JSchException {
String tunnelCommand="sftp -oPort=22 -oIdentityFile=/home/manoj/.ssh/id_dsa abc@xyz.example.com";
String tunnelLoc="var/upload";
String localFolderLoc="/home/manoj/files";
String privateKeyFile = "provide private key location";
Session session=getSession("xxx@example.com", "manoj", 22, privateKeyFile, "pass@123");
tunnelConnectionAndFileUpload(session, tunnelCommand,localFolderLoc, tunnelLoc, new String[]{"pqr_test.xml"});
terminateSession(session);
}

Keep Coding! :)


Monday, 19 August 2013

Native Android Apps Automation with WebDriver Using Appium

I am writing this post to share my personal experience with Appium to automate Native Android Apps on Windows platform.

About WebDriver - WebDriver is a web automation framework that allows to execute test scripts on desktop and mobile browsers.
If you are considering to test mobile apps, then the correct solution is Appium.

About Appium - Appium is an open source automation tool which can automate web, native and hybrid mobile apps on iOS, Android and FirefoxOS platforms.
It uses the WebDriver JSON wire protocol to drives the Android UI Automator framework.

Appium's Benefits- 
1. It can automate web, hybrid and native mobile apps. 
2. It allows us to write test cases in any programming language (like java, c#, ruby etc) using Selenium WebDriver. 
3. The other benefits of Appium is that it is cross- platform test automation tool for mobile apps which means the same test cases would work on multiple platforms.

Getting started with Appium drives on Real Android Device--

Pre-requisites--
1. Appium for Windows (download)
2. Android SDK (download)
3. JDK (download)
4. Eclipse (download)
5. TestNG (download)
6. Appium client library (download)
7. Selenium Server jar (download)
8. WebDriver client library (download)
9. Apk info- Users need to install the same app. in android mobile to get the package and activity info of the apps.(download)
Apk Info

Step 1- Setting up the Android SDK on Windows

a. Open System properties window by pressing window-key +Pause or right click on My Computer and click properties.

b. Click on 'Advanced system settings'
c. Click on 'Environment Variables'
d. Set ANDROID_HOME as shown in above figure.
e. In the 'System variables' find 'Path' and then double click on it.

f. In the 'variable value' text box, add the new path 'C:\Users\dell\android-sdks\platform-tools'.Just be sure that there is a semi-colon separating this new entry from the preexisting values.

g. Now click ok button of all boxes.

Now start android server using "adb start-server" from command prompt.


Step 2- Connect your Android device with the PC and make sure device Developer options is 'ON' and also USB debugging mode is checked as shown in below picture.



Developer options
Now hit "adb devices" from command prompt to make sure device connected successfully.

Step 3- Upzip downloaded AppiumForWindows.zip, the folder contains Appium.exe, run it by double clicking, it will look like-

 Appium v1.4.16

No need to change the IP address and port number.
Now, click on Launch button then Appium Server will start at 127.0.0.1:4723 as shown in below picture.
Appium Server Started

Step 4- Here i am taking a example of Android native app Calculator.
Calculator
Step 5- Writing test scripts for Calculator using java, WebDriver and TestNG unit framework.
package com;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.remote.MobileCapabilityType;

import io.appium.java_client.remote.AndroidMobileCapabilityType;
import java.net.MalformedURLException;
import java.net.URL;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.*;

public class CalculatorTest {

AppiumDriver driver;

@BeforeClass
public void setUp() throws MalformedURLException{

     //Set up desired capabilities and pass the Android app-activity and app-package to Appium

   DesiredCapabilities capabilities = new DesiredCapabilities();
   capabilities.setCapability(MobileCapabilityType.VERSION, "4.4.4");
   capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
   capabilities.setCapability(MobileCapabilityType.DEVICE_NAME,"TA64301YDK");
   capabilities.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "com.android.calculator2"); // This is package name of your app (you can get it from apk info app
   capabilities.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, "com.android.calculator2.Calculator"); // This is Launcher activity of your app (you can get it from apk info app)
   //Create AndroidDriver instance and connect to the Appium server.
   //It will launch the Calculator App in Android Device using the configurations specified in Desired Capabilities

   driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
}

@Test
public void testCal(){

    //locate the Text on the calculator by using By.name()
    WebElement two=driver.findElement(By.name("2"));
    two.click();
    WebElement plus=driver.findElement(By.name("+"));
    plus.click();
    WebElement four=driver.findElement(By.name("4"));
    four.click();
    WebElement equalTo=driver.findElement(By.name("="));
    equalTo.click();
    //locate the edit box of the calculator by using By.className()
    WebElement results=driver.findElement(By.className("android.widget.EditText"));
    //Check the calculated value on the edit box
    assert results.getText().equals("6"):"Actual value is : "+results.getText()+" did not match with expected value: 6";
}
@AfterClass
public void teardown(){
  
    //close the app
    driver.closeApp();
}
}


Step 6 - Execute above test scripts using TestNG.

Step 7 - Done