SlideShare a Scribd company logo
От Зефира в коробке к
Structure Zephyr
или
Как тест-менеджеру
перекроить внутренности JIRA
Никита Налютин
Experian
Предупреждение
В презентации есть
быдлокод (с багами) грязные трюки
и
Код здесь: https://github.com/p1ne/jira-zephyr-plus-structure/
О чем будем говорить
• Что такое Zephyr и Structure
• Зачем дружить Zephyr и Structure
• Как влезть в JIRA скриптами
• Как влезть в БД JIRA
• Как влезть в форматирование страниц
• Как этим всем сделать всем хорошо
• Как этого не делать
• …и о муми-троллях…
Structure – как все красиво организовать
marketplace.atlassian.com/plugins/com.almworks.jira.structure
Zephyr - как выглядят тесты
marketplace.atlassian.com/plugins/com.thed.zephyr.je
Хотим вот такой вид тестов
Хотим вот такую отчетность
Проблема
• Тест и прогон теста – разные сущности
• Статусы тестов – поля прогона теста, а не теста
• Нужен механизм проброса статуса теста на уровень теста
• Статус теста может быть разным в разных версиях/прогонах
• Выход – поля
• Latest test status
• Latest test execution
Скриптовые поля: Adaptivist Script Runner
marketplace.atlassian.com/plugins/com.onresolve.jira.groovy.groovyrunner/
Вариант реализации: ZAPI
"http://jira/rest/zapi/latest/execution?issueId=" + issueID
URLConnection urlConnection = url.openConnection();
…
BufferedReader reader = new BufferedReader( new
InputStreamReader(urlConnection.getInputStream()));
StringBuffer response = new StringBuffer();
…
def slurper = new JsonSlurper()
def result = slurper.parseText(response.toString())
if (result.recordsCount.toInteger() > 0) return
result.executions[0].versionName;
marketplace.atlassian.com/plugins/com.thed.zephyr.zapi/
Как увидеть таблицы плагинов
Как попробовать извлечь данные
marketplace/plugins/info.renjithv.jira.plugins.sysadmin.homedirectorybrowser
Вариант реализации: из базы
def delegator =
ComponentAccessor.getComponent(DelegatorInterface)
String helperName = delegator.getGroupHelperName("default");
StringBuffer sb = new StringBuffer()
def sqlStmt = ”...";
Connection conn =
ConnectionFactory.getConnection(helperName);
Sql sql = new Sql(conn)
sql.eachRow(sqlStmt) {
sb << "${it.status}”
def statusName = status[sb.toString()][0]
}
Как выбрать данные в скрипте
sqlStmt = "SELECT issue_id FROM ao_7deabf_schedule
where project_id = " + projectId + " and
(date_created between '" + timestamp.format(10.minutes.ago) +
"' and '" + timestamp.format(0.minutes.from.now) + "'
or executed_on between '" + (unixTime -
10*60*1000).toString() + "' and '" + unixTime.toString() +
"')
order by date_created desc";
Почему данные неактуальны?
• У Zephyr нет событий, означающих обновление test run
• JIRA кеширует значения атрибутов
• Поиск JQL работает исходя из кэша
• Частичное обновление кэша работает на весь проект
• Решение – периодическая перестройка кэша
Реиндекс и поиск: правильно,
но не работает
• Проблема: При попытке искать по кастом полям ничего не
находится или находится не все или не сразу
• Решение: само пройдет.
• Не проходит
• Решение: enableCache = {-> false}
• Не дает искать в принципе
Реиндекс: правильно,
но ооооочень долго
Пинаем реиндекс:
почти работает
def issueIndexManager =
ComponentAccessor.getIssueIndexManager();
def events = ComponentAccessor.getIssueEventManager();
sql.eachRow(sqlStmt) {
def issue =
ComponentAccessor.getIssueManager().getIssueObject(it.issue_i
d.toLong());
issueIndexManager.reIndex(issue);
events.dispatchEvent(EventType.ISSUE_UPDATED_ID, issue,
user, false);
}
Запуск реиндекса
• com.onresolve.jira.groovy.GroovyService – не заработало
• NSSM и периодический запуск ScriptRunner через POST
curl "http://jira/rest/scriptrunner/latest/user/exec/" ^
-H "Host: jira" ^
-H "Accept: application/json, text/javascript, */*; q=0.01" ^
-H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" ^
-H "X-Atlassian-Token: nocheck" ^
-H "X-Requested-With: XMLHttpRequest" ^
-H "Referer:
http://jira/plugins/servlet/scriptrunner/console?section=script_console" ^
--data "scriptText=&scriptFile=reindex.groovy&htmlText=&jsText="
https://nssm.cc/ https://curl.haxx.se/
А еще хотим выполнять тесты…
SELECT s.status, v.vname, s.id
FROM ao_7deabf_schedule s, projectversion v
WHERE s.project_id=" + projectId +
" and s.issue_id=" + issueId +
" and s.version_id = v.id
order by s.date_created desc
limit 1";
А еще хотим выполнять тесты…
if (!versionName.equals("") &&
(statusName.equals("UNEXECUTED") ||
statusName.equals("IN PROGRESS")) ) …
<a href="/secure/enav/#/" + executionId + "">
<span
class="trigger-label">Continue exec
</span>
</a>
А еще хотим выполнять тесты…
if (versionName.equals("")
<a id="zephyr-je-add-execute"
title="Execute Test"
class="toolbar-trigger viewissue-add-execute”
href="/secure/AddExecute!AddExecute.jspa?id=" +
issueId + "">
<span class="trigger-label">Exec new
</span>
</a>
Что делать с форматированием и поиском
coloredStatus = ”
<div class="labels exec-status-container">
<dd style="background-color: " +
statusColor + "">” + statusName +
"</dd></div>";
status = statusName
А еще хотим быстро планировать
А еще хотим экспорт тест-плана в документ
• Поле Preview, которое начинается с </td>
retStr += "</td></tr><tr style="width: 100%;">
<td colspan="10" style="font-size: 10pt;">”
retStr += wikiRenderer.render(issue.getDescription(), null)
retStr += "<br/>"
А еще хотим экспорт тест-плана в документ
Вопросы?
Код здесь: https://github.com/p1ne/jira-zephyr-plus-structure/

More Related Content

PDF
Визуализация покрытия автоматизированными UI тестами
PPTX
Грязная автоматизация
PDF
Postman
PDF
Github Flow. Тестировщики против тестирования
PDF
Дело тестера боится: как в опытных руках могут заиграть Java и TestNg
PDF
CodeFest 2014. Макаров Н. — Selenium Grid. OK Version
PPTX
Spock - the next stage of unit testing
PPTX
Selenium grid. OK version
Визуализация покрытия автоматизированными UI тестами
Грязная автоматизация
Postman
Github Flow. Тестировщики против тестирования
Дело тестера боится: как в опытных руках могут заиграть Java и TestNg
CodeFest 2014. Макаров Н. — Selenium Grid. OK Version
Spock - the next stage of unit testing
Selenium grid. OK version

What's hot (20)

PDF
Selenium grid on-demand
PPTX
Типичные ошибки начинающих писать тесты на WebDriver
PDF
QA Fest 2019. Андрей Солнцев. Десять причин моей ненависти
PPT
Let's Talk About Junit 5
PPTX
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
PDF
Spring data jee conf
PPTX
"Опыт создания системы управления сборкой и тестированием" (слайдкаст)
PDF
Автоматизация функционального тестирования REST API
PDF
Ангелы и демоны многопоточного программирования / Алексей Федоров (Одноклассн...
PDF
Формальная верификация кода на языке Си
PPTX
Оценка качества автотестов
PDF
Готовимся к Java SE 7 Programmer: от новичка до профессионала за 45 дней
PDF
Алексей Халайджи, Mail.Ru Group, «Как мы автоматизируем UI-тестирование в iOS...
PDF
Curse of spring boot test [VRN]
PDF
Логгирование. Зачем? Когда? Сколько?
PPTX
Selenium, а давай подождем?
PDF
Архитектура автоматизированных тестов
PDF
Akka: как я перестал бояться и полюбил асинхронный код
PDF
Микросервисы для автоматизации тестирования - опыт "Одноклассников"
PDF
QaAPI. Взгляд на тестирование с другой стороны баррикад. Доклад Дмитрия Марущ...
Selenium grid on-demand
Типичные ошибки начинающих писать тесты на WebDriver
QA Fest 2019. Андрей Солнцев. Десять причин моей ненависти
Let's Talk About Junit 5
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
Spring data jee conf
"Опыт создания системы управления сборкой и тестированием" (слайдкаст)
Автоматизация функционального тестирования REST API
Ангелы и демоны многопоточного программирования / Алексей Федоров (Одноклассн...
Формальная верификация кода на языке Си
Оценка качества автотестов
Готовимся к Java SE 7 Programmer: от новичка до профессионала за 45 дней
Алексей Халайджи, Mail.Ru Group, «Как мы автоматизируем UI-тестирование в iOS...
Curse of spring boot test [VRN]
Логгирование. Зачем? Когда? Сколько?
Selenium, а давай подождем?
Архитектура автоматизированных тестов
Akka: как я перестал бояться и полюбил асинхронный код
Микросервисы для автоматизации тестирования - опыт "Одноклассников"
QaAPI. Взгляд на тестирование с другой стороны баррикад. Доклад Дмитрия Марущ...
Ad

More from SQALab (20)

PDF
Готовим стажировку
PPTX
Куда приводят мечты? или Искусство развития тестировщика
PPT
Оптимизация Selenium тестов и ускорение их поддержки
PPT
Автоматизация 0.0: 0 - бюджет, 0 - опыт программирования
PPTX
Нагрузочное тестирование нестандартных протоколов с использованием Citrix и J...
PPTX
Continuous performance testing
PDF
Конфиги вместо костылей. Pytestconfig и зачем он нужен
PPT
Команда чемпионов в ИТ стихии
PPTX
API. Серебряная пуля в магазине советов
PPTX
Добиваемся эффективности каждого из 9000+ UI-тестов
PPT
Делаем автоматизацию проектных KPIs
PDF
Вредные привычки в тест-менеджменте
PPTX
Мощь переполняет с JDI 2.0 - новая эра UI автоматизации
PPT
Как hh.ru дошли до 500 релизов в квартал без потери в качестве
PPTX
Стили лидерства и тестирование
PPT
"Давайте не будем про качество"
PDF
Apache.JMeter для .NET-проектов
PPTX
Тестирование геолокационных систем
PPTX
Лидер или босс? Вот в чем вопрос
PPTX
Истинная сила тестировщика - информация
Готовим стажировку
Куда приводят мечты? или Искусство развития тестировщика
Оптимизация Selenium тестов и ускорение их поддержки
Автоматизация 0.0: 0 - бюджет, 0 - опыт программирования
Нагрузочное тестирование нестандартных протоколов с использованием Citrix и J...
Continuous performance testing
Конфиги вместо костылей. Pytestconfig и зачем он нужен
Команда чемпионов в ИТ стихии
API. Серебряная пуля в магазине советов
Добиваемся эффективности каждого из 9000+ UI-тестов
Делаем автоматизацию проектных KPIs
Вредные привычки в тест-менеджменте
Мощь переполняет с JDI 2.0 - новая эра UI автоматизации
Как hh.ru дошли до 500 релизов в квартал без потери в качестве
Стили лидерства и тестирование
"Давайте не будем про качество"
Apache.JMeter для .NET-проектов
Тестирование геолокационных систем
Лидер или босс? Вот в чем вопрос
Истинная сила тестировщика - информация
Ad

От Зефира в коробке к Structure Zephyr или как тест-менеджеру перекроить внутренности JIRA

  • 1. От Зефира в коробке к Structure Zephyr или Как тест-менеджеру перекроить внутренности JIRA Никита Налютин Experian
  • 2. Предупреждение В презентации есть быдлокод (с багами) грязные трюки и Код здесь: https://github.com/p1ne/jira-zephyr-plus-structure/
  • 3. О чем будем говорить • Что такое Zephyr и Structure • Зачем дружить Zephyr и Structure • Как влезть в JIRA скриптами • Как влезть в БД JIRA • Как влезть в форматирование страниц • Как этим всем сделать всем хорошо • Как этого не делать • …и о муми-троллях…
  • 4. Structure – как все красиво организовать marketplace.atlassian.com/plugins/com.almworks.jira.structure
  • 5. Zephyr - как выглядят тесты marketplace.atlassian.com/plugins/com.thed.zephyr.je
  • 6. Хотим вот такой вид тестов
  • 7. Хотим вот такую отчетность
  • 8. Проблема • Тест и прогон теста – разные сущности • Статусы тестов – поля прогона теста, а не теста • Нужен механизм проброса статуса теста на уровень теста • Статус теста может быть разным в разных версиях/прогонах • Выход – поля • Latest test status • Latest test execution
  • 9. Скриптовые поля: Adaptivist Script Runner marketplace.atlassian.com/plugins/com.onresolve.jira.groovy.groovyrunner/
  • 10. Вариант реализации: ZAPI "http://jira/rest/zapi/latest/execution?issueId=" + issueID URLConnection urlConnection = url.openConnection(); … BufferedReader reader = new BufferedReader( new InputStreamReader(urlConnection.getInputStream())); StringBuffer response = new StringBuffer(); … def slurper = new JsonSlurper() def result = slurper.parseText(response.toString()) if (result.recordsCount.toInteger() > 0) return result.executions[0].versionName; marketplace.atlassian.com/plugins/com.thed.zephyr.zapi/
  • 12. Как попробовать извлечь данные marketplace/plugins/info.renjithv.jira.plugins.sysadmin.homedirectorybrowser
  • 13. Вариант реализации: из базы def delegator = ComponentAccessor.getComponent(DelegatorInterface) String helperName = delegator.getGroupHelperName("default"); StringBuffer sb = new StringBuffer() def sqlStmt = ”..."; Connection conn = ConnectionFactory.getConnection(helperName); Sql sql = new Sql(conn) sql.eachRow(sqlStmt) { sb << "${it.status}” def statusName = status[sb.toString()][0] }
  • 14. Как выбрать данные в скрипте sqlStmt = "SELECT issue_id FROM ao_7deabf_schedule where project_id = " + projectId + " and (date_created between '" + timestamp.format(10.minutes.ago) + "' and '" + timestamp.format(0.minutes.from.now) + "' or executed_on between '" + (unixTime - 10*60*1000).toString() + "' and '" + unixTime.toString() + "') order by date_created desc";
  • 15. Почему данные неактуальны? • У Zephyr нет событий, означающих обновление test run • JIRA кеширует значения атрибутов • Поиск JQL работает исходя из кэша • Частичное обновление кэша работает на весь проект • Решение – периодическая перестройка кэша
  • 16. Реиндекс и поиск: правильно, но не работает • Проблема: При попытке искать по кастом полям ничего не находится или находится не все или не сразу • Решение: само пройдет. • Не проходит • Решение: enableCache = {-> false} • Не дает искать в принципе
  • 18. Пинаем реиндекс: почти работает def issueIndexManager = ComponentAccessor.getIssueIndexManager(); def events = ComponentAccessor.getIssueEventManager(); sql.eachRow(sqlStmt) { def issue = ComponentAccessor.getIssueManager().getIssueObject(it.issue_i d.toLong()); issueIndexManager.reIndex(issue); events.dispatchEvent(EventType.ISSUE_UPDATED_ID, issue, user, false); }
  • 19. Запуск реиндекса • com.onresolve.jira.groovy.GroovyService – не заработало • NSSM и периодический запуск ScriptRunner через POST curl "http://jira/rest/scriptrunner/latest/user/exec/" ^ -H "Host: jira" ^ -H "Accept: application/json, text/javascript, */*; q=0.01" ^ -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" ^ -H "X-Atlassian-Token: nocheck" ^ -H "X-Requested-With: XMLHttpRequest" ^ -H "Referer: http://jira/plugins/servlet/scriptrunner/console?section=script_console" ^ --data "scriptText=&scriptFile=reindex.groovy&htmlText=&jsText=" https://nssm.cc/ https://curl.haxx.se/
  • 20. А еще хотим выполнять тесты… SELECT s.status, v.vname, s.id FROM ao_7deabf_schedule s, projectversion v WHERE s.project_id=" + projectId + " and s.issue_id=" + issueId + " and s.version_id = v.id order by s.date_created desc limit 1";
  • 21. А еще хотим выполнять тесты… if (!versionName.equals("") && (statusName.equals("UNEXECUTED") || statusName.equals("IN PROGRESS")) ) … <a href="/secure/enav/#/" + executionId + ""> <span class="trigger-label">Continue exec </span> </a>
  • 22. А еще хотим выполнять тесты… if (versionName.equals("") <a id="zephyr-je-add-execute" title="Execute Test" class="toolbar-trigger viewissue-add-execute” href="/secure/AddExecute!AddExecute.jspa?id=" + issueId + ""> <span class="trigger-label">Exec new </span> </a>
  • 23. Что делать с форматированием и поиском coloredStatus = ” <div class="labels exec-status-container"> <dd style="background-color: " + statusColor + "">” + statusName + "</dd></div>"; status = statusName
  • 24. А еще хотим быстро планировать
  • 25. А еще хотим экспорт тест-плана в документ • Поле Preview, которое начинается с </td> retStr += "</td></tr><tr style="width: 100%;"> <td colspan="10" style="font-size: 10pt;">” retStr += wikiRenderer.render(issue.getDescription(), null) retStr += "<br/>"
  • 26. А еще хотим экспорт тест-плана в документ