Saturday, March 9, 2013

Batch operation with Apache Camel

This is a small post of how can we organize batching in apache camel 2.8.0.

Given

Apache camel version 2.8.0. Hot higher because it's production restriction so far.
A list of pojos as input
A csv file as output

Test


Camel allows to advise producer endpoints with mocks, look at setup method. Starting from camel 2.10 mocking can be done with annotations. MockEndpoint provides flexible expectation and assertion mechanism

Implementation 

Spring context


By default split output will be the same as input. Developer can change this behavior by adding AggregationStrategy like:
In camel AggregationStrategy always receives null in oldExchange for the first record in batch. All subsequent batch records will be accumulated in oldExchange by appending String with record from newExchange. Aggregation executed after all transformation in split closure body.

Definition body within split tells camel to drop input list of pojos into single elements and pass them in subsequent csvRowFormatter processor.

CsvFormatter

It's pretty simple. Extract pojo from camel exchange, format csv from it and push it back into exchange.

Conclusion

Camel provides flexible mechanism for building routing engines. It allows to build batching as well. For full version of example refer to github

This post was created mostly like a reminder.

Friday, January 25, 2013

Testing native applications with #Sikuli and #Spock framework

Recently i've been asked to code assignment for Spotify.
Looking ahead I've failed the task.
Nevertheless i would like to describe here how i did it.
I've been asked to write tests for Spotify native client for following scenarios

- test weather wrong credentials will fail login
- test weather correct credentials will allow login
- test weather search is working properly
- test weather Spotify client plays music.

I was asked to write tests using Sikuli. I haven't heard about this tool, but i was impressed by it. That's why i'm writing this post.
So lets start.

Environment setup


I'm a Linux guy, thus i'll describe setup for this OS


Install Sikuli IDE


Download Linux distribution. I decided not to use deb packages to install.
After that you'll find that you cannot take screenshots, because libaux.so:2.1 is not found (You'll find a stacktrace in Sikuli IDE with JNI error).
Install OpenCV will help but on Ubuntu 12.04 you need install following packages,   check if all libs are installed with

ldd $SIKULI_INSTALL_DIR/libs/libVisionProxy.so

where libVisionProxy.so is JNI wrapper for OpenCV

You can skip the Sikuli IDE, but i strongly recommend to do this, because you can write scripts with it easily and learn how it works.

And finally, Sikuli jar should be uploaded to local maven repo:

upload sikuli-script to local maven repo mvn install:install-file -Dfile=sikuli-script.jar -DgroupId=org.sikuli -DartifactId=sikuli-script -Dversion=0.10.2 -Dpackaging=jar

So what is the Sikuli? You can find a lot of info about in Google Search. But in few words - it's a JNI wrapper above image processing libraries installed in you operating System. For Linux it's an OpenCV, as for other systems i don't know, maybe some Intel libraries for image processing. But it's not only wrapper, it provides an API for iteration with desktop. It allows you mouse moves and clicks, keyboard iterations symulations, etc. Why wouldn't we use it for test scenarios? Right we should. Actually for native clients Sikuli is essential.

Writing tests


I'm a Groovy and Spock fun, thus i've chosen them to write tests. I've decided that UI tests are not simple unit tests but more acceptance|functional and should be behavioral tests.

Setting up prerequisites for Spotify tests

All functional tests imply following scenario:

- run application under test
- run tests against this application
- shutdown this application

I used Spock annotation extension approach to run and stop application under tests. Using this approach you can do some stuff before and after Spock scenarios, features ind iterations (for data driven tests). Here is a Spock extension for running and stopping Spotify client before and after running test:

A Spock extension annotation

A Spock extension implementation

Further I'll show how to use this extension in tests.

This Spock extension is simple. Before scenario Spotify client is started and after stopped.


Tests


There a lot of papers and presentations about UI testing approach. Personally i like @vakaleo and his essays about page object pattern. The benefits of using this approach are
- hide implementation details in tests scripts
- DRY principle


Login tests



LoginScrean page object was created, let's look what is under the hood

Sikuli Screen object represents desktop. Using Screen object tests can interact with desktop like

s.type("./src/test/resources/sikuli-password.png", pwd)

or

wait(new Pattern("src/test/resources/sikuli-login-failed.png").similar(0.75))

in first case Sikuli will try to find a region on desktop similar with image


and type password there

For the second case Sikuli will wait until following image with 0.75 ratio of similarity will appear on screen


