Inconvenient Robot framework test case using websocket and jms - java

I'm having trouble rewriting java test cases in robot framework.
in order to do this, i need to create new java keywords, but the way tests are implemented, don't make it easy !
this is an example of script that i need to rewrite in RF :
try
{
ServerSocket server = Utils.startSocketServer;
while(true)
{
Socket socket = server.accept();
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
RequestX request = (RequestX) ois.readObject();
if(request.getSource().equals(String.INFO)
{
/** do something **/
}
else if(request.getSource().equals(String.X)
{
/** do something **/
}
else
{
/** do something **/
}
/** break on condition **/
}
Utils.closeSocketServer(server);
}catch(Exception e)
{
/** do something **/
}
Any suggestion on how i can make this into a RF test case !
Make the whole script into a single keyword is not an option because somewhere in that loop, in the do something comment, i also need to call keywords.
The main idea is to fragment this script into functions so that i can use them as java keywords in RF but i still can't figure this out!

So, i did further researches and this is what i came up with :
Split this code into functions so that i can call and use them as keywords in robot framework.
So code became like this :
public static String SendTask(String taskFile)
{
ServerSocket server = null;
try
{
server = startSocketServer();
if (taskFile != null)
{
Utils.sendJMSWakeUp();
while(true)
{
Socket socket = server.accept();
ObjectInputStream ois = getInputStream(socket);
RequestX request = (cast)ois.readObject();
if (getSource(request,Strings.INFO)
{
/** log info **/
}
/** if the current jms queue is Scheduler then send task !*/
else if (getSource(request,Strings.SCHEDULER))
{
/** send task **/
break;
}
}
}
else
{
assertion(false, "Illegal Argument Value null");
}
}catch (Exception e)
{
/** log errors **/
}finally
{
/** close socket server & return a task id **/
}
}
the same goes for every JMS queue that I am listening to
public static String getTaskAck(String taskId);
public static String getTaskresult(String taskId);
it did work in my case for synchronous task execution. But this is very incovenient for asynchronous task execution. Because each time i'll have to wait for response on keyword, so the next keyword may fail because the response that he is supposed to read was already sent !
i could look into process BuiltIn library or RobotFramework-Async library for parallel keyword execution but it will be harder to process for many asynchronous jms messages.
After further investigation, i think i will look into robotframework-jmsLibrary. some developpment enhancement has to be done like adding activeMq.
This way, i can send and consume many asynchronous messages via activeMq then process every message via robotframework-jmsLibrary
Example :
RF-jmsLibrary <==> synchronous <==> activeMq <==> asynchronous <==> system

Related

Junit and Spring 5 : All my classes should be multithreading tests expect one class, how can I achieve this? SSL handshake with concurrent

I'm working on a Spring 5 project and have some very special expectations with junit. Spring 5 now support junit multithreading and that definitely works very well, I'm now running my hundreds of tests into method parrallel multithreading. But I just setup recently my whole automatic mailing system which works like a charm but that's where it start to be problematic : I run a class that send all my mails to test them, and so they are being sent concurently. But as I just tried right now to test it with not only one email at a time but several, I get a strange SSL handshake error which I related to the fact that concurrent mail sending is not supported by most mail clients.
That's where goes my interrogation: how can I run all my test classes with parallel methods execution except for that email batch sending class?
Maybe I should think about a mail queue to avoid this kind of problem in live? Anyone has an idea?
By the way, in case you wonder I'm yet using gmail client to send mail as I didn't configured it yet for our live mail sending but it will be achieved using dedicated 1and1.fr smtp email client.
Thanks for your patience!
For those who feels interested about the solution, here is how I solved it:
I created a new Singleton class which would handle the queue :
public class EmailQueueHandler {
/** private Constructor */
private EmailQueueHandler() {}
/** Holder */
private static class EmailQueueHandlerHolder
{
/** unique instance non preinitialized */
private final static EmailQueueHandler INSTANCE = new EmailQueueHandler();
}
/** access point for unique instanciation of the singleton **/
public static EmailQueueHandler getInstance()
{
return EmailQueueHandlerHolder.INSTANCE;
}
private List<EmailPreparator> queue = new ArrayList<>();
public void queue(EmailPreparator email) {
waitForQueueHandlerToBeAvailable();
queue.add(email);
}
public List<EmailPreparator> getQueue()
{
waitForQueueHandlerToBeAvailable();
List<EmailPreparator> preparators = queue;
queue = new ArrayList<>();
return preparators;
}
// This method is used to make this handler thread safe
private synchronized void waitForQueueHandlerToBeAvailable(){}
}
I then created a CRON task using #Schedule annotation in my Scheduler bean in which I would correctly handle any mail sending fail.
#Scheduled(fixedRate = 30 * SECOND)
public void sendMailsInQueue()
{
List<EmailPreparator> queue = emailQueueHandler.getQueue();
int mailsSent = queue.size();
int mailsFailed = 0;
for(EmailPreparator preparator : queue)
{
try {
// And finally send the mail
emailSenderService.sendMail(preparator);
}
// If mail sending is not activated, mail sending function will throw an exception,
// Therefore we have to catch it and only throw it back if the email was really supposed to be sent
catch(Exception e)
{
mailsSent --;
// If we are not in test Env
if(!SpringConfiguration.isTestEnv())
{
mailsFailed ++;
preparator.getEmail().setTriggeredExceptionName(e.getMessage()).update();
// This will log the error into the database and eventually
// print it to the console if in LOCAL env
new Error()
.setTriggeredException(e)
.setErrorMessage(e.getClass().getName());
}
else if(SpringConfiguration.SEND_MAIL_ANYWAY_IN_TEST_ENV || preparator.isForceSend())
{
mailsFailed ++;
throw new EmailException(e);
}
}
}
log.info("CRON Task - " + mailsSent + " were successfuly sent ");
if(mailsFailed > 0)
log.warn("CRON Task - But " + mailsFailed + " could not be sent");
}
And then I called this mail queue emptyer methods at the end of each unit test in my #After annotated method to make sure it's called before I unit test the mail resulted. This way I'm aware of any mail sending fail even if it appear in PROD env and I'm also aware of any mail content creation failure when testing.
#After
public void downUp() throws Exception
{
proceedMailQueueManuallyIfNotAlreadySent();
logger.debug("After Test");
RequestHolder requestHolder = securityContextBuilder.getSecurityContextHolder().getRequestHolder();
// We check mails sending if some were sent
if(requestHolder.isExtResultsSent())
{
for(ExtResults results : requestHolder.getExtResults())
{
ExtSenderVerificationResolver resolver =
new ExtSenderVerificationResolver(
results,
notificationParserService
);
resolver.assertExtSending();
}
}
// Some code
}
protected void proceedMailQueueManuallyIfNotAlreadySent()
{
if(!mailQueueProceeded)
{
mailQueueProceeded = true;
scheduler.sendMailsInQueue();
}
}

Vertx http server Thread has been blocked for xxxx ms, time limit is 2000

i have written a large scale http server using , but im getting this error when number of concurrent requests increases
WARNING: Thread Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 8458 ms, time limit is 1000
io.vertx.core.VertxException: Thread blocked
here is my full code :
public class MyVertxServer {
public Vertx vertx = Vertx.vertx(new VertxOptions().setWorkerPoolSize(100));
private HttpServer server = vertx.createHttpServer();
private Router router = Router.router(vertx);
public void bind(int port){
server.requestHandler(router::accept).listen(port);
}
public void createContext(String path,MyHttpHandler handler){
if(!path.endsWith("/")){
path += "/";
}
path+="*";
router.route(path).handler(new Handler<RoutingContext>() {
#Override
public void handle(RoutingContext ctx) {
String[] handlerID = ctx.request().uri().split(ctx.currentRoute().getPath());
String suffix = handlerID.length > 1 ? handlerID[1] : null;
handler.Handle(ctx, new VertxUtils(), suffix);
}
});
}
}
and how i call it :
ver.createContext("/getRegisterManager",new ProfilesManager.RegisterHandler());
ver.createContext("/getLoginManager", new ProfilesManager.LoginHandler());
ver.createContext("/getMapcomCreator",new ItemsManager.MapcomCreator());
ver.createContext("/getImagesManager", new ItemsManager.ImagesHandler());
ver.bind(PORT);
how ever i dont find eventbus() useful for http servers that process send/receive files , because u need to send the RoutingContext in the message with is not possible.
could you please point me to the right direction? thanks
added a little bit of handler's code:
class ProfileGetter implements MyHttpHandler{
#Override
public void Handle(RoutingContext ctx, VertxUtils utils, String suffix) {
String username = utils.Decode(ctx.request().headers().get("username"));
String lang = utils.Decode(ctx.request().headers().get("lang"));
display("profile requested : "+username);
Profile profile = ProfileManager.FindProfile(username,lang);
if(profile == null){
ctx.request().response().putHeader("available","false");
utils.sendResponseAndEnd(ctx.response(),400);
return;
}else{
ctx.request().response().putHeader("available","true");
utils.writeStringAndEnd(ctx, new Gson().toJson(profile));
}
}
}
here ProfileManager.FindProfile(username,lang) does a long running database job on the same thread
...
basically all of my processes are happening on the main thread , because if i use executor i will get strange exceptions and nullpointers in Vertx , making me feel like the request proccessors in Vertx are parallel
Given the small amount of code in the question lets agree that the problem is on the line:
Profile profile = ProfileManager.FindProfile(username,lang);
Assuming that this is internally doing some blocking JDBC call which is a anti-pattern in Vert.x you can solve this in several ways.
Say that you can totally refactor the ProfileManager class which IMO is the best then you can update it to be reactive, so your code would be like:
ProfileManager.FindProfile(username,lang, res -> {
if (res.failed()) {
// handle error, sent 500 back, etc...
} else {
Profile profile = res.result();
if(profile == null){
ctx.request().response().putHeader("available","false");
utils.sendResponseAndEnd(ctx.response(),400);
return;
}else{
ctx.request().response().putHeader("available","true");
utils.writeStringAndEnd(ctx, new Gson().toJson(profile));
}
}
});
Now what would be hapening behind the scenes is that your JDBC call would not block (which is tricky because JDBC is blocking by nature). So to fix this and you're lucky enough to use MySQL or Postgres then you could code your JDBC against the async-client if you're stuck with other RDBMS servers then you need to use the jdbc-client which in turn will use a thread pool to offload the work from the event loop thread.
Now say that you cannot change the ProfileManager code then you can still off load it to the thread pool by wrapping the code in a executeBlocking block:
vertx.executeBlocking(future -> {
Profile profile = ProfileManager.FindProfile(username,lang);
future.complete(profile);
}, false, res -> {
if (res.failed()) {
// handle error, sent 500 back, etc...
} else {
Profile profile = res.result();
if(profile == null){
ctx.request().response().putHeader("available","false");
utils.sendResponseAndEnd(ctx.response(),400);
return;
}else{
ctx.request().response().putHeader("available","true");
utils.writeStringAndEnd(ctx, new Gson().toJson(profile));
}
}
});

Apache Camel creating Consumer component

I'm newbie to Apache Camel. In hp nonstop there is a Receiver that receives events generated by event manager assume like a stream. My goal is to setup a consumer end point which receives the incoming message and process it through Camel.
Another end point I simply need to write it in logs. From my study I understood that for Consumer end point I need to create own component and configuration would be like
from("myComp:receive").to("log:net.javaforge.blog.camel?level=INFO")
Here is my code snippet which receives message from event system.
Receive receive = com.tandem.ext.guardian.Receive.getInstance();
byte[] maxMsg = new byte[500]; // holds largest possible request
short errorReturn = 0;
do { // read messages from $receive until last close
try {
countRead = receive.read(maxMsg, maxMsg.length);
String receivedMessage=new String(maxMsg, "UTF-8");
//Here I need to handover receivedMessage to camel
} catch (ReceiveNoOpeners ex) {
moreOpeners = false;
} catch(Exception e) {
moreOpeners = false;
}
} while (moreOpeners);
Can someone guide with some hints how to make this as a Consumer.
The 10'000 feet view is this:
You need to start out with implementing a component. The easiest way to get started is to extend org.apache.camel.impl.DefaultComponent. The only thing you have to do is override DefaultComponent::createEndpoint(..). Quite obviously what it does is create your endpoint.
So the next thing you need is to implement your endpoint. Extend org.apache.camel.impl.DefaultEndpoint for this. Override at the minimum DefaultEndpoint::createConsumer(Processor) to create your own consumer.
Last but not least you need to implement the consumer. Again, best ist to extend org.apache.camel.impl.DefaultConsumer. The consumer is where your code has to go that generates your messages. Through the constructor you receive a reference to your endpoint. Use the endpoint reference to create a new Exchange, populate it and send it on its way along the route. Something along the lines of
Exchange ex = endpoint.createExchange(ExchangePattern.InOnly);
setMyMessageHeaders(ex.getIn(), myMessagemetaData);
setMyMessageBody(ex.getIn(), myMessage);
getAsyncProcessor().process(ex, new AsyncCallback() {
#Override
public void done(boolean doneSync) {
LOG.debug("Mssage was processed " + (doneSync ? "synchronously" : "asynchronously"));
}
});
I recommend you pick a simple component (DirectComponent ?) as an example to follow.
Herewith adding my own consumer component may help someone.
public class MessageConsumer extends DefaultConsumer {
private final MessageEndpoint endpoint;
private boolean moreOpeners = true;
public MessageConsumer(MessageEndpoint endpoint, Processor processor) {
super(endpoint, processor);
this.endpoint = endpoint;
}
#Override
protected void doStart() throws Exception {
int countRead=0; // number of bytes read
do {
countRead++;
String msg = String.valueOf(countRead)+" "+System.currentTimeMillis();
Exchange ex = endpoint.createExchange(ExchangePattern.InOnly);
ex.getIn().setBody(msg);
getAsyncProcessor().process(ex, new AsyncCallback() {
#Override
public void done(boolean doneSync) {
log.info("Mssage was processed " + (doneSync ? "synchronously" : "asynchronously"));
}
});
// This is an echo server so echo request back to requester
} while (moreOpeners);
}
#Override
protected void doStop() throws Exception {
moreOpeners = false;
log.debug("Message processor is shutdown");
}
}

Java Client Server Programming: How to pass message from server to All Client threads?

I am creating a program with a server A and multiple clients B, C, D.
B C & D will all message the client with a number X, and I would like to know how it is possible for the server to message ALL clients simultaneously with the latest value for X?
As it stands, it will update only the client who has last passed number X.
Here is the code I have for run()
public void run(){
String number;
do
{
//Accept message from client on
//the socket's input stream...
received = in.readLine();
//Echo message back to client on
//the socket's output stream...
out.println("Number recieved: " + number);
}
}
Google up JMS Publish and Subscribe.
Basically:
The server publishes to a topic and the clients subscribe to a topic.
The best way to notify clients about something is to use JMX. If you're not supposed to use this technology, then you should keep clients list somewhere in your code (say in static field) and then iterate over this list and send received number
I'm not sure what you're trying to do...but you could try broadcasting a message using socket programming. Check this out
You can add all the sockets to a collection. Send the same message to every socket in the collection. Remove sockets from the collection when they are closed.
e.g.
final List<Socket> sockets = new CopyOnWriteArrayList<Socket>();
// when you have a new socket
sockets.add(socket);
// when you have a dead socket.
sockets.remove(socket);
// to send the same message to multiple sockets.
public static void sendToAll(byte[] bytes) {
for(Socket s: sockets)
try {
s.getOutputStream().write(bytes);
} catch (IOException ioe) {
// handle exception, close the socket.
sockets.remove(s);
}
}
I agree the real solution is JMS, but if you want to "roll your own" a simple solution I would suggest is making your own simplified version using the same idea of JMS. Create a class that will receive events from your client. Create an interface that your clients can implement and then add themselves as a listener to this new class. Some simple code:
class MyEventPublisher {
Collection<EventListener> listeners;
int number;
public void addListener(EventListener listener) {
listeners.add(listener);
}
public void setNumber(int newNumber) {
int oldNumber = this.number;
this.number = newNumber;
for (EventListener listener : listeners) {
listener.numberChanged(newNumber, oldNumber);
}
}
}
interface EventListener {
void numberChanged(int newNumber, int oldNumber);
}
class MyClientSocket implements EventListener {
MyEventPublisher publisher;
public MyClientSocket(MyEventPublisher publisher) {
this.publisher = publisher;
publisher.addListener(this);
}
public recieveNumberFromSocket() {
int numberFromSocket = readNumber();
publisher.setNumber(numberFromSocket);
}
public void numberChanged(int newNumber, int oldNumber) {
//someone else changed the number
//do something interesting with it
}
}
You are looking for a multicast protocol, based on your descriptions.
So, I'll guess you'll be better of looking this:
Multicast (JDK 6)
Multicast (JDK 7)
Previous versions starting from JDK version 1.4.2 include multicast but you'll be better off if you use JDK version 6 or greater ;)

Create listener for server socket response?

I have a server-client pair and I want to create a listener on the client end for new server responses. I am not sure how to do this, right now I can only interact in a direct synchronous way.
Here is the server:
public class TestServer {
public static void main(String[] args) throws Exception {
TestServer myServer = new TestServer();
myServer.run();
}
private void run() throws Exception {
ServerSocket mySS = new ServerSocket(4443);
while(true) {
Socket SS_accept = mySS.accept();
BufferedReader myBR = new BufferedReader(new InputStreamReader(SS_accept.getInputStream()));
String temp = myBR.readLine();
System.out.println(temp);
if (temp!=null) {
PrintStream serverPS = new PrintStream(SS_accept.getOutputStream());
serverPS.println("Response received: " + temp);
}
}
}
}
As you can see, it sends a response when it gets one. However in general I won't be sure when other servers I use send responses, so I would like to create an asynchronous listener (or at least poll the server for a response every half-second or so).
Here is what I'm trying on the client end:
protected static String getServerResponse() throws IOException {
String temp;
try {
BufferedReader clientBR = new BufferedReader(new InputStreamReader(mySocket.getInputStream()));
temp = clientBR.readLine();
} catch (Exception e) {
temp = e.toString();
}
return temp;
}
And just for reference, yes, sending over data from client to server works fine (it System.out's the data correctly). However, when I call the above function to try and retrieve the server response, it just hangs my application, which is an Android application in case that's relevant.
What I want from a function is just the ability to ask the server if it has data for me and get it, and if not, then don't crash my damn app.
On the client side create a ConnectionManager class which will handle all the socket I/O. The ConnectionManager's connect() method will create and start a new thread which will listen for server responses. As soon as it will receive a response it will notify all the ConnectionManager's registered listeners. So in order to receive asynchronously the server responses you will have to register a listener in ConnectionManager using its register(SomeListener) method.
Also, you can have a look at JBoss Netty which is an asynchronous event-driven network application framework. It greatly simplifies and streamlines network programming such as TCP and UDP socket server.

Categories

Resources