Tuesday, November 22, 2011

Перебираем циклом пользовательские переменные

Постановка задачи. Имеется N пользовательских переменных, значения которых вычисляются в BeanShall скрипте (в данном случае это - разные интервалы времени, но суть не важно). У этих пользовательских переменных user-friendly имена, так что сразу понятно, что передаётся этой переменной.
Необходимо выполнить некоторый однотипный набор действий, передавая параметрами все эти переменные.
То есть, нужно сделать цикл, который будет просто перебирать все эти переменные.

Первой мыслью было создать файл, куда запихиваются имена этих кастомных переменных с тем, чтобы потом их оттуда взять. Не сработало. Как бы ни мучались, имена передаются как текст.

Пришлось искать обходные пути.

Решение вышло несколько кривоватым, но, тем не менее, рабочим.

Итак в BeanShell скрипт и User Defined Variables добавляем T1..TN переменные, куда дублируем все нужные нам переменные с user-friendly именами.

Далее, создаем Loop, куда помещаем все нужные нам операции, которые должны быть выполнены в цикле. Ставим Loop Counter равным N (количество переменных).

Там, где нам нужно передавать значение переменной, в параметрах ставим
${__V(T${__counter(FALSE)})}
в нужном месте.

Всё работает :)

ПыСы. Отдельное спасибо Дэну Аркуше за подсказку решения "в лоб"

Дополнение. Нашлось лучшее решение.

Данный метод работает, если цикл у вас всего один. А что делать, если вложенных циклов несколько?

Параметр false у функции {__counter(FALSE)} означает, что этот счётчик будет увеличиваться только в пределах одного треда.
Но, если у вас будет сверху ещё 2 цикла с числом проходов X и Y, то счётчик ваш будет увеличиваться от 1 до X*Y*N, что приведёт к тому, что переменные у нас просто закончатся. нам-то нужно, чтобы этот счётчик работал от 1 до N.

В этом случае на помощь приходит конфигурационный элемент Counter


Задаём ему такие значения:
Start - 1
Increment - 1
Maximum - N (количество переменных)
Number format - 0 (в этом случает счёт начинается с 1, если Вы поставите 00, то счёт будет вестись с 01, если 000 - то с 001 соответственно).
Reference Name - Count (произвольное имя счётчика, на которое мы будем ссылаться).
Обязательно поставить галочку для "Track counter independently for each user".

После этого смело пишем этот счётчик везде, где он нам может понадобиться.

Т.е., ${__V(T${Count})}

Wednesday, November 9, 2011

Проверяйте системное время на виртуалках!!!

Два дня ковырялась, чего скрипт у меня генерит шопопало.
Время - 30е октября, хоть тресни.
Пока не дошло зайти и проверить системное время виртуалки (бубунта, штоп её).
И вы-таки не поверите...

Блондинко, блин...

Thursday, August 4, 2011

Добавляем кастомные функции в BeanShell

Исходя из предыдущего поста, возинкла необходимость написания простейшей функции, которая бы приписывала нолик к входному значению, в случае, если это значение меньше 10.
Два дня копала форумы, ничего не нашла.
А всего-то надо было почитать про BeanShell!!!!

Решение оказалось банальным до безобразия.

add( a, b )
{
return a + b;
}

foo = add(1, 2); // 3
foo = add("Oh", " baby"); // "Oh baby"

Итак, результирующий код выглядит следующим образом:

Calendar cal=Calendar.getInstance(TimeZone.getTimeZone("America/Los_Angeles"));

Conv(val)
{
String m = "";

if (val<10)

{
m = "0" + String.valueOf(val);
}

else
{
m =String.valueOf(val);
}

return m;
}

String newTime = Conv(cal.get(Calendar.YEAR)) + "-" + Conv(cal.get(Calendar.MONTH)+1) + "-" + Conv(cal.get(Calendar.DAY_OF_MONTH)) + "T" + Conv(cal.get(Calendar.HOUR_OF_DAY)) + "%3A" + Conv(cal.get(Calendar.MINUTE)) + "%3A" + Conv(cal.get(Calendar.SECOND)) + "Z";

vars.put("myTime", newTime);