Playing with waiting of second image on desktop we can write tests for login window.

Pay attention to the Spock specification annotation. Annotating scenario with @RunSpotify will trigger listeners registered in SpotifySpockExtention, therefore Spotify client will be started and stopped for specification.

Lets look at more complex specification

Search and play tests


The page object SpotifyUIScrean


Here i would like to explain how music playing can be validated. Imagine simple player. When you start composition progress bar starts moving from left to right. That motion should be checked. You can find the code in progress closure in SpotifyUIScrean page object.
Slider should be found on desktop


then SikuliEventAdapter should be registered on this region and observe method should be triggered for this region. If something changed on this region targetChanged method will be triggered and we can treat it as progress bar motion

And finally grug-and-drop feature. In my test "verify that Marilyn Manson Cyclops song is playing" volume level increased to the maximum position. look at upVolume closure for details.
Player control should be found


On the right side

should be found

and then drug slider to
I had to do this trick because slider presents twice on Spotify UI, for volume control and song progress bar.

That's all. Here is a source code

PS.
i found wonderful post where web ui was tested with #Geb and #Sikuli in combination.

DISCLAIMER
I don't pretend this is a best solution and i would like to see you criticism of my code. I have a response from Spotify guys on my solution which is controversial IMHO :)

Wednesday, December 12, 2012

Handling Thread Exceptions

I've been a witness when interviewer asked candidate a question:
- "Is it any way to handle exception thrown within particular thread from client thread?"
Imagine the situation when you need to know if any exception was thrown in thread you scheduled and run. Surround Thread#start() with try-catch clause doesn't make any sense, because it's asynchronous call of Runnable.

I can suggest at least 2 ways to do it

1. Old school approach.
One can register Exception handler before starting the thread:

Thread thread = new Thread(new Runnable() {   
 public void run() {
  throw new RuntimeException("simulate failure for oldschool approach");    
  }
 });
thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
 public void uncaughtException(Thread t, Throwable e) {
  System.out.println("I'm in thread " + Thread.currentThread().getName());
  e.printStackTrace();
 }
});  
thread.start();

The output is following:

I'm in thread Thread-0 
java.lang.RuntimeException: simulate failure for oldschool approach 
at org.sdo.concurrency.interview.ExceptionWithinThreadTask$1.run(ExceptionWithinThreadTask.java:26) 
at java.lang.Thread.run(Thread.java:722)


UncaughtExceptionHandler#uncaughtException was executed in newly created thread. To make it visible from client thread synchronization should be used (Thread#join for instance)

2. Futures approach

System.out.println("Simulating using future");
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
Future future = newSingleThreadExecutor.submit(new Callable
<String>() {
 public String call() throws Exception {
  throw new RuntimeException("simulate fail");
 }
 });
try {
 future.get();
}
catch (InterruptedException e) {
 e.printStackTrace();
}
catch (ExecutionException e) {
 System.out.println("I'm in thread " + Thread.currentThread().getName());
 e.printStackTrace();
}
newSingleThreadExecutor.shutdown();

The output is:

I'm in thread main
java.util.concurrent.ExecutionException: java.lang.RuntimeException: simulate fail
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:252)
at java.util.concurrent.FutureTask.get(FutureTask.java:111)
at org.sdo.concurrency.interview.ExceptionWithinThreadTask.simulateUsingFuture(ExceptionWithinThreadTask.java:52)
at org.sdo.concurrency.interview.ExceptionWithinThreadTask.main(ExceptionWithinThreadTask.java:18)
Caused by: java.lang.RuntimeException: simulate fail
at org.sdo.concurrency.interview.ExceptionWithinThreadTask$3.call(ExceptionWithinThreadTask.java:48)
at org.sdo.concurrency.interview.ExceptionWithinThreadTask$3.call(ExceptionWithinThreadTask.java:1)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)

Pay attention that exception was handled in client thread.


Conclusion

The second approach is more natural. We can surround Future#get() with try-catch clause and handle inner-thread exception from client threads. From the other side using oldschool approach leads to additional effort to make throwable visible from client thread.

Wednesday, August 29, 2012

О курении

