Does anyone know if it is possible to use selenium WebDriver (im using java) to check for messages in log files?
Currently the only way to know if an action in the front end of our system has completed is to ssh into our servers and wait for confirmation from the log files. This is how the process is tested manually but now I need to automate that test. Is it possible to use selenium to check this out?
My current method to achieve this seems overly complex:
Run actions in Front end
Launch shell Script to check log files from Selenium Test (includes ssh to server as logs are stored there)
Create "Action Completed" message in simple text file on server if logs show action is completed otherwise show "Action NOT completed"
scp file back to my machine/VM
read in file to eclipse
Create method in test to check contents of file something like if ("Action completed" message is returned -> continue) else (repeat from bullet point 2)
Is there a simpler way???
Self Answer - After considering all the posts, this is the solution I came up with that works really well. I have wirtten a method which allows me to parse the logs using regex right from Eclipse. Below is the code with heavy commenting to show what I have done....
public void checkLogs() throws IOException{
//create an empty string to hold the output
String s = null;
// using the process API and runtime exec method to directly ssh in the client machine and run any command you like. I need the live logs so I used tail -f
Process p = Runtime.getRuntime().exec("ssh user#ipaddress tail -f /location/file");
// use buffered reader to bring the output of the command run on the clinet machine back to the output in eclipse. I also created an output for the error stream to help with debugging if the commands dont work as I am not directly looking at the output when I run the commands on the client machine
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
// For my test I only want to continue with the clicks in the front end once I know the system has been reset. For our system this can only be checked in the logs. So I created a boolean flag which will only become true once the regex I run matches lines from the output. Use a while loop with != null to check every line of the output
boolean requestArrived = false;
while ((s = stdInput.readLine()) != null) {
System.out.println(s); // so I can see live what is happening. (great for debugging)
//search for the specific string that lets me know the system has been started the reset. (can run any regex here)
if(r.equalsIgnoreCase("system reset request received")){
System.out.println("***********************************************************************************************");
// Change the state of the boolean flag to true as we know now that the backend is ready to continue
requestArrived = true;
}
if(t.equalsIgnoreCase("System reset has happened successfully"))// a secondary check to see when the system is ready to continue{
System.out.println("##############################################################################################");
//if both string that we are looking for have been received we can continue with the rest of the script
if (requestArrived) {
break;
}
}
}
//close the terminal
p.destroy();
}
I hope that helps someone :)
Add a special page to your site that tails the logfile. Have a shared secret that selenium knows and the site if you need to keep the logfile confidential. Then just visit that page and use the usual methods to check for strings
There may be some permissions problems to overcome: normally web applications shouldn't be able to see the logs.
With the present solution you describe, Selenium is not really the right tool for the job (even though you could probably find a solution).
I can see several possible approaches:
Add a page that shows the progress (as suggested by Vorsprung). This could be a separate page, or some message in the existing GUI. This could be only for Selenium, or maybe it could even become a proper feature for all users (or only for administrators), if it makes sense for your system.
Use a system like you describe, but run the server on the local system (as a special test instance). Then you can skip the SSHing.
Create some service (REST or similar) on the server to query job status. Again, this may be useful for more than just testing.
What makes sense depends on how the system is used (how users currently check whether a job has completed, what information about a job is interesting, etc.).
EDIT: I misread your question, As you were asking for a simpler solution, but I tried to provide solution for the complex approach. Anyways I hope it will be useful.
Actual Answer:
I had done following activity for my project
clear logs using a shell script on remote unix server
Perform front end activity
capture logs after predefined time (say, 60 seconds )
SFtp back to client machine
first you will need an SFTP client and SSH client to interact with unix server
here Node is an object containing Unix env details. so change accordingly.
Using JSch lib for this
public static String runCommand(String Command, Node node )
{
String output = null;
if (node.getConnType().equals("SSH")){
int exitStatus = 0;
try{
JSch jsch=new JSch();
JSch.setConfig("StrictHostKeyChecking", "no");
Session session=jsch.getSession(node.getUserName(), node.getHost(), 22);
session.setPassword(node.getPassword());
session.setConfig("PreferredAuthentications",
"publickey,keyboard-interactive,password");
session.connect();
String command=Command;
Channel channel=session.openChannel("exec");
((ChannelExec)channel).setCommand(command);
channel.setInputStream(null);
((ChannelExec)channel).setErrStream(System.err);
InputStream in=channel.getInputStream();
channel.connect();
byte[] tmp=new byte[1024];
while(true){
while(in.available()>0){
int i=in.read(tmp, 0, 1024);
if(i<0)break;
output = new String(tmp, 0, i);
}
if(channel.isClosed()){
if(in.available()>0) continue;
exitStatus= channel.getExitStatus();
//System.out.println("exit-status: "+exitStatus);
break;
}
try{Thread.sleep(1000);}catch(Exception ee){}
}
channel.disconnect();
session.disconnect();
}
catch(Exception e){
e.printStackTrace();
}
if (exitStatus == 0)
{
if(output != null)
return output.replaceAll("[\\n\\r]", "");
}
}
return null;
}
SFTP client
public boolean transferFileSFTP(Node node,String srcDir,String targetDir,String srcFileName,String targetFileName, String direction)
{
JSch jsch = new JSch();
Session session = null;
try {
session = jsch.getSession(node.getUserName(), node.getHost(), 22);
session.setConfig("StrictHostKeyChecking", "no");
session.setConfig("PreferredAuthentications",
"publickey,keyboard-interactive,password");
session.setPassword(node.getPassword());
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
ChannelSftp sftpChannel = (ChannelSftp) channel;
System.out.println("src:" + srcDir+srcFileName );
System.out.println("target:" + targetDir+targetFileName );
sftpChannel.get(targetDir+targetFileName, srcDir+srcFileName);
sftpChannel.exit();
session.disconnect();
return true;
} catch (JSchException e) {
e.printStackTrace();
} catch (SftpException e) {
e.printStackTrace();
}
return false;
}
Now,
To wait until desired time and make it thread based to collect logs simultaneously from different applications involved,
using ExecutorService and Future<String> utilities
So created one LogCollector class which will initiate request and another is ThreadClass(logical) which will perform activities on log file.
LogCollector.java
public class LogCollector {
private static ExecutorService pool = Executors.newFixedThreadPool(100);
private static List<Future<String>> list = new ArrayList<Future<String>>();
public static void add(Node node, String srcDir, String targetDir, String srcFileName, String targetFileName, long wait )
{
list.add(pool.submit(new LogCollectorThread(System.currentTimeMillis()/1000,wait, srcDir, targetDir, srcFileName, targetFileName, node )));
}
public static void getResult()
{
try{
for (Future<String> future : list) {
String out =future.get();
//DO whatever you want to do with a response string return from your thread class
}
pool.shutdown();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
LogCollectorThread.java
public class LogCollectorThread implements Callable<String>{
long startTime;
long wait;
String srcFileName;
String targetFileName;
String srcDir;
String targetDir;
Node node;
public LogCollectorThread(long startTime, long wait,String srcDir, String targetDir,String srcFileName, String targetFileName,
Node node) {
super();
this.startTime = startTime;
this.wait = wait;
this.srcFileName = srcFileName;
this.targetFileName = targetFileName;
this.srcDir = srcDir;
this.targetDir = targetDir;
this.node = node;
}
/***
* Returns a String with Parameters separated by ',' and status at the end
* status values:
* 0 - successfully retrieved log file
* 1 - failure while retrieving log file
*/
#Override
public String call() throws Exception {
while((System.currentTimeMillis()/1000 - startTime)<=wait)
{
Thread.sleep(1000);
}
MyFTPClient sftp= new MyFTPClient();
boolean result =sftp.transferFileSFTP(this.node, this.srcDir, this.targetDir, this.srcFileName, this.targetFileName, "From");
System.out.println(this.node.getHost() + ","+ this.srcDir + ","+this.targetDir +","+ this.srcFileName +","+ this.targetFileName);
if(result == true)
return this.node.getHost() + ","+ this.srcDir + ","+this.targetDir +","+ this.srcFileName +","+ this.targetFileName +"," + "0" ;
else
return this.node.getHost() + ","+ this.srcDir + ","+this.targetDir +","+ this.srcFileName +","+ this.targetFileName +"," + "1" ;
}
}
How to use LogCollector classes:
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(Calendar.getInstance().getTime());
Helper.runCommand("cd /opt/redknee/app/crm/current/log/; echo > AppCrm.log", testEnv.getBSS());
LogCollector.add(testEnv.getBSS(), "collectedLogs\\", "/opt/redknee/app/crm/current/log/", timeStamp + "_" + testEnv.getBSS().getHost() + "_BSS_AppCrm.log" , "AppCrm.log", 60);
//So your thread is working now, so now perform your Front End Activity
//After 60 seconds, log file will be SFTPed to client host
//You can perform you activity before adding logCollectorThread or just before that
LogCollector.getResult();
Here I have given too much code,
But it is too hard to describe each step line by line.
Main thing i wanted to prove is using java most of the things are possible.
It is upto you to decide how critical it is and is it worth doing.
Now coming to your exact requirement of searching for a particular string.
As you can see in logCollectorThread,
currently i am doing nothing but just waiting till 60 seconds to complete.
So here you can use runCommand to grep desired string from logs
you can use command like
grep -i "Action Completed" | grep -v 'grep' | wc -l
if it return 1, you found your string
Similarly you can check for failure message.
and return desired string from your thread and get it as result in threadCollector.getResult() method.
And Once file is FTPed to your client, parsing it for a particular string using Java would be very easy. StackOverflow will help you in that :)
declaimer: don't expect code to be fully working.
It will work but you have to put your efforts. your java knowledge will be needed to plug-in the missing pieces
To check the action got completed, checking server logs might be solution. But still in GUI, we could see visibility of some html elements or messages or java script variable or overriding javscript functions.
With the help of Selenium JavscriptExecutor, we can override alert method (refer example 21)similarly we can override onreadystatechange for the request/response completion.
JavaScript Window variables can be used to show the action completeness by checking after each ajax request.
We can use selenium wait to wait for an element to be visible, identify an element using xpath.
There are more tutorials available in the below link for element wait, typing in textbox and so on.
http://software-testing-tutorials-automation.blogspot.com/2014/05/selenium-webdriver-tutorials-part-two.html
Related
This question already has answers here:
Getting unwanted characters when reading command output from SSH server using JSch
(2 answers)
Closed 3 years ago.
jsch = new JSch();
session = jsch.getSession(userName, ip, 22);
session.setPassword(passWord);
session.connect();
channel = session.openChannel("shell");
expect = new Expect(channel.getInputStream(), channel.getOutputStream());
((ChannelShell) channel).setPtyType("dumb");
channel.connect();
System.out.println("After channel and expect");
if (expect.expect("#") > -1) {
output = "Connected";
} else {
output = "Unexpected Prompt";
System.out.println("Unexpected Prompt");
}
expect.send("top" + "\n");
Thread.sleep(3000);
System.out.println("inside top");
OutputStream out = channel.getOutputStream();
out.write(3); // send CTRL-C
out.flush();
System.out.println("exit1");
if (expect.expect("$") > -1) {
System.out.println("finding $");
contt = (expect.before);
if (contt != null && contt != "") {
output=StringUtils.replace(contt,"\"","");
System.out.println("afterline"+output);
} else {
contt="Error in Top Check";
System.out.println("Error in Top check");
}
} else {
System.out.println("oit");
}
While I am running this code, I am getting output
[H[J[mtop - 05:54:39 up 53 days, 15:21, 22 users, load average: 0.44, 0.80, 0.76[m[K
Tasks:[m[m 443 [mtotal,[m[m 1 [mrunning,[m[m 442 [msleeping,[m[m 0 [mstopped,[m[m 0 [mzombie[m[K
Cpu(s):[m[m 2.8%[mus,[m[m 0.8%[msy,[m[m 0.1%[mni,[m[m 95.9%[mid,[m[m 0.3%[mwa,[m
like these. I am getting unwanted characters along with it. How can I remove them?
These are ANSI escape codes that are normally interpreted by a terminal client to pretty print the output.
You get these, because you the JSch "shell" channel by default requests a pseudo terminal for the session. In general, its a bad idea to use a "shell" channel for automation.
But if you really have to for some reason, disable pseudo terminal by calling setPty:
channel.setPty(false);
But in 99% cases it's a bad idea. Trying to simulate a human is error prone. The human-interaction features of commands tend to change (get improved), what in turn will break your code, when the server gets updated.
You better ask new question about your ultimate goal (what do you want to use top for?), because you are likely on a wrong track.
Related questions:
Removing shell stuff (like prompts) from command output in JSch
Is there a simple way to get rid of junk values that come when you SSH using Python's Paramiko library and fetch output from CLI of a remote machine?
My requirement is to connect to remote machine via ssh using java . I am using jsch to do the same. I have a sequence of commands to be executed and each command execution depends on the output of the previous command.
Fox example, if I am executing:
ls -l
after login into my remote machine by calling:
runCommand(“ls -l\n”);
Based on the output I get from the above step I need to create a directory:
runCommand(“mkdir test\n”);
On executing this I am getting:
com.jcraft.jsch.JSchException: failed to send channel request
at com.jcraft.jsch.Request.write(Request.java:65)
at com.jcraft.jsch.RequestPtyReq.request(RequestPtyReq.java:76)
at com.jcraft.jsch.ChannelSession.sendRequests(ChannelSession.java:212)
at com.jcraft.jsch.ChannelShell.start(ChannelShell.java:44)
at com.jcraft.jsch.Channel.connect(Channel.java:152)
at com.apple.mailmove.ssh.ExecuteSecureShellCommand.runCommand(ExecuteSecureShellCommand.java:90)
at com.apple.mailmove.ssh.ExecuteSecureShellCommand.main(ExecuteSecureShellCommand.java:160)
and here is the runCommad code:
//Find below my method
public void runCommand(String command)
{
try{
is = new ByteArrayInputStream(command.getBytes());
channel.setInputStream(is);
channel.setOutputStream(baos);
channel.connect(15 * 1000);
// Wait three seconds for this demo to complete (ie: output to be streamed to us).
Thread.sleep(3*1000);
for (int timeout = 200000; timeout > 0; timeout--)
{
if(baos.size() != 0)
{
System.out.println(baos.toString());
break;
}
else
{
System.out.println("No output!!!!");
Thread.sleep(5000); // wait a bit then try again
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
Checked the connection status with
channel.isConnected
method before channel.conenct(15*1000) is called and it displayed true. Once channel.conenct(15*1000) is called the channel connection status returns false.
I am not able to understand why the channel gets disconnected when channel.connect(15*1000) is called for the second time. Is there any other way to execute the commands one by one so that I could get the output of previous command and execute the second command?
For running one or more commands via SSH, I would recommend to use the exec channel that JSch provides. For a full example, see this page.
You'll have to change your code to create a new channel for each command that you want to run:
public void runCommand(String command) {
ChannelExec channel = (ChannelExec)session.openChannel("exec");
channel.setCommand(command);
try (InputStream stdOut = channel.getInputStream();
InputStream stdErr = channel.getErrStream()) {
channel.connect(TIMEOUT);
// read from stdOut and stdErr
}
channel.disconnect();
}
I am making a game with LibGDX, now I am trying to restart the game by re-running the jar, for that I am using the jar's path, finding it by using:
String location = new File(DesktopLauncher.class
.getProtectionDomain().getCodeSource().getLocation()
.getPath()).toString().replace("%20", " ");
After using that I attempt to restart using a Process and the Runtime.getRuntime().exec("java -jar " + location + "\\Test.jar");
Now that far it works, but the problem is that the first instance of the game from which I create the new instance (from which I restart), remains on the screen and won't close until the second instance closes.
This is my code for the restart:
public static void restart() {
Gdx.app.exit();
try {
String location = new File(DesktopLauncher.class
.getProtectionDomain().getCodeSource().getLocation()
.getPath()).toString().replace("%20", " ");
System.out.println(location);
Process pro = Runtime.getRuntime().exec(
"java -jar " + location + "\\Test.jar");
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(
"reprot.txt")));
InputStream stream = pro.getErrorStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(
stream));
String line = "";
writer.write(location);
while ((line = reader.readLine()) != null) {
writer.write(line);
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Am I doing something wrong? How can I close the first instance of the game after starting the second instance?
I tried doing it using a different thread, having this code:
public static void main(String[] args) {
try {
String location = new File(DesktopLauncher.class
.getProtectionDomain().getCodeSource().getLocation()
.getPath()).toString();
System.out.println(location);
Process pro = Runtime.getRuntime().exec(
"java -jar " + location + "\\Test.jar");
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(
"report.txt")));
InputStream stream = pro.getErrorStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(
stream));
String line = "";
writer.write(location);
while ((line = reader.readLine()) != null) {
writer.write(line);
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
But it still has the same problem.
EDIT: I tried to used System.exit(0);, and try to use the LwjglApplication to close it but it remains the same, however I have made some progress:
When creating this new process, the second instance of the game, the first instance's UI freezes, causing the game not to respond. I thought, well if it doesn't respond I should just find a way to kill it off and leave the other instance, but that can't be accomplished due to the fact that when closing once instance of the game (by forcing a close on it), you close both instances.
I think I figured out a piece of this annoying puzzle:
Let's say our main instance of the game is called 'Game_1', and the instance that we're creating is 'Game_2'.
After looking at the code and thinking about what happens (with testing of small classes and not the large game), I think that that the 'Game_1' isn't closing because 'Game_2' isn't closing.
In more complex terms, the instance of 'Game_1' won't close because it is somehow attached to 'Game_2' and thus is waiting for 'Game_2' to close before it itself will close.
So if that correct, the way to close 'Game_1' would to make 'Game_2' run simultaneously to 'Game_1' making it independent and thus allowing 'Game_1' to continue with the current progress of the code, which will be the implementation of Gdx.app.exit(); method.
So now the question remains, how do I make the instance of 'Game_2' run independently from 'Game_1'? Or how would I make 'Game_1' continue the code or, not to wait till an exit value will be received from 'Game_2'.
EDIT2: MASSIVE PROGRESS After adding a line of code System.exit(0); in the restart class, 'Game_1' continued not to respond, BUT after terminating 'Game_1', 'Game_2' did not get turned off, I'll continue to play around with it until I figure out what to do.
EDIT3: I continue to try and fix it so it'll work, but have ran into another problem. I figured out that if I can simulate an exit value for the process of 'Game_2' without actually exiting, I can terminate 'Game_1' 's UI, while keeping game 2 still alive, if anyone has any ideas please share them with me.
EDIT4: I continue my attempts to do this, but I can't follow what's going on, I'm trying to pass a PID to the restart class by writing
"java -cp " + location + "\\Test.jar Restart " + PID but it doesn't seem to work, or I don't seem to receive any information (syso for example) from the Restart class. On top of that I have found a memory leak inside my game that I will address once I finish working this out.
Please, if you have any idea how to help me, even just a theory, please share it.
EDIT5: I have established the efficiency of the termination of a given process using this LINK
Here is the solution, since I can't answer my problem until tomorrow:
Alright, finally, I finished solving it, it has a few problems, only two of them I will mention since it concerns the code in general and not how I'm using it. 'Game_1' will be the game that was started first, and 'Game_2' will be the instance of the restarted game. This is it:
First off I got the PID of the current process that is currently running, 'Game_1', from which I will create 'Game_2'. The problem with this is that Java applications all have the same name, 'Java.exe', and what that causes is a bunch of applications of the same name, so for now I add a message saying that the game should be the only java instance on the computer, not eclipse, or anything like that.
The code for the PID retrieval is this:
private static String getPID() {
try {
String line;
Process p = Runtime.getRuntime().exec(
System.getenv("windir") + "\\system32\\" + "tasklist.exe");
BufferedReader input = new BufferedReader(new InputStreamReader(
p.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line);
if (line.contains("java")) {
String data = line.subSequence(27, 35).toString();
data = data.trim();
return data;
}
}
input.close();
} catch (IOException e) {
e.printStackTrace();
}
return "-1";
}
Now, later on, I will look for a way to name the process that is currently running, so that you won't have to use line.contains("java") since it might give more than one instance, but for now it's as good as it gets.
This code uses an exe file inside of windows that basically gives all the current processes running on the computer, so you can find your.
The returned list is given in this format:
Image Name PID Session Name Session# Mem Usage
========================= ======== ================ =========== ============
All the processes will be located here.
The PID is located between the 27th character to the 35th, and that's why I added
String data = line.subSequence(27, 35).toString();
so that it returns the PID of the process.
After doing that I prepared a cmd with an execution command as follows:
String jarLocation = new File(YourClass.class.getProtectedDomain().getCodeSource().getLocation().getPath()).toString();
String command = "java -cp " + jarLocation + " your.Package.here.Restart \""+PID+"\"";
Runtime.getRuntime().exec("cmd /C start cmd.exe /C \"" + command + "\"");
Now first off I got the location of the .jar file. It is returned in the following format:
C:\A%20Folder\To%20YourJar\YourJar.jar
So there needs to be the following formatting to the location
jarLocation = jarLocation.replace("%20", " ");
Just to turn all the %20's to white spaces.
Note If you do not have spaces in your directory the previous step of formatting is not required.
After that I had prepared the actual command, which is as follows (this is for me, but you can change it to fit your needs).
java - calling the java program in cmd.
-cp - execute a class located inside of a jar file. Then I added the jar location, then added the package and added an argument (for the String[] args in the main method) of the PID to be terminated.
Now the following line of code represents a OS dependency, so if you want to add multiple OS support, I would recommend finding the equivalent to cmd in the other OS and figuring out how to use it.
The last line of code is the execution, where we get the runtime, start a cmd and execute a single command before closing the cmd.
You can find details about it in the following issue: LINK
#Vincent Ramdhanie also gives a link to commands you can run using runtime when activating cmd.
After that I had a class that was actually restarting the game itself, which is named Restart.
Like the last line of code, a line of code there represents OS dependency, so if you want to support multiple OS's, find the equivalent to taskkil in other OS's. According to #erhun it's pkill for Linux or something, sorry I don't exactly remember.
This is the code for that class:
public static void main(String[] args) {
try {
String location = new File(DesktopLauncher.class
.getProtectionDomain().getCodeSource().getLocation()
.getPath()).toString();
location = "\"" + location.replaceAll("%20", " ");
Runtime.getRuntime().exec("taskkill /F /PID " + args[0]);
Runtime.getRuntime().exec("java -jar " + location);
} catch (IOException e) {
e.printStackTrace();
}
}
Like with the previous line, location here means the same thing as before, and you have to format it if you have spaces in the directory.
After that you need to terminate the previous process, that is where taskkill /F /PID + args[0] comes in. If you run that you will terminate the task with the id of args[0], which was 'Game_1' 's PID.
After that I just run the jar file and you're good to go.
I would like to note something, I tried running it so that the main class (DesktopLauncher) would use the Restart class through an exec command in runtime, but the problem presisted, and I found that the only way to fix this, was to work around it, and use cmd. (This was after using cmd to debug the location string).
That's it, I worked a whole week, trying to fix this problem, and as crude as this is, it's a solution, for the mean time. If I have a problem somewhere in this code please tell me.
There is a much 'easier' method to do what you want. You will of course have to adapt to your own application as what you are trying to do is completely outside of libgdx's scope. It is a cross-platform library and the idea update/restart is very different with mobile.
An actual desktop cross-platform solution can be found here, I would highly suggest you not use your method as it is not a reliable solution and very platform specific.
Below is an example of how you would do it in libgdx. You need two things, code to launch the application and code to restart it.
Launcher:
public class TestLauncher {
public static void main(final String[] args) {
final LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.title = "Game";
cfg.width = 1280;
cfg.height = 720;
cfg.backgroundFPS = 12;
cfg.foregroundFPS = 60;
final Runnable rebootable = new Runnable() {
#Override public void run() {
if (Gdx.app != null) {
Gdx.app.exit();
}
TestLauncher.restart();
}
};
new LwjglApplication(new RebootTest(rebootable), cfg);
}
public static void restart() {
final StringBuilder cmd = new StringBuilder();
cmd.append(System.getProperty("java.home") + File.separator + "bin" + File.separator + "java ");
for (final String jvmArg : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
cmd.append(jvmArg + " ");
}
cmd.append("-cp ").append(ManagementFactory.getRuntimeMXBean().getClassPath()).append(" ");
cmd.append(TestLauncher.class.getName()).append(" ");
try {
Runtime.getRuntime().exec(cmd.toString());
} catch (final IOException e) {
e.printStackTrace();
}
}
}
Sample Game Code:
public class RebootTest implements ApplicationListener {
private final Runnable rebootHook;
private Stage stage;
private Skin skin;
public RebootTest(final Runnable rebootHook) {
this.rebootHook = rebootHook;
}
#Override public void create() {
this.stage = new Stage();
this.skin = new Skin(Gdx.files.internal("skin/uiskin.json"));
final Table table = new Table();
table.setFillParent(true);
final TextButton button = new TextButton("Reboot", this.skin);
button.addListener(new ClickListener() {
#Override public void clicked(final InputEvent event, final float x, final float y) {
Gdx.app.postRunnable(RebootTest.this.rebootHook);
}
});
table.add(button).expand().size(120, 40);
this.stage.addActor(table);
Gdx.input.setInputProcessor(this.stage);
}
#Override public void resize(final int width, final int height) {}
#Override public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
this.stage.act();
this.stage.draw();
}
#Override public void pause() {}
#Override public void resume() {}
#Override public void dispose() {
if (this.stage != null) {
this.stage.dispose();
}
if (this.skin != null) {
this.skin.dispose();
}
}
}
InetAddress byName = InetAddress.getByName("173.39.161.140");
System.out.println(byName);
System.out.println(byName.isReachable(1000));
Why does isReachable return false? I can ping the IP.
The "isReachable" method has not been worthy of using for me in many cases. You can scroll to the bottom to see my alternative for simply testing if you're online and capable of resolving external hosts (i.e. google.com) ... Which generally seems to work on *NIX machines.
The issue
There is alot of chatter about this :
Here are other, similar questions :
Detect internet Connection using Java
How do I test the availability of the internet in Java?
And even a reported bug on this same matter :
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4921816
Part 1 : A reproducible example of the problem
Note that in this case, it fails.
//also, this fails for an invalid address, like "www.sjdosgoogle.com1234sd"
InetAddress[] addresses = InetAddress.getAllByName("www.google.com");
for (InetAddress address : addresses) {
if (address.isReachable(10000))
{
System.out.println("Connected "+ address);
}
else
{
System.out.println("Failed "+address);
}
}
//output:*Failed www.google.com/74.125.227.114*
Part 2 : A Hackish Workaround
As an alternative, you can do this :
// in case of Linux change the 'n' to 'c'
Process p1 = java.lang.Runtime.getRuntime().exec("ping -n 1 www.google.com");
int returnVal = p1.waitFor();
boolean reachable = (returnVal==0);
The -c option of ping will allow ping to simply try to reach the server once(as opposed to the infinite ping which we're used to using at the terminal).
This will return 0 if the host is reachable. Otherwise, you will get "2" as a return value.
Much simpler - but of course it is platform specific.
And there may be certain privilege caveats to using this command - but I find it works on my machines.
PLEASE Note that :
1) This solution is not production quality. Its a bit of a hack. If google is down, or your internet is temporarily slow, or maybe even if there is some funniness in your privileges/system settings, if could return false negatives (i.e. it could fail even though the input address is reachable).
2) The isReachable failure is an outstanding issue. Again - there are several online resources indicating that there is no "perfect" way of doing this at the time of this writing, due to the way the JVM tries to reach hosts - I guess it is an intrinsically platform specific task which, although simple, hasn't yet been abstracted sufficiently by the JVM.
I came here to get an answer for this same question, but I was unsatisfied by any of the answers because I was looking for a platform independent solution. Here is the code which I wrote and is platform independent, but requires information about any open port on the other machine (which we have most of the time).
private static boolean isReachable(String addr, int openPort, int timeOutMillis) {
// Any Open port on other machine
// openPort = 22 - ssh, 80 or 443 - webserver, 25 - mailserver etc.
try {
try (Socket soc = new Socket()) {
soc.connect(new InetSocketAddress(addr, openPort), timeOutMillis);
}
return true;
} catch (IOException ex) {
return false;
}
}
Update: Based on a recent comment to this answer, here is a succinct version of the above code:
private static boolean isReachable(String addr, int openPort, int timeOutMillis) {
// Any Open port on other machine
// openPort = 22 - ssh, 80 or 443 - webserver, 25 - mailserver etc.
try (Socket soc = new Socket()) {
soc.connect(new InetSocketAddress(addr, openPort), timeOutMillis);
return true;
} catch (IOException ex) {
return false;
}
}
If you only want to check if it is connected to internet use this method , It returns true if internet is connected, Its preferable if you use the address of the site you are trying to connect through the program.
public static boolean isInternetReachable()
{
try {
//make a URL to a known source
URL url = new URL("http://www.google.com");
//open a connection to that source
HttpURLConnection urlConnect = (HttpURLConnection)url.openConnection();
//trying to retrieve data from the source. If there
//is no connection, this line will fail
Object objData = urlConnect.getContent();
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
Just mentioning it explicitly since the other answers don't. The ping part of isReachable() requires root access on Unix. And as pointed out by bestsss in 4779367:
And if you ask why ping from bash doesn't, actually it does need as well. Do that ls -l /bin/ping.
Since using root was not an option in my case the solution was to allow access to port 7 in the firewall to the specific server I was interested in.
I am not sure what was the state when the original question was asked back in 2012.
As it stands now, ping will be executed as a root. Through the ping executable's authorization you will see the +s flag, and the process belonging to root, meaning it will run as root. run ls -liat on where the ping is located and you should see it.
So, if you run InetAddress.getByName("www.google.com").isReacheable(5000) as root, it should return true.
you need proper authorizations for the raw socket, which is used by ICMP (the protocol used by ping)
InetAddress.getByName is as reliable as ping, but you need proper permissions on the process to have it running properly.
Since you can ping the computer, your Java process should run with sufficient privileges to perform the check. Probably due to use of ports in the lower range. If you run your java program with sudo/superuser, I'll bet it works.
I would suggest that the ONLY reliable way to test an internet connection is to actually connect AND download a file, OR to parse the output of an OS ping call via exec(). You cannot rely on the exit code for ping and isReachable() is crap.
You cannot rely on a ping exit code as it returns 0 if the ping command executes correctly. Unfortunately, ping executes correctly if it can't reach the target host but gets a "Destination host unreachable" from your home ADSL router. This is kind of a reply that gets treated as a successfull hit, thus exit code = 0. Have to add though that this is on a Windows system. Not checked *nixes.
private boolean isReachable(int nping, int wping, String ipping) throws Exception {
int nReceived = 0;
int nLost = 0;
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("ping -n " + nping + " -w " + wping + " " + ipping);
Scanner scanner = new Scanner(process.getInputStream());
process.waitFor();
ArrayList<String> strings = new ArrayList<>();
String data = "";
//
while (scanner.hasNextLine()) {
String string = scanner.nextLine();
data = data + string + "\n";
strings.add(string);
}
if (data.contains("IP address must be specified.")
|| (data.contains("Ping request could not find host " + ipping + ".")
|| data.contains("Please check the name and try again."))) {
throw new Exception(data);
} else if (nping > strings.size()) {
throw new Exception(data);
}
int index = 2;
for (int i = index; i < nping + index; i++) {
String string = strings.get(i);
if (string.contains("Destination host unreachable.")) {
nLost++;
} else if (string.contains("Request timed out.")) {
nLost++;
} else if (string.contains("bytes") && string.contains("time") && string.contains("TTL")) {
nReceived++;
} else {
}
}
return nReceived > 0;
}
nping is number of try to ping ip(packets), if you have busy network or systems choose biger nping numbers.
wping is time waiting for pong from ip, you can set it 2000ms
for using this method u can write this:
isReachable(5, 2000, "192.168.7.93");
Or using this way:
public static boolean exists(final String host)
{
try
{
InetAddress.getByName(host);
return true;
}
catch (final UnknownHostException exception)
{
exception.printStackTrace();
// Handler
}
return false;
}
InetAddress.isReachable is flappy, and sometimes returns unreachable for addresses which we can ping.
I tried the following:
ping -c 1 <fqdn> and check the exit status.
Works for all the cases i had tried where InetAddress.isReachable doesn't work.
To Check Internet
public boolean isInternetAvailable() {
try {
InetAddress ipAddr = InetAddress.getByName("google.com");
//You can replace it with your name
return !ipAddr.equals("");
} catch (Exception e1) {
try {
Process p1 = java.lang.Runtime.getRuntime().exec("/system/bin/ping -W 1 -c 1 www.google.com");
int returnVal = 0;
returnVal = p1.waitFor();
boolean reachable = (returnVal==0);
return reachable;
} catch (Exception e2) {
e2.printStackTrace();
return false;
}
}
}
To check network connectivity
private boolean isNetworkConnected() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
}
Because isReachable is using the TCP protocol(by WireShark) The Ping command is using ICMP protocol,if you want to return true you need to open the 7 port
I want to test whether a remote system is reachable using Java or in other words "send a ping" using Java. This functionality should be encapsulated in a method with boolean value, for example
public boolean isReachable(String ip) {
// what to do :-)
}
I've tested the Java Process class, but I don't think that it is the best way to do this, because of the complex output handling with OutputBuffers.
Process proc = Runtime.getRuntime().exec("ping " + ip);
Another possibility would be creating a Socket Connection and handle thrown exceptions, but if the remote system is a "naked" unix system, there might be no Socket on the other side :-) Additionally, I'd like to be able to set a timeout, when a remote system is not reachable.
So how could I do this? Thank you!
InetAddress.getByName(ip).isReachable(timeout);
InetAddress.getByName(host).isReachable(timeOut) (seen here)
It looks like you are using Linux so you will probably find that isReachable() is unreliable (because you will not have permissions to send ICMP packets, and very few servers have the Echo service running).
If that is the case then I think you will need to use spawn a Process in the way you suggest, but I recommend using a command like:
ping -c 1 hostname
This will terminate after one attempt and you can then examine the exit status of the process - much more reliable than parsing standard output.
Ping returns 0 for success non-zero on failure.
I think isReachable() can't be used as reliable option. Better pure java option I think will be something like this:
private static boolean isReachable(String host, int openPort, int timeOutMillis) {
try {
try (Socket soc = new Socket()) {
soc.connect(new InetSocketAddress(host, openPort), timeOutMillis);
}
return true;
} catch (IOException ex) {
return false;
}
}
And if you want to check if host is accessible via web/browser here is it:
private static boolean hostsWebApp(String host, int timeOutMillis) {
boolean isReachable = isReachable(host, 80, timeOutMillis);
if(!isReachable) {
return isReachable(host, 443, timeOutMillis);
} else {
return true;
}
}
I know this question has found its answer but I'd like to add my code just for "copy-paste".
public boolean isIpReachable(String ip, int timeout){
boolean state = false;
try {
state = InetAddress.getByName(ip).isReachable(timeout);
} catch (IOException e) {
//Parse error here
}
return state;
}