Simulate network connectivity issues on Linux using Java - java

I would like to have an automated test for the following scenario:
User logs in and performs some "lengthy" operation. For example tries to upload a file.
In the middle of that lengthy operation, the connection to the server is lost for a period of time, and then restored.
Application does whatever it's supposed to do in this case. For example shows a message to the user asking if they want to retry.
I want steps 1. and 3. to be done by Selenium. Question is: how can I do the step 2. as part of the automated test?
Details on the tools and environment:
Selenium is on Java with Junit
Test must run on Linux and Windows
It will also run on 3 browsers: Firefox, Chrome, IE 11
Couple of solutions I was thinking about:
Call some script that manipulates a connection on the machine.
Manipulate proxy settings of the browser (proxy points to fake address, thus connection is broken).
Use a real proxy, which could be controlled from the code (e.g. by some commands), so it can behave as "working" or "broken" connection.
None of these solutions is ideal for various reasons.
So: did anyone try to solve a similar problem? Would like to hear your solution or alternative ideas, that you think may work. Thanks.

Option 1
Stubbing
You'll have to identify what would be the exception thrown and what will be the component that throws it in a real case scenario. You can do that easily, simulate the scenario in your machine and when the exception is thrown, the stack-trace will tell you exactly what component thrown it.
Then you'll have to extend the component that throws the exception and inject it in the proper place and, ultimately, create an API to trigger that exception.
If you think you need a framework to automate this kind of tests, have a look to to Fitnesse.
Option 2
Simulation
Simulating a real network problem, would be overly complicated and the benefits are not worth the effort in this case (imo).
Anyway... Linux has an excellent built in network emulation layer called netem that allows any kind of seamless interaction with the network traffic. This kernel module is controlled by the tc command line interface.
It's not very easy to get it right when you want to apply those condition to a single port because you'll have to:
Netfilter rule to mark the packets that we want to limit
Traffic Control policy
Filter to bind the packets to the policy
A simple example would be if you want to have 10% packet loss on the whole eth0, in which case you'll use:
tc qdisc change dev eth0 root netem loss 10%
Then you'll have to wrap this functionality in some java controllable way.
If I failed on discouraging you, here is a good guide: TrafficControl

You can execute the following commands on windows on cmd to disconnect and reconnect network.
> ipconfig /release
> ipconfig /renew
Using this you can use the Java Runtime class to execute the command.
Runtime.getRuntime().exec("ipconfig /release");
I have tested this on windows and it works.
The Linux equivalent of the cmd commands are as follows
> sudo ifconfig eth0 up
> sudo ifconfig eth0 down
Note that eth0 here is the name of my Ethernet connection. You can list the names of all the connections using
> ifconfig -a
You can look at the following thread to execute bash through Java - How to execute bash command with sudo privileges in Java?

Related

debugging multi process java applications

What is a good system for debugging a multi process Java application where it isn't clear which process should be debugged?
For example, in Python I can use rpdb and add the line import rpdb; rpdb.set_trace() so execution blocks until I connect to the debugger with e.g. nc 127.0.0.1 4444.
Compared to the above quick and reliable method, when I'm using a Java debugger, I see the following challenges:
Ensure that every process is run with proper arguments to allow debugging -- in my case it isn't clear what is starting all the processes so it isn't obvious where to change the arguments. Is there a way to change the defaults on my computer to always include the jvm options -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=1044?
Decide what process to connect the debugger to before the desired code is hit -- again, it isn't clear which process I should connect to, and it is convenient that rpdb blocks until the debugger connects and you don't need to identify the process id. Is there anything similar to this in Java?
Start java with something like:
java -agentlib:transport=dt_socket,server=y,suspend=y,address=1044
The suspend=y bit tells the VM to wait until a debugger connects before running main(). address is the port to connect to.

limiting the network bandwidth of a java process

Is there an efficient way to limit the bandwidth of a certain java process?
I am familiar with solutions like trickle to limit bandwidth of a certain process on run time
sudo trickle -s -d 1024 /path/to/app.sh
But when dealing with java processes it makes it more of a challenge because the application initiates a JVM or in some cases a WRAPPER service that initiates a JVM - that means that solutions like 'trickle' will not work.
I can try and limit (using trickle) the whole java process (by wrapping / messing up with /usr/bin/java s.link) - UGLY.
Does anyone know of a better solution for limiting the bandwidth of a java process (JVM)?
Thanks!
Unfortunately I don't think trickle can do it.
I have similar issue and I solved it via throttling bandwidth on a particular port. For example you application opens port 34567 to communicate, then you can apply firewall setting and throttle it down.
On a mac I am using "ipfw", example:
sudo ipfw pipe 1 config bw 5KByte/s
sudo ipfw add 2 pipe 1 src-port 6666
On linux I am using "tc", examples & source: http://www.cyberciti.biz/faq/linux-traffic-shaping-using-tc-to-control-http-traffic/
As a final solution, you can create bash script that monitors processes and picks ones you need and throws port throttling on it.
The question is not really clear.
Do you have control of the Java code? Otherwise, are you the System Administator?
If you are using a Java code you could use the Socket paradigm and then limit each socket connection by using the following method: setPerformancePreferences(int connectionTime, int latency, int bandwidth).
In the other case, the bandwidth limitation capability depends by the OS and the way the Java applications are executed.