Не то чтобы я заядлый курильщик но иногда на меня нападает сильная тяга покурить, это может продлиться от пару дней и до нескольких месяцев. Я сам себя постоянно казню за это, да и организм уже не тот, что был в студенческие годы и постоянно напоминает о вредных привычках с изрядной настойчивостью.
Бороться я с этой привычкой успешно можно с помощью спорта. Я заставлял себя бегать три раза в неделю по примерно пять километров. Когда занимаешься спортом, понимаешь как тебе плохо и как может быть хорошо если бросишь эту дрянь. В общем бегал я так пока не начал испытывать боль в правой ноге, решил приостановить забеги, нога прошла а привычка вернулась.
И вот как то я стоял на причале возле дачи на берегу лимана, смачно затягивался очередной сигаретой, и ко мне подходит старшая дочь и говорит, "папа ну зачем ты куришь, ты же можешь заболеть и умереть, а я тебя так люблю". Это было полторы недели назад, я понимаю что срок маленький, но то была последняя сигарета, с тех пор как только я  хочу за курить, я спрашиваю себя, а действительно ли я хочу умереть раньше и не увидеть как вырастут мои дочери, у меня появятся внучки/ки и правнучки/ки? Ответ приходит один - НЕТ!!!

Бросайте курить.

PS Собираюсь прикупить кроссовки для бега по твердой поверхности, посоветуйте хорошую обувь. 

Thursday, December 22, 2011

Разработка через тестирование. Организовываем Додзё



Сегодня в Luxoft UBS DC удалось организовать двухчасовую сессию посвященную TDD и coding dojo практикам.


Было минимум теории. Благодаря SmartBoard удалось достичь максимальной вовлеченности участников.


Всего было 8 человек, каждый успел побывать в роли pilot и copilot. 


Тренировались на кате Game Of Life


К сожалению мы не успели закончить полностью, закончили лишь на 80 - 90 % реализации.


Зато провели ретроспекцию, что очень важно в такого рода мероприятиях.


Среди недостатков отметили отсутвие дизайн сессии и работы у WiteBoard. Кроме того специфика Dojo привнесла некую сумбурность в процесс, потому как приходилось каждые 7 минут ротировать участников.


Однако, всем понравилось, и все изъявили желание продолжать проведения такого рода мероприятий, что скорее всего приведет к образованию KievGojo.


Для тех кому интересна эта тема предлагаю посмотреть пятиминутный ролик о том как организовать подобного рода мероприятие. А также добро пожаловать на сайт энтузиастов coding dojo.

В дальнейшем планируется провести ряд практических и теоретических сессий по методологиям, инструментам и подходам к написанию тестов.

Пока все.

Tuesday, December 20, 2011

Надоел Enterprise. Немного геометрии

Недавно наводил порядок в архивах и наткнулся на папку с диссертацией. покопался немного в исходниках матлаба и решил проверить рабочее ли все?

Взор у меня пал на скрипт Circles.m. Скажу честно код совершенно нечитабелен. И если бы его когдато написал не я то наверно я черти с два понял что там написано.

сценарий таков:

1. Есть изображение черно белое, какой то слитной фигуры, например самолета. Вот пример
2. Делаем над ним двумерное преобразование Гильберта. В результате мы получим точки в местах перегибов контура фигуры - назовем их характерными точками
3. А теперь геометрия. Задача найти центр масс слитной фигуры, в данном случае самолета, и провести концентрические окружности с центом в центре масс фигуры. Представить эти окружности как радар, и предположить что если характерная точка в пределах видимости радара, то засветить её. Должно получиться что то типа вот этого:
проблема в том что характерные точки вовсе не обязательно будут лежать на концентрических окружностях радар. Необходимо сделать допущение что если характерная точка в непосредственной близости от радара, то она засветится, как то вот так

черным цветом  обозначил светящиеся точки, не лучший вариант но тем не менее понятно вроде.

Теперь о реализации.

Писалось это очень давно и на скриптовом языке для научных вычислениях Matlab.

скрипт выглядит примерно так


for r = 10 : 10 : 130
        %рассчет координат точек окружности радара - 100 точек с радиусом r и центром в xr,yr
        circlePoints = calcCirclePoints(xr, yr, r, 100, 0);
        hold on
        plot(circlePoints(1,:), circlePoints(2,:), 'r-')
        hold on
        for i = 1 : length(arClasterData)
            d = sqrt((arClasterData(i,1) - xr)^2 + (arClasterData(i,2) - yr)^2);
            if d >= (r-1)