Примечание! Если использовать Calendar cal=Calendar.getInstance() то у вас будет использоваться ваше _ЛОКАЛЬНОЕ_ время.
Мне это не подходило, т.к. объекты на сервере должны были создаваться по серверному времени.
Проблему решил перевод в формат UTC. Я использовала метод TimeZone.getTimeZone("America/Los_Angeles")) (список временных зон можно посмотреть вот здесь )
Однако, многим не нравится использование метода getTimeZone(), потому есть альтернативное решение.

Да, и ещё! Не забывайте о правильном использовании галочки "Encode?" в параметрах.
Если используются URL escape characters, то эту галочку ставить не нужно!

Thursday, July 14, 2011

Jmeter. Борьба с кастомным форматом даты/времени.

Понадобилось мне в один из вызовов вставить дату в следующем формате: yyyy-MM-ddThh:Amm:ssZ

Первый хинт - нельзя напрямую передавать ":", потому пользуемся URL escape code (http://www.december.com/html/spec/esccodes.html) - %3A.

Описанный в мануале способ не сработал (http://jakarta.apache.org/jmeter/usermanual/functions.html#__time) - изменённая строчка в jmeter.properties #time.USER1=yyyy-MM-ddTHH%3Amm%3Assz с последующим вызовом функции ${__time(USER1)}не сработала. Не сработало даже #time.USER1=yyyy-MM-dd.


Потому был найден обходной путь.

1. В наш любимый Config Element -> User Defined Variables помимо всего прочего добавляем переменную myTime.
2. К текущей Thread Group добавляем Sampler -> BeanShell Sampler, в теле скрипта которого пишем следующее:

Calendar cal=Calendar.getInstance();
int mm = cal.get(Calendar.MONTH);
mm = mm +1; //почему-то джава месяцы считает 0-11
String month = "";
if (mm<10)
{
   month = "0" + String.valueOf(mm);
}
    else
       {
         month =String.valueOf(mm);
       }
String newTime = String.valueOf(cal.get(Calendar.YEAR)) + "-" + month + "-" + String.valueOf(cal.get(Calendar.DAY_OF_MONTH)) + "T" + String.valueOf(cal.get(Calendar.HOUR_OF_DAY)) + "%3A" + String.valueOf(cal.get(Calendar.MINUTE)) + "%3A" + String.valueOf(cal.get(Calendar.SECOND)) + "Z";
vars.put("myTime", newTime);

3. Тадам - вызываем нашу переменную {myTime} в нужном месте реквеста.


Небольшая поправка. Дата-то вычисляется, но, если число или месяц меньше 10, то дата получается без нолика.
То же самое относится и к часам, минутам и секундам.

Потому возникла необходимость написания функции.
О том, как это делается - следующий пост.

Jmeter, Как же залогиниться на https, да ещё и с сертификатом? - 2

Предыдущий способ для меня не сработал, потому с помощью нашего программиста мы нашли следующую лазейку.
1. К текущей Thread Group ( о том, что это такое, и с чем его едят, я расскажу чуть позже) добавляем HTTP Cookie Manager (правый клик на имени Thread Group -> Add -> Config Element -> HTTP Cookie Manager).

2. К этой же группе добавляем Add -> Config Element -> HTTP Authorization Manager со следующими параметрами:
Base URL - https://${host}:8181/
Username - ${username}
Password - ${password}

где HOST, username, password - это переменные, заданные в User Defined Variables (об этом тоже чуть позже).

3. В ту же Thread Group добавляем Add -> Sampler-> HTTP Request, с помощью которого мы вытягиваем cookies.
В пути (path) указываем 100% работающую api'ку, у которой мы можем отобрать печеньку. (Именно за этим и нужен программист, ибо у нас просто нет списка апишек с описанием, а он-то уж точно знает, что куда и как).
Переименуем этот запрос, допустим, в Get Cookies (для того, чтобы переименовать достаточно просто написать желаемое в поле Name).

3.1. Правый клик на свежесозданном Get Cookies показывает нам контекстное меню, из которого мы выбираем Add -> Post Processor -> Regular Expressions Extractor. В нём мы записываем следующее:
Reference Name: csrfmiddlewaretoken
Regular Expression: Set-Cookie: csrftoken=(\w+);
Template: $1$
Match No. (0 for Random): 1
Default value: not found

Я подозреваю, что Reference Name и регулярное выражение могут варьироваться для каждого конкретного случая, потому помощь девелоперов тут более чем приветствуется.

4. Создаём ещё один HTTP Request  с именем, скажем, Login to apache со следующими параметрами:
Server Name or IP: ${HOST}
Path: относительный путь к логину, например, /login/ (т.е., что дописывается после имени хоста, чтобы попасть на страничку логина).

Send Parameters with the Request:
username - ${username}
password - ${password}
csrfmiddlewaretoken - ${csrfmiddlewaretoken}

Усё :) После этого у меня заработало!

Да, ещё нужно учитывать, что токен может передаваться, как в заголовке, так и в теле. В зависимости от этого надо ставить соответствующую галочку а обработчике регулярных выражений.

Jmeter, Как же залогиниться на https, да ещё и с сертификатом?

Способ номер раз, предложенный Артёмом Розуменко.

В командной строке сделать следующие действия (это чтоб ССЛ был по барабану устанавливается 1 раз и на всю жизть)
Для установки сертификата синатра.гармошка.ком
C:\Program Files\Java\jdk1.6.0_19\bin>keytool -import -alias sinatra.eharmony.com -file c:\sinatra.eharmony.com -keystore C:\Progra~1\Java\jdk1.6.0_19\jre\lib\security\cacerts
где C:\Program Files\Java\jdk1.6.0_19\bin - путь к бину ЖДК, c:\sinatra.eharmony.com - путь к месту где лежит сертификат, а C:\Progra~1\Java\jdk1.6.0_19\jre\lib\security\cacerts - в каталоге ЖДК по такому пути есть этот файл он за сертификаты отвечает.
если все введено правильно, то спросит пароль в консоли, а пароль "changeit"
потом проверьте что все поставилось такой командой:
C:\Program Files\Java\jdk1.6.0_19\bin>keytool -list -keystore C:\Progra~1\Java\jdk1.6.0_19\jre\lib\security\cacerts
В большом списке должон быть и новый серт.
Потом проделать следующее, можно и без консоли
1. Add the three key jars to your JVM's "ext" (extentions) directory; e.g.
    cp jcert.jar jnet.jar jsse.jar $JAVA_HOME/jre/lib/ext/
2. After the jars are in place, you must modify the file "java.security" to allow usage of the providers found within the jars. Find the file
   find $JAVA_HOME -name "java.security" как правило оно в C:\Program Files\Java\jdk1.6.0_19\jre\lib\security
3.  Add the following line to the file java.security (in case it's not exsists):
    security.provider.2=com.sun.net.ssl.internal.ssl.Provider а такая строчка у меня была, если есть то не вставляйте.
И после конфигурации в 15-20 минут наступает непреодолимое счастье :).
Сертификат тянется с файерфокса по средствам нажатия на замочек и экспорт его потом на тачку.
Там ещё очень аккуратно надо импортить в caserts. На всякий случай нужно этот файлик забэкапить (хотя, оттуда, по необходимости, можно и удалять).

Хинт - добавляя сертификат в caserts, его имя нужно прописывать точно так же, как оно появляется в самом сертификате. Т.е., если у Вас самописный сертификат говорит, что он выпущен для vasya-pupkin, то его надо прописывать именно, как vasya-pupkin, хоть вы и ходите на сайт vasya-pupkin.com через https.
Кому нужны файлы - свистите, скину :)

Джиметр для блондинок и не только. Intro.

Не столь давно вплотную столкнулась с необходимостью решать довольно нетривиальные задачи с помощью джиметра.
До того, весь опыт общения с оным сводился исключительно к записи каких-то простеньких действий, которые просто воиспроизводились нужное количество раз после несложных правок.
Вследствие того, что блондинка я натуральная, покурив гугль и мануал, сходу понять ничего не удалось, потому методом проб и ошибок, пришлось осваивать азы работы с джиметром, выкидывать разный ненужный мусор из выцепленных из Гугля последовательностей действий.

Да, задача осложнялась тем, что работать мне нужно было с https'ом. Потому простая запись логина не срабатывала.
Не помог и BadBoy, который умеет записывать скрипты в UI режиме, и затем экспортировать их в JMeter.

Раньше джиметр не умел записывать https запросы, потому BadBoy был единствненным приемлемым выходом (плюс, с более удобным интерфейсом). Однако, начиная с версии 2.3, джиметр-таки научился работать с https, потому необходимость в BadBoy'е отпала.

Тем не менее, работа с BadBoy'ем помогла мне гораздо красивее оформлять джиметровские скрипты.

Но обо всём по порядку :)