Is there a way I can get appium to startup within the code I am writing for a junit test? Since appium only needs to run when my test is running it doesnt make sense to me to keep the appium server always going.
Right now I am using junit and maven to run test builds. Due to stability issues with appium it will sometimes die in the middle of the build, thus failing all remaining tests. I want to know if it is possible to add something to the #Before method to start the appium server before connecting the WebDriver to it, and then terminating it in the #After method. This should address any issues with appium failures since it can reset before starting the next test.
Still looking into starting and ending processes in general in java to see if this will work. If I figure this out I will update this post to help anyone else interested in testing this way.
Figured out how to get this to work by just running the terminal command within the code
#Before
public void setUp() throws Exception {
closeSimulatorAndInstruments(); // also closes any appium servers
appium = Runtime.getRuntime().exec("/usr/local/bin/appium");
Thread.sleep(1000); // wait for appium to start up, not sure how to check the status
... // start test
}
#After
public void tearDown() throws Exception {
captureScreenshot(testName.getMethodName());
driver.quit();
appium.destroy(); // kills the appium server so it wont collide with the next run
}
I'm seeing issues with my CI box running jenkins attempting to do this but it's probably unrelated. Locally this is working great since I don't have to remember to run appium separately anymore or check to see if it died. This is not advised however if you need to see the appium output which may contain important errors
I have written a library for this.
/**
*#author Raghu Nair
*/
public class Appium {
private static volatile Appium instance;
public static Appium getInstance(String outFile, String errFile) {
if (instance == null) {
synchronized (Appium.class) {
if (instance == null) {
instance = new Appium(outFile, errFile);
}
}
}
return instance;
}
Process process;
final String outFile;
final String errFile;
private Appium(String outFile, String errFile) {
this.outFile = outFile;
this.errFile = errFile;
}
public void start() throws IOException {
if (process != null) {
stop();
}
String processName = System.getProperty("appium.bin");
String processString = processName + " -lt 180000";
ProcessBuilder builder = new ProcessBuilder("bash");
process = builder.start();
OutputStream outStream = System.out;
if (outFile != null) {
outStream = new FileOutputStream(outFile);
}
OutputStream errStream = System.err;
if (errFile != null) {
errStream = new FileOutputStream(errFile);
}
handleStream(process.getInputStream(), new PrintWriter(outStream));
handleStream(process.getErrorStream(), new PrintWriter(errStream));
try (PrintWriter writer = new PrintWriter(process.getOutputStream())) {
//writer.println("kill -9 `ps -ef | grep appium | cut -d' ' -f2`");
writer.println("export PATH=$PATH:/usr/bin/:/usr/local/bin/");
writer.println(processString);
writer.flush();
}
}
private void handleStream(final InputStream processOut, final PrintWriter writer) {
Thread outHandler;
outHandler = new Thread(new Runnable() {
#Override
public void run() {
try {
BufferedReader stdout = new BufferedReader(
new InputStreamReader(processOut));
String line;
while ((line = stdout.readLine()) != null) {
writer.println(line);
writer.flush();
}
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
}
});
outHandler.start();
}
public void stop() {
System.out.println("Stopping the process");
if (process != null) {
try {
process.destroy();
process.getErrorStream().close();
process.getInputStream().close();
process.getOutputStream().close();
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
}
}
public static void main(String[] args) throws Exception {
System.setProperty("appium.bin", "/Applications/Appium.app//Contents/Resources/node_modules/.bin/appium");
Appium appium = Appium.getInstance("/Users/<user>/tmp/appium.out", "/Users/<user>/tmp/appium.err");
appium.start();
TimeUnit.SECONDS.sleep(30);
appium.stop();
}
I've solved this in a very similar way using a DefaultExecutor to keep track of the Appium process so it can be destroyed at the end of the tests. This also allows the Appium output to be logged out during the tests using a DefaultExecuteResultHandler.
To avoid using a sleep to wait for Appium to start, you could create your WebDriver instance inside a try-catch
for (int i = 10; i > 0; i--) {
try {
driver = new RemoteWebDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
// If we successfully attach to appium, exit the loop.
i = 0;
} catch (UnreachableBrowserException e) {
LOGGER.info("Waiting for Appium to start");
}
}
You could add a sleep in the catch block if you wanted to poll less frequently.
I see we can improve a bit above solution.
Create Profiles for each environment ( define appium home)
you could redirect the Process output stream to a file. File name could be defined in profile are in java file.
Related
My Java programme starts several other Java processes. When the programme is closed, all created processes should be terminated.
If the programme is stopped via an internal stop command, all data can be saved and the processes shut down. I use a shutdown hook for this, and it works very well so far.
But if the programme terminates abruptly or is not closed correctly by the user, all processes remain running and the programme does not work the next time it is started.
How can I make it so that code is executed when the programme stops abruptly, or rather, how can I stop the processes?
As suggested, I should have included some code. Here is a simplified version of the code:
Class which starts the process:
#Override
public void startProcess() throws IOException {
String command = "java -jar server.jar nogui";
this.process = Runtime.getRuntime().exec(command, null, new CloudFolder(super.getPath()).get());
final InputReader reader = new InputReader();
reader.open();
String in = reader.getInput();
if (in.equals("stop")) {
this.process.destroy();
this.process.getOutputStream().close();
}
}
Main class:
public static void main(String[] args) {
// normally the startProcess() Method would be
// called right here.
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
// Just to see if it worked
File file = new File("closing");
try {
file.createNewFile();
} catch (IOException exception) {
exception.printStackTrace();
}
}
}, "Shutdown-thread"));
}
I am using MAC terminal to start appium server. In terminal I have executed command appium & to start the server which is working.
I have installed appium server through terminal using npm -g install appium
However when I am trying to execute the same code using Java then server is not starting.
Code:
Runtime.getRuntime().exec(new String[]{"/bin/sh","appium &"})
Error:
No such file or directory.
I have also tried to create shell script with appium command. When I invoke the shell script through Java, it says that command not found.
Code to invoke shell script command.
Process p = new ProcessBuilder(new String[]{"/bin/sh","-c","sh appium.sh"})
On invoking in Java, it gives error "appium.sh:Error on line1 - appium command not found"
When I invoked the same shell script through the terminal, appium server started successfully.
You can use below code for Starting appium server using java code and use service_url while intializing appium driver .Example is taken from THIS POST
import java.io.File;
import io.appium.java_client.service.local.AppiumDriverLocalService;
import io.appium.java_client.service.local.AppiumServiceBuilder;
public class AppiumServerStartStop {
static String Appium_Node_Path="C:\\Program Files (x86)\\Appium\\node.exe";
static String Appium_JS_Path="C:\\Program Files (x86)\\Appium\\node_modules\\appium\\bin\\appium.js";
static AppiumDriverLocalService service;
static String service_url;
public static void appiumStart() throws Exception{
service = AppiumDriverLocalService.buildService(new AppiumServiceBuilder().
usingPort(2856).usingDriverExecutable(new File(Appium_Node_Path)).
withAppiumJS(new File(Appium_JS_Path)));
service.start();
Thread.sleep(25000);
service_url = service.getUrl().toString();
}
public static void appiumStop() throws Exception{
service.stop();
}
}
public static void startAppiumServer() {
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
final String appiumNodeFilePath = APPIUM_NODE_FILE_PATH;
final String appiumJavaScriptServerFile = APPIUM_JAVA_SCRIPT_SERVER_FILE_PATH;
final String appiumServerPortNumber = APPIUM_SERVER_PORT_NUMBER;
final String appiumServerConfigurations = "--no-reset --local-timezone --port "+ appiumServerPortNumber+ " -bp "+(Integer.parseInt(appiumServerPortNumber)+1);
(new Thread(){
public void run(){
String startCommand ="\"" + appiumNodeFilePath + "\" \""+ appiumJavaScriptServerFile + "\" "+ appiumServerConfigurations;
System.out.println("Server start command: "+startCommand);
executeCommand(startCommand);
}
}).start();
try {
Thread.sleep(25000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void executeCommand(String command) {
String s = null;
try {
Process p = Runtime.getRuntime().exec(command);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
System.out.println("Appium Server Output Logs:\n");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
System.out.println("Appium Server Error Logs:\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
} catch (IOException e) {
System.out.println("exception: ");
e.printStackTrace();
}
}
APPIUM_NODE_FILE_PATH="C:\Program Files (x86)\Appium\node.exe";
APPIUM_JAVA_SCRIPT_SERVER_FILE_PATH="C:\ProgramFiles(x86)\Appium\node_modules\appium\bin\appium.js
If you are interested to learn how it should be implemented, check appium-java-client AppiumDriverLocalService class.
And since you are using java in most cases its better to use AppiumDriverLocalService instead implementing your own solution:
AppiumDriverLocalService service = AppiumDriverLocalService.
buildDefaultService();
service.start() // to start appium server
...
service.getUrl() // to get URL of running server
...
service.isRunning() // to check if appium server is alive
...
service.stop() // to stop appium server
I try to code a Java program which uses Drozer (a tool written in Python to test vulnerabilities in Android app). I need to execute commands directly from Java and so far everything goes pretty well, but I have a problem when an interavtive session of drozer starts. It seems that the problem occurs when EOF needs to be handled, since ctrl + D also can't stop the session. Here is what I get after hitting ctrl + D
*** Unknown syntax: EOF
Here is the code I use to connect from Java to Drozer, after running it, my program starts infinite loop printing the same error: *** Unknown syntax: EOF.
Any other command works like a charm. Any ideas what do I do wrong?
Cheers
public class test1 {
public static void main(String a[]) throws InterruptedException, IOException {
List<String> commands = new ArrayList<String>();
List<String> commands1 = new ArrayList<String>();
commands.add("/usr/local/bin/drozer");
commands.add("console");
commands.add("connect");
ProcessBuilder pb = new ProcessBuilder(commands);
pb.redirectErrorStream(true);
try {
Process prs = pb.start();
Thread inThread = new Thread(new In(prs.getInputStream()));
inThread.start();
Thread.sleep(1000);
OutputStream writeTo = prs.getOutputStream();
writeTo.write("oops\n".getBytes());
writeTo.flush();
writeTo.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
class In implements Runnable {
private InputStream is;
public In(InputStream is) {
this.is = is;
}
#Override
public void run() {
try {
byte[] b = new byte[1024];
int size = 0;
while ((size = is.read(b)) != -1) {
System.out.println(new String(b));
}
is.close();
} catch (IOException ex) {
Logger.getLogger(In.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I am trying to run an accurev command using Java Runtime exec (as described in code below). Since I have a network problem so when the login command is executed the command keeps on waiting for the response and doesn't time out. So how should I be able handle this error.
private static void accurevLogin() throws IOException {
Runtime runTime = Runtime.getRuntime();
String userName = prop.getProperty("UserName");
String password = prop.getProperty("Password");
String command = (new StringBuilder("accurev login ")).append(userName).append(" ").append(password).toString();
Process ps = null;
try {
ps = runTime.exec(command);
} catch (IOException e) {
System.out.println("Command Execution Error!");
}
/* Error handling Code */
System.out.println("ACCUREV LOGGED IN");
}
When I use
BufferedReader input = new BufferedReader(new InputStreamReader(ps.getInputStream()));
input.readline in the loop will keep on running and I am not able to check the output.
The best way would be to use a timeout option of the accurev command, if available.
If there is no such option, you should execute it in a seperate Java thread and abort programatically after some timeout of your choosing.
Here is an example with a simple sleep command:
Thread thread = new Thread() {
public void run() {
try {
Process proc = Runtime.getRuntime().exec("sleep 5");
} catch (IOException e) {
e.printStackTrace();
}
}
};
thread.start(); //start thread in background
synchronized (thread) {
try {
thread.wait(1000L); //your timeout
if (thread.isAlive()) {
System.out.println("interrupting");
thread.interrupt(); //interrupt the thread
}
} catch (Exception e) {
System.out.println("interrupted");
}
}
I have a class 'one' that compiles class 'two' using commands
I use this code to run two
Process p2 = Runtime.getRuntime().exec("java two");
BufferedReader in = new BufferedReader(
new InputStreamReader(p2.getInputStream()) );
while ((line = in.readLine()) != null) {
System.out.println(line);
}
in.close();
Now when 'two' has printings in its main method, it works fine and they are printed in the console but when it has a user input Eclipse crashes.
when I even remove the while loop it doesn't allow me to write in the console
I am creating a new console using
MessageConsole console = new MessageConsole("", null);
console.activate();
ConsolePlugin.getDefault().getConsoleManager()
.addConsoles(new IConsole[] { console });
MessageConsoleStream stream = console.newMessageStream();
System.setOut(new PrintStream(stream, true));
I had a similar problem. I extended the MessageConsole (just to be able to have a specific consolePageParticipant) and in the constructor I have redirected the System.out to a new MessageConsoleStream. With the first version of my code the RCP application crashed, with the second version it hanged.
I already don't remember how did the code which crashed/hanged look like, but I found out that I cannot redirect the output sooner, than the MessageConsole is displayed. So I used a new thread to wait for some time (5 seconds - maybe too much?) before the redirect.
messageConsoleStream = myConsole.newMessageStream();
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
OutputStream out = new OutputStream() {
#Override
public void write(int b) throws IOException {
messageConsoleStream.write(b);
oldOut.write(b);
}
};
System.setOut(new PrintStream(out));
LOGGER.debug("'System.out' is redirected to the console."); //$NON-NLS-1$
}
}, "Redirect system out to console...").start(); //$NON-NLS-1$
Still it would be good to change the Thread.sleep(5000); to some wait until the console is displayed...
specify the Terminal in the line:
Process p2 = Runtime.getRuntime().exec("gnome-terminal -x java two");
or
Process p2 = Runtime.getRuntime().exec("xterm -x java two");
this makes the program to run in the foreground otherwise it becomes an invisible process...