%уравнение прямой ax+b рассчитаем коэффициенты a и b для прямой проходящей от центра до характерной точки
[a, b] = calcLineKoef(xr, yr, arClasterData(i,1), arClasterData(i,2));
%а теперь рассчитаем расстояние от характерной точки до окружности радара
d = pointToCircleDist(arClasterData(i,1), arClasterData(i,2), xr, yr, r, a, b);
%если расстояние меньше 1 то засветим точку
                if d <= 1
                    hold on
                    plot(arClasterData(i,1), arClasterData(i,2),'k*')
                end
            end
        end
    end

Самой интересной функцией тут является на мой взгляд расчет расстояния от точки до окружности. Как известно это можно сделать с помощью касательной к окружности, а именно нахождения координат точки соприкосновения касательной и окружности и расчета Евклидова расстояния от этой точки до характерной точки. Сделал я это так


function d = pointToCircleDist(xp, yp, xr, yr, r, a, b)

switch checkCircleSector(xr, yr, xp, yp)
    case 1
        y = yr + r * sin(abs(atan(a)));
        x = xr + r * cos(abs(atan(a)));
    case 2
        y = yr + r * sin(pi - abs(atan(a)));
        x = xr + r * cos(pi - abs(atan(a)));
    case 3
        y = yr + r * sin(pi + abs(atan(a)));
        x = xr + r * cos(pi + abs(atan(a)));
    case 4
        y = yr + r * sin(2*pi - abs(atan(a)));
        x = xr + r * cos(2*pi - abs(atan(a)));
end
d = sqrt((xp - x)^2 + (yp - y)^2);

В зависимости от того в каком квандранте находится характерная точка, координаты точки касания рассчитываются по разному


Как то так. На мой взгляд интересно.

Thursday, December 1, 2011

Software development values

Давненько не писал в блог. Очень много работы в последнее время, зачастую нет времени банально пойти поесть или даже ... нет не будем об этом.
Перебирая почту нашел рассылку от InfoQ в которой была ссылка на книгу "Patterns of Agile Practice of Adoption The Technical Cluster". Решил поделиться мыслями о прочитанном.
Business Value.
В процессе жизненного цикла Delivery какой то функциональности, я уделяю много внимания деталям, я не хочу сказать что это плохо, наоборот, продумывая все возможные варианты и углубляясь в детали я делаю свой продукт лучше. Но, лучше для кого? для себя? потому что я разобрались с очередной нетривиальной задачей и потешили свое самолюбие, или для конечного пользователя?
Для меня, поле моего интереса заканчивается примерно тогда, когда я написал код, который по моему хорошо работает и решает описанную задачу. Есть мнение что для аналитика он заканчивается тогда, когда он провел анализ и разложил все по полочкам, так, чтобы это понятно было мне, как разработчику, а для специалиста по качеству, когда функциональность протестирована и все может идти в релиз. Я конечно сейчас говорю о людях которые получают кайф от своей работы, а не приходят туда для того чтобы отметится, потому что иначе не переведут на карточку ЗП, и вообще попросят написать заявление по собственному желанию. Потому что с такими нужно прощаться сразу так чтобы они не тянули команду вниз во всех смыслах этого слова.
Человек существо эгоистичное, но если поднять немного выше голову то можно найти еще источник удовлетворения своего самолюбия. И этим источником является конечный пользователь, кастомер, не знаю как вы его называете. Но, надеюсь мы все понимаем одно и тоже под этими словами.
Кастомер существо благодарное, и если говорить о материальной стороне, то если вы делаете качественный продукт, то с вами перезаключат контракт, если ваш продукт сэкономил кучу денег кастомеру то наверняка он с вами поделится и т.д. или вообще отбросим материальную сторону и представим, что вашей фичей стали пользоваться кучу народу и благодарны вам за её.
Мораль.
Доводите свой продукт общими усилиями, а не кидайте дело, когда оно выходит за пределы вашей специализации.
Собирайте отзывы от конечных пользователей, в конце концов, если не учитывать бабло которое вам платят, это самое главное, ибо в отзыве отражается качество анализа, технического решения и тестирования
Вырабатываете практики, которые вам позволят избавиться от рутинной работы во время Delivery.
Не бойтесь экспериментировать, пробуйте разные подходы и практики, выступайте в разных ролях в команде, это позволит лучше понять все стороны и этапы разработки анализа и тестирования.
Эволюционируете всей командой а не по частям, делитесь опытом.
Заражайте остальные команды которые вокруг вас своей производительностью.
В противном случае ~40 процентов жизни, которую вы проводите на работе превращается в угрюмое и унылое времяпрепровождение.