How to up an aplication on remote linux and wait for answer

Someone can tell me the best way, through a web Java application, how to run an application on a remote machine (linux) and how to know if this application has already completed. I know the application terminates automatically, so just wanted to wait for the answer.
any help or advice are very welcome.
I was confused by the wording, so I will assume the following: the web application and the remote application are running on two different machines, with the remote application on Linux.
If that is the case, then you would be better off using a SSH library for Java (there are several - JSch, sshj, Ganymed SSH-2, to connect to the remote machine and run commands on it. This is a better approach than using ProcessBuilder, for it abstracts you from the problem of providing your password to the terminal (which can get quite tricky).
I'm not sure what you meant by this statement: "I know the application terminates automatically, so just wanted to wait for the answer." so I'll make another assumption that you want to know if the remote process terminated successfully or not. I'm unsure if any of the SSH libraries posted above, will allow you to get the remote process status in a non-trivial way, so you are better off writing a shell wrapper to your remote command that will return a parseable message.
If you are running both on the same machine, use ProcessBuilder.

Emulating network disconnects to locally test distributed app partitioning

I have several instances of a distributed application running on the localhost; every instance communicate with others through certain ports, all instances together make an ensemble.
(I'm actually talking about ZooKeeper, running on Linux)
Now I want to write unit tests to emulate ensemble partitioning.
E.g. I have 5 instances, and I want to split them into two groups of 3 and 2 so that an instance from one group couldn't communicate to an instance from another group. It would emulate real-world situation when 3 machines are in one datacenter, 2 machines are in another one, and datacenters become partitioned.
The problem is essentially to make a socket work selectively: speak to one socket, but don't speak to another. One solution that comes to mind is to abstract communication layer and inject testing rules into it (in the form of "if I'm an instance from one group I'm not not allowed to speak to an instance from another group -- close socket or ignore data or whatever").
But maybe there exist some tools for this, maybe some testing framework?
In general, how do you test such cases in your distributed apps?
P.S. Though question is tagged with "java" (since ZooKeeper is written in Java), it'd be great to hear solutions for any other language, or language-independent ones -- maybe some linux guru-tricks.
Maybe this answer will save a few hours of googling for someone.
Linux has a very good firewall utility, iptables. It allows you to block communication between processes, like this:
iptables -A INPUT -p tcp --sport <source port> --dport <dest port> -j DROP
While not a full-blown unit testing framework by any measure, this helps a bit with manual testing in my case.
I would be tempted to say that this is integration testing rather than unit testing (or that it will be really hard to do proper unit testing of such thing).
The few times I needed to test such things, I've used virtualisation (e.g. VMWare) to test the system. You can test reboot, shutdown, etc. of nodes all from one physical machine running several images.
In the past I have disconnected network cables. You can always disable a network interface via the OS.
try blockade. https://github.com/dcm-oss/blockade
It's a docker based tool to emulate the behaviour you want. Runs on linux only, but there is a Vagrant file for setup if you want to run it from another OS.

How to run shell script on remote machine from Java?

I'm creating a test which will perform some stress testing of the app which talks to a Postgres database. In order to make it replicable I'd like to recreate the database on every run. Startup method decorated with org.junit.Before annotation will drop the database (if it exists) and restore it from a dump file. Doing this form shell/command is trivial:
psql -f db.out newdb
or something along these lines. Since the test may be performed on a JVM that's not running on the same machine which hosts the database I'm wondering if it's possible to invoke shell/batch script on remote machine from Java programmaticaly.
Thanks
If you have knowledge of the machine details (hostname, login, password) the only thing I can think of at the moment is using a Java SSH library to login to the box and run that command.
Or you could write a script on your local machine which ran the script on the remote machine given the correct parameters.
That's the simplest way I can think of anyway!
If setting up SSH is too complex, you can write a small Java program which listens for connections on a socket and then runs the script. Install that on the Postgres server and connect to it in the test case.
That said, I suggest to install a copy of Postgres on every developer machine. That would make your tests run much faster and you wouldn't get spurious errors when two developers run the tests at the same time. Also, you won't have errors because of network problems, because someone does maintenance on the server, because developer X has changed the DB schema, etc. etc.

Categories

Resources