Repocop: различия между версиями

Материал из ALT Linux Wiki
м Tools/Repocop» переименована в «Repocop»)
 
(не показано 58 промежуточных версий 13 участников)
Строка 1: Строка 1:
[[Category:Sisyphus]]
[[Категория:Sisyphus]]
[[Категория:Devel]]
[[Категория:Repocop]]
{{Category navigation|title=Repocop|category=Repocop}}
 
<!--MovedFromFreesourceInfo|AltLinux/Sisyphus/Tools/Repocop-->
<!--MovedFromFreesourceInfo|AltLinux/Sisyphus/Tools/Repocop-->
 
[[Изображение:Robocop-12inch-5-01.jpg|tumb|left]]
== repocop ==
[http://absurdopedia.net/wiki/Огромный_боевой_робот Малый огромный боевой робот], созданный [http://absurdopedia.net/wiki/Безумные_учёные безумными учёными]
{| class="wikitable" style="width:100%;"
|-
|
[[Изображение:Robocop-12inch-5-01.jpg]]
<!-- http://www .star store .com/acatalog/robocop-12inch-5-01.jpg -->
|
[http://absurdopedia.wikia.com/wiki/%D0%9E%D0%B3%D1%80%D0%BE%D0%BC%D0%BD%D1%8B%D0%B9_%D0%B1%D0%BE%D0%B5%D0%B2%D0%BE%D0%B9_%D1%80%D0%BE%D0%B1%D0%BE%D1%82 малый огромный боевой робот], созданный [http://absurdopedia.wikia.com/wiki/%D0%91%D0%B5%D0%B7%D1%83%D0%BC%D0%BD%D1%8B%D0%B5_%D1%83%D1%87%D0%B5%D0%BD%D1%8B%D0%B5 безумными учёными]  
для тестирования отдельных rpm пакетов или всего Сизифа.
для тестирования отдельных rpm пакетов или всего Сизифа.


В отличие от [[Tools/sisyphuscheck|sisyphus_check]], который настолько суров, что сначала убивает возможного
В отличие от [[sisyphus_check|sisyphus_check]], который настолько суров, что сначала убивает возможного
нарушителя, а потом его допрашивает, repocop в открытый бой не вступает, ограничиваясь  
нарушителя, а потом его допрашивает, repocop в открытый бой не вступает, ограничиваясь
невнятными выкриками на американском английском и показом красных и желтых карточек.
невнятными выкриками на американском английском и показом красных и жёлтых карточек.


Другими словами, repocop представляет собой платформу для запуска интеграционных тестов.
Другими словами, repocop представляет собой платформу для запуска интеграционных тестов.
В её состав входит собственно пускатель тестов, различные генераторы отчётов из полученных результатов,
а также генератор патчей для исправления найденных ошибок, если это возможно.
Сами тесты в repocop не входят. Тесты оформлены как отдельные пакеты, поэтому набор тестов легко конфигурируется.


Результаты ежедневного тестирования Sisyphus публикуются на [http://repocop.altlinux.org/pub/repocop/reports/ repocop.altlinux.org]
Результаты ежедневного тестирования Sisyphus публикуются на [http://repocop.altlinux.org/pub/repocop/reports/ repocop.altlinux.org]
а так же доступны через web-интерфейс prometeus на [http://sisyphus.ru/ http://sisyphus.ru/].
а так же доступны через web-интерфейс prometheus2.0 на [http://packages.altlinux.org/ru packages.altlinux.org].
|}


Например, для мейнтейнера {{man|viy}} удобными ссылками на результаты тестирования будут: [http://packages.altlinux.org/ru/Sisyphus/maintainers/viy по пакетам], [http://repocop.altlinux.org/pub/repocop/reports/txt/by-acl/viy.txt по ACL] и [http://repocop.altlinux.org/pub/repocop/reports/txt/by-leader/viy.txt по лидеру пакетов].
Сгенерированные патчи можно просмотреть:
[http://repocop.altlinux.org/pub/repocop/reports/diff/by-acl/viy/ по ACL] и [http://repocop.altlinux.org/pub/repocop/reports/diff/by-leader/viy/ по лидеру пакетов].


__TOC__
__TOC__
Строка 27: Строка 29:
=== Установка ===
=== Установка ===


установка repocop на локальной машине:
Установка repocop на локальной машине:
$ apt-get install repocop repocop-unittest
<source lang="bash">
apt-get install repocop repocop-unittests-local
</source>


repocop состоит из следующих пакетов:
repocop состоит из следующих пакетов:
{| border="1"
{| class="standard"
!Пакет
!Описание
|-
|-
|
|class="shadow"|repocop
repocop
|Основной пакет
|
основной пакет.
|-
|-
|
|class="shadow"|repocop-tools
repocop-prometeus
| Инструменты для исправления пакетов силами repocop. Не обязателен.
|
|-
Плагин к prometeus. не нужен при обычнй установке.
|class="shadow"|repocop-prometeus
|Плагин к prometeus. Не нужен при обычной установке
|}
|}


Сами тесты вместе с пакетом не идут, их надо устанавливать отдельно.
Полный список тестов можно посмотреть на [http://packages.altlinux.org/ru/search?utf8=%E2%9C%93&branch=Sisyphus&query=repocop-unittest http://packages.altlinux.org/].


Сами тесты вместе с пакетом не идут, их надо устанавливать отдельно.
Для удобства виртуальный пакет repocop-unittest позволяет установить все официальные тесты, которые используются в sisyphus-cybertalk@ и на [http://packages.altlinux.org/ru packages.altlinux.org].
Полный список тестов можно посмотреть на [http://sisyphus.ru/find.shtml?request=repocop-unittest http://sisyphus.ru/find.shtml?request=repocop-unittest].
Для удобства, виртуальный пакет repocop-unittest позволяет установить все официальные тесты,
которые используются в cybertalk@ и на [http://sisyphus.ru/ http://sisyphus.ru/].


=== Запуск ===
=== Запуск repocop для тестирования пакетов ===


* Пример запуска repocop для тестирования свежесобранных пакетов:
* Пример запуска repocop для тестирования свежесобранных пакетов:
:<pre>repocop-run  ~/hasher/repo/*/RPMS.hasher/*.rpm</pre>
*: {{cmd|repocop-run  ~/hasher/repo/*/RPMS.hasher/*.rpm}}
* Пример запуска repocop для тестирования репозитория:
* Пример запуска repocop для тестирования репозитория:
:<pre>repocop-run  /var/ftp/pub/Linux/ALT/Sisyphus/files/{noarch,i586}/RPMS</pre>
*: {{cmd|repocop-run  /var/ftp/pub/Linux/ALT/Sisyphus/files/{noarch,i586}/RPMS}}


При повторном запуске будут тестироваться только новые пакеты, так как результаты тестов кешируются
При повторном запуске будут тестироваться только новые пакеты, так как результаты тестов сохраняются
в <repocop cache dir>. По умолчанию <repocop cache dir> равно <tt>~/.repocop</tt>.
в <repocop workdir>. По умолчанию <repocop workdir> равно <tt>~/.repocop</tt>.
Значение по умолчанию для <repocop cache dir> можно переопределить с помощью опции -c <repocop cache dir>
Значение по умолчанию для <repocop workdir> можно переопределить с помощью опции --workdir <repocop workdir>
либо поменять с помощью переменной окружения REPOCOP_CACHEDIR. Например, так:
либо поменять с помощью переменной окружения REPOCOP_WORKDIR. Например, так:
<tt>export REPOCOP_CACHEDIR=/tmp/.private/user/repocop</tt>.
<tt>export REPOCOP_WORKDIR=/tmp/.private/user/repocop</tt>.


Для ухода за кешем используются утилиты <tt>repocop-purge-* </tt>.
Для ухода за кешем используются утилиты <tt>repocop-purge-* </tt>.
{| border="1"
 
{| class="standard"
!Утилита
!Описание
|-
|-
|
|class="shadow"|repocop-purge-except
repocop-purge-except
|очистить все записи, кроме относящихся к пакетам, данным как аргументы.
|
очистить все записи, кроме относящихся к пакетам, данным как аргументы.
|-
|-
|
|class="shadow"|repocop-purge-given
repocop-purge-given
|очистить все записи, относящиеся к пакетам, данным как аргументы.
|
очистить все записи, относящиеся к пакетам, данным как аргументы.
|}
|}


 
полезная опция <tt>-l (--last-run)</tt> означает «все пакеты, которые repocop-run тестировал при последнем запуске».
полезная опция <tt>-l (--last-run)</tt> означает "все пакеты, которые repocop-run тестировал при последнем запуске".
Таким образом, сразу после запуска repocop-run для проверки всего репозитория имеет смысл вызвать
Таким образом, сразу после запуска repocop-run для проверки всего репозитория имеет смысл вызвать  
<tt>repocop-purge-except --last-run</tt>, чтобы устаревшие данные из кеша не попали в отчёт,
<tt>repocop-purge-except --last-run</tt>, чтобы устаревшие данные из кеша не попали в отчет,
а сразу после запуска repocop-run для проверки пробной сборки имеет смысл вызвать
а сразу после запуска repocop-run для проверки пробной сборки имеет смысл вызвать  
<tt>repocop-purge-given --last-run</tt>, чтобы удалить из кеша данные о пробной сборке, ещё не попавшей в репозиторий.
<tt>repocop-purge-given --last-run</tt>, чтобы удалить из кеша данные о пробной сборке, еще не попавшей в репозиторий.


Результаты тестов можно просмотреть либо непосредственно в кеше, либо воспользоваться каким-либо
Результаты тестов можно просмотреть либо непосредственно в кеше, либо воспользоваться каким-либо
генератором отчетов, например, <tt>repocop-report-txt</tt>.  
генератором отчетов, например, <tt>repocop-report-txt</tt>.
<tt>repocop-report-txt</tt> обработает кеш и сложит результаты тестов в читабельном виде
<tt>repocop-report-txt</tt> обработает кеш и сложит результаты тестов в читабельном виде
в подпапку <repocop cache dir>/reports/txt/.
в подпапку <repocop workdir>/reports/txt/.


==== тестирование свежесобранных пакетов с помощью repocop-check. ====
==== Тестирование свежесобранных пакетов с помощью repocop-check ====


Утилита <tt>repocop-check</tt> -- busybox для занятого майнтайнера. Позволяет в одном вызове проверить
Утилита <tt>repocop-check</tt> busybox для занятого майнтайнера. Позволяет в одном вызове проверить
свежесобранные пакеты. (Сделано по заявке Дамира @damir).
свежесобранные пакеты без создания или установки базы repocop репозитория, для которого собран пакет.


Пример вызова:
Пример вызова:
repocop-check /hasher/repo/*/RPMS/hasher /hasher/repo/SRPMS/hasher
repocop-check /hasher/repo/*/RPMS/hasher /hasher/repo/SRPMS/hasher


Опция <tt>--newer <filename></tt> позволяет дополнительно отфильтровать те пакеты, которые новее, чем  
Опция <tt>--newer <filename></tt> позволяет дополнительно отфильтровать те пакеты, которые новее, чем
указанный <filename>.
указанный <filename>.


Исходный код.
При вызове <tt>repocop-check</tt> выполняются только тесты уровня пакета. Тесты уровня дистрибутива не выполняются.
<pre>#!/bin/sh -e
Чтобы проверить собранные пакеты тестами уровня дистрибутива, необходимо скачать и установить свежую базу repocop
repocop-run -q "$@"
и воспользоваться утилитой <tt>repocop-check-against-repository</tt>.
repocop-report-stdout "$@"
repocop-purge-given --no-db-vacuum -q "$@"</pre>


==== уход за кешем с помощью repocop-purge-*. ====
==== Уход за кешем с помощью repocop-purge-* ====


Для ухода за кешем используются утилиты <tt>repocop-purge-* </tt>.
Для ухода за кешем используются утилиты <tt>repocop-purge-* </tt>.
{| border="1"
 
{| class="standard"
!Утилита
!Описание
|-
|-
|
|class="shadow"|repocop-purge-except
repocop-purge-except
|очистить все записи, кроме относящихся к пакетам, данным как аргументы.
|
очистить все записи, кроме относящихся к пакетам, данным как аргументы.
|-
|-
|
|class="shadow"|repocop-purge-given
repocop-purge-given
|очистить все записи, относящиеся к пакетам, данным как аргументы.
|
|} <!-- Почему-то второй раз таблица повторяется и описание к ней... Баг? -->
очистить все записи, относящиеся к пакетам, данным как аргументы.
|}


 
опция <tt>-l (--last-run)</tt> означает «все пакеты, которые repocop-run тестировал при последнем запуске».
опция <tt>-l (--last-run)</tt> означает "все пакеты, которые repocop-run тестировал при последнем запуске".
Опция <tt>-l</tt> по своей природе очень коварна, так как человек через минуту забывает, что именно он
Опция <tt>-l</tt> по своей природе очень коварна, так как человек через минуту забывает, что именно он  
запускал последний раз. Так что рекомендуется использовать её больше в скриптах.
запускал последний раз. Так что рекомендуется использовать ее больше в скриптах.


пример вызова <tt>repocop-purge-* </tt> для очистки кеша от устаревших пакетов:
пример вызова <tt>repocop-purge-* </tt> для очистки кеша от устаревших пакетов:
repocop-purge-except /var/ftp/pub/Linux/ALT/Sisyphus/files/{SRPMS,i586/RPMS,i386/RPMS,noarch/RPMS}
repocop-purge-except /var/ftp/pub/Linux/ALT/Sisyphus/files/{SRPMS,i586/RPMS,i386/RPMS,noarch/RPMS}


==== Пример автоматизации тестирования репозитария с помощью repocop. ====
==== Пример автоматизации тестирования репозитория с помощью repocop ====


Указанный скрипт можно запускать после каждого обновления дистрибутива,
Указанный скрипт можно запускать после каждого обновления дистрибутива,
руками или через cron.
руками или через cron.
<pre>#!/bin/sh
<source lang="bash">
# you may choose alternative path to cachedir
#!/bin/sh
export REPOCOP_CACHEDIR=~/.repocop
# you may choose alternative path to workdir
export REPOCOP_WORKDIR=~/.repocop


# edit paths to repository below !!!
# edit paths to repository below !!!
Строка 143: Строка 143:
repocop-purge-except --last-run
repocop-purge-except --last-run
repocop-report-txt >/dev/null
repocop-report-txt >/dev/null
</source>


## sample code for publishing txt reports (by repocop-report-txt) on ftp ##
=== Запуск repocop для исправления пакетов ===
# uncomment and fix it.
{{Main|Repocop/RepairMiniHOWTO}}
# FTP_HOME=/var/ftp/pub/people/repocop
=== Как писать код, исправляющий пакеты, под repocop ===
# rm -rf $FTP_HOME/reports/txt
{{Main|Packaging Automation/Embedded Language/Repocop}}
# mkdir -p $FTP_HOME/reports
# cp -a $REPOCOP_CACHEDIR/reports/txt  $FTP_HOME/reports/


## code for qa-robot mail scam. see man qa-robot for details
=== Как писать тесты для repocop ===
qa-robot -m <sisyphus-cybertalk@???> -s repocop-warning repocop-report-qa-robot-warn
qa-robot -m <sisyphus-cybertalk@???> -s repocop-bugreport repocop-report-qa-robot-fail</pre>
 
=== Как писать тесты для repocop. ===


Тест в общем случае состоит из нескольких исполняемых файлов и файлов данных со специальными именами,
Тест в общем случае состоит из нескольких исполняемых файлов и файлов данных со специальными именами,
которые собраны в одном каталоге вида <tt><testname>/</tt>.
которые собраны в одном каталоге вида <tt><testname>/</tt>.
Исполняемые файлы, входящие в тест, получают аргументы через переменные.  
Исполняемые файлы, входящие в тест, получают аргументы через переменные.
Тест возвращают значение через вызов одной из команд repocop-test-skip, repocop-test-ok, repocop-test-warn, repocop-test-fail.
Тест возвращают значение через вызов одной из команд repocop-test-skip, repocop-test-ok, repocop-test-warn, repocop-test-fail.
Возвратить значение для каждого пакета нужно ровно 1 раз.
Возвратить значение для каждого пакета нужно ровно 1 раз.


{| border="1"
{| class="standard"
!Команда
!Описание
|-
|-
|
|repocop-test-skip
repocop-test-skip
|тесту нечего проверять в данном пакете.
|
тесту нечего проверять в данном пакете.
|-
|-
|
|repocop-test-ok
repocop-test-ok
|пакет попадает под определение теста и с ним все в порядке.
|
пакет попадает под определение теста и с ним все в порядке.
|-
|-
|
|repocop-test-experimental
repocop-test-experimental
|ошибок нет, но тест советует сделать экспериментальное/разрабатываемое изменение.
|
ошибок нет, но тест советует сделать экспериментальное/разрабатываемое изменение.
|-
|-
|
|repocop-test-info
repocop-test-info
|ошибок нет, есть замечания к пакету, пакет можно сделать лучше.
|
ошибок нет, есть замечания к пакету, пакет можно сделать лучше.
|-
|-
|
|repocop-test-warn
repocop-test-warn
|несущественная ошибка, пакет можно сделать лучше.
|
несущественная ошибка, пакет можно сделать лучше.
|-
|-
|
|repocop-test-fail
repocop-test-fail
|найдена существенная ошибка.
|
найдена существенная ошибка.
|}
|}


repocop-test-info, repocop-test-warn, repocop-test-fail в качестве аргументов принимают сообщение об ошибке.
repocop-test-info, repocop-test-warn, repocop-test-fail в качестве аргументов принимают сообщение об ошибке.
Дополнительная опция -k |--key <REPOCOP_PKG_KEY> позволяет явно указать пакет.
Дополнительная опция -k |--key <REPOCOP_PKG_KEY> позволяет явно указать пакет.
Подробнее использоание этой опции будет разобрано в разделе "Тесты -постпроцессоры".
Подробнее использование этой опции будет разобрано в разделе «Тесты-постпроцессоры».


Многие тесты совместно используют одни и те же данные. Примером может служить база данных rpm.db,  
Некоторые тесты тестируют не отдельный пакет, а весь репозиторий и по своей природе сразу получают список пакетов.
которая создается в процессе работы repocop. Для каждого пакета в ней содержатся список файлов, значения
Для ускорения работы вместо индивидуальных команд repocop-test-* можно воспользоваться командой
полей Group:, URL:, Requires:, Provides, скрипты %postun, и т. д., т.е. вся информация, которая содержится
repocop-test-import-tsv
в заголовке rpm пакета.  
 
Многие тесты совместно используют одни и те же данные. Примером может служить база данных rpm.db,
которая создаётся в процессе работы repocop. Для каждого пакета в ней содержатся список файлов, значения
полей Group:, URL:, Requires:, Provides, скрипты %postun, и т. д., то есть вся информация, которая содержится
в заголовке rpm пакета.


Кроме того, логика обработки данных меняется гораздо чаще, чем структура хранения данных.
Кроме того, логика обработки данных меняется гораздо чаще, чем структура хранения данных.
Чтобы повысить повторную используемость кода и не прогонять весь репозиторий через тесты каждый раз,
Чтобы повысить повторную используемость кода и не прогонять весь репозиторий через тесты каждый раз,
когда в тесте меняется логика, в repocop 0.07 введена новая сущность -- коллекторы (сборщики данных).
когда в тесте меняется логика, в repocop 0.07 введена новая сущность коллекторы (сборщики данных).
Коллекторы устроены в точности как тесты, но не возвращают никаких результатов, только собирают данные для своей базы.
Коллекторы устроены в точности как тесты, но не возвращают никаких результатов, только собирают данные для своей базы.
Собранные коллекторами данные могут использоваться в тестах при вызове скриптов <testname>/done.
Собранные коллекторами данные могут использоваться в тестах при вызове скриптов <testname>/posttest.


Это позволяет дорогие по машинному времени вызовы <testname>/test сосредоточить в коллекторах, а
Это позволяет дорогие по машинному времени вызовы <testname>/test сосредоточить в коллекторах, а
в тестах использовать дешевые вызовы <testname>/done.
в тестах использовать дешёвые вызовы <testname>/posttest.


Рекомендуемый формат хранения собранных коллектором данных -- файл SQLite. Архитектура repocop  
Рекомендуемый формат хранения собранных коллектором данных файл SQLite. Архитектура repocop
не запрещает альтернативные форматы хранения, но разнородные форматы данных могут затруднить
не запрещает альтернативные форматы хранения, но разнородные форматы данных могут затруднить
обработку данных тестами. Например, данные из разных файлов SQLite можно обработать одним запросом  
обработку данных тестами. Например, данные из разных файлов SQLite можно обработать одним запросом
SQLite, чего не скажешь о разнородных форматах.
SQLite, чего не скажешь о разнородных форматах.


==== Предопределенные имена для файлов, входящих в тест. ====
==== Предопределённые имена для файлов, входящих в тест ====
{| border="1"
 
{| class="standard"
!Имя!!Mode!!Функция
|-
|<testname>/init.sql.x||align="center"|644||Инициализация схемы БД под SQLite. X — версия схемы
|-
|<testname>/upgrade.sql.Y||align="center"|644||Скрипты обновления схемы БД до версии Y на SQL
|-
|-
|
|<testname>/upgrade||align="center"|755||Общий скрипт обновления схемы БД. Используется в случае, когда SQL недостаточно
имя
|
mode
|
функция
|-
|-
|
|<testname>/init||align="center"|755||Инициализатор коллекторов и попакетных тестов. Запускается 1 раз при запуске repocop
<testname>/init.sql.x
|
644
|
инициализация схемы БД под SQLite. X - версия схемы.
|-
|-
|
|<testname>/options||align="center"|755||Дополнительные настройки для теста. Читается 1 раз в начале работы repocop
<testname>/upgrade.sql.Y
|
644
|
скрипты обновления схемы БД до версии Y на  SQL.
|-
|-
|
|<testname>/filepattern||align="center"|755||паттерн (egrep -f) для файлов пакета, обрабатывамых тестом.  
<testname>/upgrade
|
755
|
общий скрипт обновления схемы БД. Используется в случае, когда SQL недостаточно.
|-
|-
|
|<testname>/test||align="center"|755||Обработчик пакетов. Будет запуcкаться для каждого обрабатываемого пакета
<testname>/init
|
755
|
Инициализатор. Запускается 1 раз при запуске repocop.
|-
|-
|
|<testname>/done||align="center"|755||Деструктор коллекторов и попакетных тестов. запускается 1 раз в конце работы repocop
<testname>/test
|
755
|
Обработчик пакетов. Будет запуcкаться для каждого обрабатываемого пакета.
|-
|-
|
|<testname>/purge||align="center"|755||Удаление устаревших записей из собственного кеша теста. Вызывается утилитами repocop-purge-*
<testname>/done
|
755
|
Подведение итогов и деструктор. запускается 1 раз в конце работы repocop.
|-
|-
|
|<testname>/purge.sql||align="center"|644||Удаление устаревших записей из собственной БД теста. Вызывается утилитами repocop-purge-*
<testname>/purge
|
755
|
Удаление устаревших записей из собственного кеша теста. Вызывается утилитами repocop-purge-*.
|-
|-
|
|<testname>/posttest||align="center"|755|| Обработчик коллекторов. запускается 1 раз в конце работы repocop
<testname>/purge.sql
|
644
|
Удаление устаревших записей из собственной БД теста. Вызывается утилитами repocop-purge-*.
|-
|-
|
|<testname>/description||align="center"|644||Описание теста. Не используется, но возможно использование в будущем
<testname>/description
|
644
|
Описание теста. Не используется, но возможно использование в будущем.
|}
|}


 
==== Упаковка тестов по каталогам в rpm пакете ====
==== Упаковка тестов в пакеты rpm ====
{| class="standard"
{| border="1"
!Имя
!Описание
|-
|-
|
|%_datadir/repocop/pkgtests/%testname/*
%_datadir/repocop/pkgtests/%testname/*
|тест бинарных пакетов
|
тест бинарных пакетов
|-
|-
|
|%_libdir/repocop/pkgtests/%testname/*
%_libdir/repocop/pkgtests/%testname/*
|тест бинарных пакетов
|
тест бинарных пакетов
|-
|-
|
|%_datadir/repocop/pkgcollectors/%testname/*
%_datadir/repocop/pkgcollectors/%testname/*
|коллектор бинарных пакетов
|
коллектор бинарных пакетов
|-
|-
|
|%_libdir/repocop/pkgcollectors/%testname/*
%_libdir/repocop/pkgcollectors/%testname/*
|коллектор бинарных пакетов
|
коллектор бинарных пакетов
|-
|-
|
|%_datadir/repocop/srctests/%testname/*
%_datadir/repocop/srctests/%testname/*
|тест исходных пакетов
|
тест исходных пакетов
|-
|-
|
|%_libdir/repocop/srctests/%testname/*
%_libdir/repocop/srctests/%testname/*
|тест исходных пакетов
|
тест исходных пакетов
|-
|-
|
|%_datadir/repocop/srccollectors/%testname/*
%_datadir/repocop/srccollectors/%testname/*
|коллектор исходных пакетов
|
коллектор исходных пакетов
|-
|-
|
|%_libdir/repocop/srccollectors/%testname/*
%_libdir/repocop/srccollectors/%testname/*
|коллектор исходных пакетов
|
коллектор исходных пакетов
|}
|}


==== Тесты без состояния ====


==== Тесты без состояния. ====
простейшим примером тестов являются тесты без состояния,
 
простейшим примером тестов являются тесты без состояния,  
которые помнят только текущий пакет и сразу выдают сообщение об ошибке.
которые помнят только текущий пакет и сразу выдают сообщение об ошибке.
Таким тестам не нужны <tt><testname>/init</tt> и <tt><testname>/done</tt>.  
Таким тестам не нужны <tt><testname>/init</tt> и <tt><testname>/done</tt>.
Они состоят из единственного скрипта <tt><testname>/test</tt>.
Они состоят из единственного скрипта <tt><testname>/test</tt>.


<tt><testname>/test</tt> вызывается для тех пакетов, которые еще не обрабатывались этим тестом.
<tt><testname>/test</tt> вызывается для тех пакетов, которые ещё не обрабатывались этим тестом.
Если файл <tt><testname>/test</tt> новее, чем результаты тестов, то они удаляются как устаревшие
Если файл <tt><testname>/test</tt> новее, чем результаты тестов, то они удаляются как устаревшие
и соответствующие пакеты проходят тест заново.
и соответствующие пакеты проходят тест заново.


Аргументы <tt><testname>/test</tt>:
Аргументы <tt><testname>/test</tt>:
REPOCOP_PKG_ROOT - директория, в которую распаковано содержимое пакета.
REPOCOP_PKG_KEY - внутренний id пакета в базах repocop. Используется в тестах с состоянием.
REPOCOP_PKG - полный путь к пакету.
также доступны
REPOCOP_PKG_NAME
REPOCOP_PKG_VERSION
REPOCOP_PKG_RELEASE
REPOCOP_PKG_EPOCH


тест без состояния упаковывается в rpm как %_datadir/repocop/pkgtests/%testname/test  
* REPOCOP_PKG_ROOT — директория
* REPOCOP_PKG_KEY — внутренний id пакета в базах repocop. Используется в тестах с состоянием
* REPOCOP_PKG — полный путь к пакету
также доступны:
* REPOCOP_PKG_NAME
* REPOCOP_PKG_VERSION
* REPOCOP_PKG_RELEASE
* REPOCOP_PKG_EPOCH
 
тест без состояния упаковывается в rpm как %_datadir/repocop/pkgtests/%testname/test
либо как %_libdir/repocop/pkgtests/%testname/test, в зависимости от языка, на котором он написан.
либо как %_libdir/repocop/pkgtests/%testname/test, в зависимости от языка, на котором он написан.


Простейший тест на shell:
Простейший тест на shell:
<pre>#!/bin/sh
<source lang="bash">
#!/bin/sh
grep -s -q -r $REPOCOP_PKG_NAME-buildroot $REPOCOP_PKG_ROOT/ && \
grep -s -q -r $REPOCOP_PKG_NAME-buildroot $REPOCOP_PKG_ROOT/ && \
exec repocop-test-fail "found paths to buildroot:" || exec repocop-test-ok</pre>
exec repocop-test-fail "found paths to buildroot:" || exec repocop-test-ok
</source>
тест не совсем корректный, так как на самом деле нужно искать $REPOCOP_SRC_NAME-buildroot (damir@)
тест не совсем корректный, так как на самом деле нужно искать $REPOCOP_SRC_NAME-buildroot (damir@)


Строка 378: Строка 310:
Packager: Igor Yu. Vlasenko <viy@altlinux.org>
Packager: Igor Yu. Vlasenko <viy@altlinux.org>


Summary: %testname intergration tests for repocop test platform.
Summary: %testname integration tests for repocop test platform
Group: Development/Other
Group: Development/Other
License: GPL or Artistic
License: GPL or Artistic


%description
%description
The test warns packages that ...
The test warns package maintainers that ...


%prep
%prep
Строка 401: Строка 333:


%changelog</pre>
%changelog</pre>
==== Корректное использование сторонних утилит в тестах ====


==== Тесты с состоянием. ====
Если тест вызывает для проверки пакетов сторонние утилиты, такие, как {{prg|sisyphus_check}} или {{prg|desktop-file-validate}},
то полученные результаты теста зависят не только от пакета и самого теста, но и от версии сторонней утилиты.
Поэтому корректный тест при изменениях в сторонней утилите должен сбрасывать результаты тестов.
Для сброса результатов тестов достаточно поменять timestamp у скрипта test.


Тест общего вида инициализирует свое состояние с помощью <tt><testname>/init.sql.*</tt>, (в общем случае - при вызове <tt><testname>/init</tt>).
'''Пример оформления проверки в rpm пакете с помощью rpm trigger.'''
По мере прохождения тест может накапливать информацию о пакетах, исспользуя <testname>/test,
<pre>
а в конце работы обработать ее и сообщить о найденных ошибках в скрипте <testname>/done.
%triggerin -- sisyphus_check
# if test itself is installed/updated, just keep build timestamp
[ $2 = 1 ] && exit 0 ||:
# at every sisyphus_check upgrade we should bump timestamp
# to discard cached results of old sisyphus_check
touch %_datadir/repocop/pkgtests/%testname/test
</pre>


Полезные переменные.
Заметим, что без дополнительной проверки
{| border="1"
<pre>
[ $2 = 1 ] && exit 0 ||:
</pre>
trigger вызывался бы и при установке/обновлении самого теста.
Это было бы плохо тем, что в результате невозможно было бы использовать кеш тестов repocop,
доступный в песочнице repocop.altlinux.org: почти всегда на локальной машине timestamp соответствующего теста был бы новее, чем у
теста, использующегося в песочнице.
 
==== Тесты с состоянием ====
 
Тест общего вида инициализирует своё состояние с помощью <tt><testname>/init.sql.*</tt>, (в общем случае — при вызове <tt><testname>/init</tt>).
По мере прохождения тест может накапливать информацию о пакетах, используя <testname>/test,
а в конце работы удалить промежуточные результаты в деструкторе <testname>/done и обработать её и сообщить о найденных ошибках в скриптах и <testname>/posttest.
 
{| class="standard"
|+Полезные переменные
!Переменная
!Описание
|-
|REPOCOP_TEST_STATEDIR
|личная постоянная директория. Обычно $REPOCOP_STATEDIR/$REPOCOP_TEST_NAME
|-
|-
|
|REPOCOP_STATEDIR
REPOCOP_TEST_CACHEDIR
|каталог, в котором хранятся личные постоянные директории тестов. Полезен для обращения к данным других тестов/коллекторов.
|
личная постоянная директория.
|-
|-
|
|REPOCOP_TEST_TMPDIR
REPOCOP_TEST_TMPDIR
|личная временная директория.
|
личная временная директория.
|-
|-
|
|REPOCOP_TEST_NAME
REPOCOP_TEST_NAME
|<testname>
|
<testname>.
|-
|-
|
|REPOCOP_TEST_DBDIR
REPOCOP_TEST_DBDIR
|каталог с базами данных SQLite установленных коллекторов.
|
каталог с базами данных SQLite установленных коллекторов.
|-
|-
|
|REPOCOP_TEST_DB
REPOCOP_TEST_DB
|личная база данных SQLite теста или коллектора.
|
личная база данных SQLite теста или коллектора.
|}
|}


в переменной REPOCOP_TEST_CACHEDIR тесту передается его личная постоянная директория,
В переменной REPOCOP_TEST_STATEDIR тесту передаётся его личная постоянная директория,
чтобы он мог хранить в ней свое состояние как между вызовами <testname>/test так и между
чтобы он мог хранить в ней свое состояние как между вызовами <testname>/test так и между
вызовами repocop-run. а в переменной REPOCOP_TEST_TMPDIR тесту передается его личная  
вызовами repocop-run, а в переменной REPOCOP_TEST_TMPDIR тесту передается его личная
временная директория, которая сохраняется между вызовами <testname>/test и в конце  
временная директория, которая сохраняется между вызовами <testname>/test и в конце
гарантированно удаляется силами repocop-run.
гарантированно удаляется силами repocop-run.


Строка 449: Строка 401:


Коллектор отличается от теста тем, что он никогда не вызывает <tt>repocop-test-*</tt>, и, следовательно,
Коллектор отличается от теста тем, что он никогда не вызывает <tt>repocop-test-*</tt>, и, следовательно,
единственным резудльтатом работы коллектора является создание базы данных.
единственным результатом работы коллектора является создание базы данных.
Также, для упаковки коллекторов предусмотрены каталоги
Также, для упаковки коллекторов предусмотрены каталоги
{| border="1"
{| class="standard"
!Каталог
!Описание
|-
|-
|
|%_datadir/repocop/pkgcollectors/%testname/*
%_datadir/repocop/pkgcollectors/%testname/*
|коллектор бинарных пакетов
|
коллектор бинарных пакетов
|-
|-
|
|%_libdir/repocop/pkgcollectors/%testname/*
%_libdir/repocop/pkgcollectors/%testname/*
|коллектор бинарных пакетов
|
коллектор бинарных пакетов
|-
|-
|
|%_datadir/repocop/srccollectors/%testname/*
%_datadir/repocop/srccollectors/%testname/*
|коллектор исходных пакетов
|
коллектор исходных пакетов
|-
|-
|
|%_libdir/repocop/srccollectors/%testname/*
%_libdir/repocop/srccollectors/%testname/*
|коллектор исходных пакетов
|
коллектор исходных пакетов
|}
|}


а для тестов -
а для тестов -
{| border="1"
{| class="standard"
!Каталог
!Описание
|-
|-
|
|%_datadir/repocop/pkgtests/%testname/*
%_datadir/repocop/pkgtests/%testname/*
|тест бинарных пакетов
|
тест бинарных пакетов
|-
|-
|
|%_libdir/repocop/pkgtests/%testname/*
%_libdir/repocop/pkgtests/%testname/*
|тест бинарных пакетов
|
тест бинарных пакетов
|-
|-
|
|%_datadir/repocop/srctests/%testname/*
%_datadir/repocop/srctests/%testname/*
|тест исходных пакетов
|
тест исходных пакетов
|-
|-
|
|%_libdir/repocop/srctests/%testname/*
%_libdir/repocop/srctests/%testname/*
|тест исходных пакетов
|
тест исходных пакетов
|}
|}


===== Инициализация коллектора =====


===== Инициализация коллектора. =====
Рекомендуемый формат хранения базы данных, собираемой коллектором файл SQLite с именем <tt><testname>.db</tt>,
 
расположенный в REPOCOP_TEST_DBDIR. repocop в значительной мере упрощает инициализацию баз данных такого
Рекомендуемый формат хранения базы данных, собираемой коллектором --- файл SQLite с именем <tt><testname>.db</tt>,  
вида. При наличии файла <tt><testname>/init.sql.x</tt> (инициализация схемы БД под SQLite. x версия схемы.) repocop
расположенный в REPOCOP_TEST_DBDIR. repocop в значительной мере упрощает инициализацию баз данных такого  
проверяет, есть ли уже файл REPOCOP_TEST_DBDIR/<testname>.db и при необходимости создаёт её из указанной схемы.
вида. При наличии файла <tt><testname>/init.sql.x</tt> (инициализация схемы БД под SQLite. x - версия схемы.) repocop  
проверяет, есть ли уже файл REPOCOP_TEST_DBDIR/<testname>.db и при необходимости создает из указанной схемы.


Если файл базы уже есть, то repocop запрашивает ее версию командой "PRAGMA user_version". Если эта версия и число x  
Если файл базы уже есть, то repocop запрашивает её версию командой «PRAGMA user_version». Если эта версия и число x
совпадают, на этом инициализация заканчивается. Если текущая версия больше х, то происходит аварийный останов.
совпадают, на этом инициализация заканчивается. Если текущая версия больше х, то происходит аварийный останов.
Если текущая версия больше х, то ищутся скрипты <tt><testname>/upgrade.sql.Y</tt>, где Y от currrent version+1 до x, и  
Если текущая версия меньше х, то ищутся скрипты <tt><testname>/upgrade.sql.Y</tt>, где Y от currrent version+1 до x, и
последовательно выполняются. Если найден скрипт <tt><testname>/upgrade</tt>, то он тоже выполняется.
последовательно выполняются. Если найден скрипт <tt><testname>/upgrade</tt>, то он тоже выполняется.
Если же скриптов обновления не найдено, то старая база удаляется. Также, если это тест, то его результаты тоже удаляются.
Если же скриптов обновления не найдено, то старая база удаляется. Также, если это тест, то его результаты тоже удаляются.
repocop автоматически помечает базу версией x и при апгрейде, и при созданиии.
repocop автоматически помечает базу версией x и при апгрейде, и при созданиии.


Альтернативно, коллектор может вести свою базу в REPOCOP_TEST_CACHEDIR в каком угодно формате.
Альтернативно, коллектор может вести свою базу в REPOCOP_TEST_STATEDIR в каком угодно формате.
В этом случае для инициализации предусмотрен скрипт <tt><testname>/init</tt>.
В этом случае для инициализации предусмотрен скрипт <tt><testname>/init</tt>.


===== Обработка коллектором пакетов. =====
===== Обработка коллектором пакетов =====


Обработка коллектором пакетов производится через вызовы <tt><testname>/test</tt> полностью аналогично тестам  
Обработка коллектором пакетов производится через вызовы <tt><testname>/test</tt> полностью аналогично тестам
без состояния. Единственное отличие в том, что коллектор использует переменную окружения REPOCOP_PKG_KEY  
без состояния. Единственное отличие в том, что коллектор использует переменную окружения REPOCOP_PKG_KEY
- внутренний id пакета в базах repocop. Коллектор не должен изобретать свои собственные идентификаторы пакета,
внутренний id пакета в базах repocop. Коллектор не должен изобретать свои собственные идентификаторы пакета,
а должен сохранять всю собранную информацию с этим REPOCOP_PKG_KEY.
а должен сохранять всю собранную информацию с этим REPOCOP_PKG_KEY.


===== Завершение работы коллектора. =====
===== Завершение работы коллектора =====


Если после работы коллектора остался какой-то мусор, его можно удалить в скрипте <tt><testname>/done</tt>.
Если после работы коллектора остался какой-то мусор, его можно удалить в скрипте <tt><testname>/done</tt>.


===== Уход за базой данных коллектора. =====
===== Уход за базой данных коллектора =====


Со временем БД коллектора накапливает устаревшие записи о пакетах, которых больше нет в репозитории.
Со временем БД коллектора накапливает устаревшие записи о пакетах, которых больше нет в репозитории.
Если коллектор хранит данные в базе вида REPOCOP_TEST_DBDIR/<testname>.db, то утилиты repocop-purge-*
Если коллектор хранит данные в базе вида REPOCOP_TEST_DBDIR/<testname>.db, то утилиты repocop-purge-*
удалят из всех таблиц, содержащих колонку PKGID (название заглавными буквами) строки, соответствующие  
удалят из всех таблиц, содержащих колонку PKGID (название заглавными буквами) строки, соответствующие
устаревшим pkgid. (pkgid - это то, что передается коллектору в переменной окружения REPOCOP_PKG_KEY).
устаревшим pkgid. (pkgid это то, что передается коллектору в переменной окружения REPOCOP_PKG_KEY).
После этого дополнительно вызывается SQL скрипт <tt><testname>/purge.sql</tt>, если он существует.
После этого дополнительно вызывается SQL скрипт <tt><testname>/purge.sql</tt>, если он существует.


Если же коллектор использует свое собственное хранилище, для удаления устаревших записей из собственного  
Если же коллектор использует своё собственное хранилище, для удаления устаревших записей из собственного
кеша теста он должен предоставить скрипт <tt><testname>/purge</tt>.
кеша теста он должен предоставить скрипт <tt><testname>/purge</tt>.
утилиты repocop-purge-* вызовут этот скрипт автоматически.
Утилиты repocop-purge-* вызовут этот скрипт автоматически. В качестве аргумента передается одна
из опций <tt>--except</tt> либо <tt>--given</tt>, с тем же значением, что и в утилитах repocop-purge-*,
а на stdin будет подан список pkgid, по одному pkgid на строку.
 
==== Постпроцессоры ====
скрипты <tt><testname>/posttest</tt> и <tt><testname>/distrotest</tt> вызываются после завершения цикла работы тестов и коллекторов пакетов,
и, также, возможно, после вызова утилит <tt>repocop-purge-*</tt>.
Они предназначены для обработки баз данных, собранных коллекторами.
Постпроцессоры также делятся на коллекторы и тесты (см. далее).
Кроме того, с целью оптимизации работы repocop они дополнительно разделены еще на два класса:
<tt><testname>/posttest</tt> (посттесты) и <tt><testname>/distrotest</tt> (дистротесты).
К <tt><testname>/posttest</tt> относятся тесты, результат работы которых зависит только от самого тестируемого пакета.
Результат такого теста не меняется, пока не изменится сам пакет.
К дистротестам <tt><testname>/distrotest</tt> относятся тесты, результат работы которых зависит от состояния
дистрибутива, точнее, контекста, в котором выполняется тест.
Примером дистротеста является тест на файловый конфликт. Пусть пакет A конфликтует по файлам с пакетом B
и дистротест показывает этот конфликт. Если пакет В изменится так, что конфликт исчезнет, то результат дистротеста
для пакета A изменится, не смотря на то, что пакет A не менялся.
 
Как следствие, посттесты можно запускать всегда и в любом контексте,
А дистротест -- только если
* из базы вычищены старые версии пакетов утилитами <tt>repocop-purge-*</tt>
* им обеспечен максимально возможный контекст (т.е. коллекторами repocop'а
обработан весь дистрибутив).


==== Тесты -постпроцессоры ====
Поэтому по умолчанию скрипт {{prg|repocop-run}} не запускает дистротесты. Для их запуска у него есть опция
{{term|--distrotest}}.


Постпроцессор -- это тест, который '''не''' тестирует отдельные пакеты, а использует готовые базы данных,
собранные коллекторами. Такой тест состоит из единственного скрипта <tt><testname>/done</tt>.
Допустимо, что тест-постпроцессор не использует статус skip для пакетов, которые не попадают под действие теста,
в связи с тем, что статус skip им присваивается по умолчанию. Однако не желательно,
хотя и допустимо , что тест-постпроцессор не использует статус ok.
Поскольку при вызове <tt>repocop-test-*</tt> отсутствует естественный контекст (текущий пакет), то постпроцессор
должен явно указывать пакет, на который вешается статус. Для этого утилитам <tt>repocop-test-*</tt> передается
опция <tt>-k|--key <pkgid></tt>, где <pkgid> в свое время был получен соответствующим коллектором через
переменную окружения REPOCOP_PKG_KEY и сохранен им в своей базе.


Пример простого теста-постпроцессора.
===== Тесты-постпроцессоры =====
<pre>#!/bin/sh                                                                       
 
Постпроцессор — это тест, который '''не''' тестирует отдельные пакеты, а использует готовые базы данных,
собранные коллекторами. Такой тест состоит из единственного скрипта <tt><testname>/posttest</tt>.
Допускается, что тест-постпроцессор может пометить каким-либо статусом только часть пакетов из присутствующих в базе.
У остальных пакетов по умолчанию для этого теста будет статус skip.
Поскольку при вызове <tt>repocop-test-*</tt> отсутствует естественный контекст (текущий пакет), то постпроцессор должен явно указывать пакет, которому присваивается статус. Для этого утилитам <tt>repocop-test-*</tt> передаётся опция <tt>-k|--key <pkgid></tt>, где <pkgid> в своё время был получен соответствующим коллектором через переменную окружения REPOCOP_PKG_KEY и сохранён им в своей базе.
 
Пример простого теста-постпроцессора:
<source lang="bash">
#!/bin/sh                                                                       
sqlite3 "$REPOCOP_TEST_DBDIR/altlinux-alternatives.db" <<EOSQL
sqlite3 "$REPOCOP_TEST_DBDIR/altlinux-alternatives.db" <<EOSQL
.mode tabs
.mode tabs
Строка 562: Строка 525:
for i in `cat $REPOCOP_TEST_TMPDIR/warn`; do repocop-test-warn -k $i  "xml format of alternatives is obsolete"; done
for i in `cat $REPOCOP_TEST_TMPDIR/warn`; do repocop-test-warn -k $i  "xml format of alternatives is obsolete"; done
for i in `cat $REPOCOP_TEST_TMPDIR/ok`; do repocop-test-ok -k $i; done
for i in `cat $REPOCOP_TEST_TMPDIR/ok`; do repocop-test-ok -k $i; done
rm $REPOCOP_TEST_TMPDIR/*</pre>
rm $REPOCOP_TEST_TMPDIR/*
==== Тесты пакетов с исходниками. ====
</source>


тесты пакетов с исходниками аналогичны тестам бинарных пакетов, за исключением того, что
===== Коллекторы-постпроцессоры =====
 
Иногда нескольким тестам-постпроцессорам для своей работы необходимо вычислить один и тот же промежуточный набор данных.
в этом случае удобно выделить вычисление этих данных в отдельный скрипт <tt><testname>/posttest</tt>,
который сохраняет результаты своей работы в промежуточной базе данных для последующего использования
тестами-постпроцессорами. Такие скрипты будем называть коллекторы-постпроцессоры.
 
Коллекторы относят к тем же типам (<tt><testname>/posttest</tt> и <tt><testname>/distrotest</tt>)
что и тесты-постпроцессоры, которые ими пользуются. Т.е. коллектор, используемый тестами
<tt><testname>/posttest</tt>, тоже должен быть <tt><testname>/posttest</tt>.
 
==== Тесты пакетов с исходниками ====
 
Аналогичны тестам бинарных пакетов за исключением того, что
они устанавливаются в <tt>%_datadir/repocop/srctests/</tt>.
они устанавливаются в <tt>%_datadir/repocop/srctests/</tt>.
тестам передается в переменной  
Тестам передается в переменной
REPOCOP_PKG - полный путь к src.rpm пакету.
* REPOCOP_PKG полный путь к src.rpm пакету.
REPOCOP_PKG_ROOT - директория, в которую распаковано содержимое пакета.  
* REPOCOP_PKG_ROOT директория, в которую распаковано содержимое пакета.
(для пакетов с исходниками по умолчанию распаковывается только spec-файл.  
(для пакетов с исходниками по умолчанию распаковывается только spec-файл.
содержимомое src.rpm - нужно ли это будет кому-то?)
содержимомое src.rpm нужно ли это будет кому-то?)
Дополнительно в переменной REPOCOP_PKG_SPECFILE передается полный путь к спек-файлу.
Дополнительно в переменной REPOCOP_PKG_SPECFILE передаётся полный путь к спек-файлу.
также доступны
также доступны:
REPOCOP_PKG_NAME
* REPOCOP_PKG_NAME
REPOCOP_PKG_VERSION
* REPOCOP_PKG_VERSION
REPOCOP_PKG_RELEASE
* REPOCOP_PKG_RELEASE
REPOCOP_PKG_EPOCH
* REPOCOP_PKG_EPOCH
и т. д., полностью аналогично тестам бинарных пакетов.
и т. д., полностью аналогично тестам бинарных пакетов.


пример простейшего теста.
пример простейшего теста.
<pre>if OUTPUT=`rpmquery -p --requires $REPOCOP_PKG | egrep '(xorg-x11-devel|XFree86-devel)'`; then  
<source lang="bash">
if OUTPUT=`rpmquery -p --requires $REPOCOP_PKG | egrep '(xorg-x11-devel|XFree86-devel)'`; then  
   exec repocop-test-warn "Please, refresh your BuildRequires: using buildreq." \
   exec repocop-test-warn "Please, refresh your BuildRequires: using buildreq." \
" The following obsolete dependencies blow up the build:" $OUTPUT
" The following obsolete dependencies blow up the build:" $OUTPUT
else  
else  
     exec repocop-test-skip
     exec repocop-test-skip
fi</pre>
fi
</source>


=== Исходный код ===
=== Исходный код ===


Можно получить [http://sisyphus.ru/find.shtml?request=repocop в Sisyphus] и [http://git.altlinux.org/people/viy/packages/?p=repocop.git;a=summary в git].
Можно получить в [http://packages.altlinux.org/ru/search?utf8=%E2%9C%93&branch=Sisyphus&query=repocop Sisyphus] и [http://git.altlinux.org/people/viy/packages/?p=repocop.git;a=summary git].
 
{| class="wide"
| Разработано при поддержке [http://www.fasie.ru/ Фонда содействия развитию МП НТС] в рамках НИОКР 01201066526
| [[Изображение:Logo_FASIE_preview.jpg|200px|rigft]]
|}

Текущая версия от 13:07, 12 сентября 2022


tumb

Малый огромный боевой робот, созданный безумными учёными для тестирования отдельных rpm пакетов или всего Сизифа.

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

Другими словами, repocop представляет собой платформу для запуска интеграционных тестов. В её состав входит собственно пускатель тестов, различные генераторы отчётов из полученных результатов, а также генератор патчей для исправления найденных ошибок, если это возможно. Сами тесты в repocop не входят. Тесты оформлены как отдельные пакеты, поэтому набор тестов легко конфигурируется.

Результаты ежедневного тестирования Sisyphus публикуются на repocop.altlinux.org а так же доступны через web-интерфейс prometheus2.0 на packages.altlinux.org.

Например, для мейнтейнера viy@ удобными ссылками на результаты тестирования будут: по пакетам, по ACL и по лидеру пакетов. Сгенерированные патчи можно просмотреть: по ACL и по лидеру пакетов.

Установка

Установка repocop на локальной машине:

apt-get install repocop repocop-unittests-local

repocop состоит из следующих пакетов:

Пакет Описание
repocop Основной пакет
repocop-tools Инструменты для исправления пакетов силами repocop. Не обязателен.
repocop-prometeus Плагин к prometeus. Не нужен при обычной установке

Сами тесты вместе с пакетом не идут, их надо устанавливать отдельно.

Полный список тестов можно посмотреть на http://packages.altlinux.org/.

Для удобства виртуальный пакет repocop-unittest позволяет установить все официальные тесты, которые используются в sisyphus-cybertalk@ и на packages.altlinux.org.

Запуск repocop для тестирования пакетов

  • Пример запуска repocop для тестирования свежесобранных пакетов:
    repocop-run ~/hasher/repo/*/RPMS.hasher/*.rpm
  • Пример запуска repocop для тестирования репозитория:
    repocop-run /var/ftp/pub/Linux/ALT/Sisyphus/files/{noarch,i586}/RPMS

При повторном запуске будут тестироваться только новые пакеты, так как результаты тестов сохраняются в <repocop workdir>. По умолчанию <repocop workdir> равно ~/.repocop. Значение по умолчанию для <repocop workdir> можно переопределить с помощью опции --workdir <repocop workdir> либо поменять с помощью переменной окружения REPOCOP_WORKDIR. Например, так: export REPOCOP_WORKDIR=/tmp/.private/user/repocop.

Для ухода за кешем используются утилиты repocop-purge-* .

Утилита Описание
repocop-purge-except очистить все записи, кроме относящихся к пакетам, данным как аргументы.
repocop-purge-given очистить все записи, относящиеся к пакетам, данным как аргументы.

полезная опция -l (--last-run) означает «все пакеты, которые repocop-run тестировал при последнем запуске». Таким образом, сразу после запуска repocop-run для проверки всего репозитория имеет смысл вызвать repocop-purge-except --last-run, чтобы устаревшие данные из кеша не попали в отчёт, а сразу после запуска repocop-run для проверки пробной сборки имеет смысл вызвать repocop-purge-given --last-run, чтобы удалить из кеша данные о пробной сборке, ещё не попавшей в репозиторий.

Результаты тестов можно просмотреть либо непосредственно в кеше, либо воспользоваться каким-либо генератором отчетов, например, repocop-report-txt. repocop-report-txt обработает кеш и сложит результаты тестов в читабельном виде в подпапку <repocop workdir>/reports/txt/.

Тестирование свежесобранных пакетов с помощью repocop-check

Утилита repocop-check — busybox для занятого майнтайнера. Позволяет в одном вызове проверить свежесобранные пакеты без создания или установки базы repocop репозитория, для которого собран пакет.

Пример вызова: repocop-check /hasher/repo/*/RPMS/hasher /hasher/repo/SRPMS/hasher

Опция --newer <filename> позволяет дополнительно отфильтровать те пакеты, которые новее, чем указанный <filename>.

При вызове repocop-check выполняются только тесты уровня пакета. Тесты уровня дистрибутива не выполняются. Чтобы проверить собранные пакеты тестами уровня дистрибутива, необходимо скачать и установить свежую базу repocop и воспользоваться утилитой repocop-check-against-repository.

Уход за кешем с помощью repocop-purge-*

Для ухода за кешем используются утилиты repocop-purge-* .

Утилита Описание
repocop-purge-except очистить все записи, кроме относящихся к пакетам, данным как аргументы.
repocop-purge-given очистить все записи, относящиеся к пакетам, данным как аргументы.

опция -l (--last-run) означает «все пакеты, которые repocop-run тестировал при последнем запуске». Опция -l по своей природе очень коварна, так как человек через минуту забывает, что именно он запускал последний раз. Так что рекомендуется использовать её больше в скриптах.

пример вызова repocop-purge-* для очистки кеша от устаревших пакетов: repocop-purge-except /var/ftp/pub/Linux/ALT/Sisyphus/files/{SRPMS,i586/RPMS,i386/RPMS,noarch/RPMS}

Пример автоматизации тестирования репозитория с помощью repocop

Указанный скрипт можно запускать после каждого обновления дистрибутива, руками или через cron.

#!/bin/sh
# you may choose alternative path to workdir
export REPOCOP_WORKDIR=~/.repocop

# edit paths to repository below !!!
repocop-run /var/ftp/pub/Linux/ALT/Sisyphus/files/{noarch,i586}/RPMS

repocop-purge-except --last-run
repocop-report-txt >/dev/null

Запуск repocop для исправления пакетов

Основная статья: Repocop/RepairMiniHOWTO

Как писать код, исправляющий пакеты, под repocop

Основная статья: Packaging Automation/Embedded Language/Repocop


Как писать тесты для repocop

Тест в общем случае состоит из нескольких исполняемых файлов и файлов данных со специальными именами, которые собраны в одном каталоге вида <testname>/. Исполняемые файлы, входящие в тест, получают аргументы через переменные. Тест возвращают значение через вызов одной из команд repocop-test-skip, repocop-test-ok, repocop-test-warn, repocop-test-fail. Возвратить значение для каждого пакета нужно ровно 1 раз.

Команда Описание
repocop-test-skip тесту нечего проверять в данном пакете.
repocop-test-ok пакет попадает под определение теста и с ним все в порядке.
repocop-test-experimental ошибок нет, но тест советует сделать экспериментальное/разрабатываемое изменение.
repocop-test-info ошибок нет, есть замечания к пакету, пакет можно сделать лучше.
repocop-test-warn несущественная ошибка, пакет можно сделать лучше.
repocop-test-fail найдена существенная ошибка.

repocop-test-info, repocop-test-warn, repocop-test-fail в качестве аргументов принимают сообщение об ошибке. Дополнительная опция -k |--key <REPOCOP_PKG_KEY> позволяет явно указать пакет. Подробнее использование этой опции будет разобрано в разделе «Тесты-постпроцессоры».

Некоторые тесты тестируют не отдельный пакет, а весь репозиторий и по своей природе сразу получают список пакетов. Для ускорения работы вместо индивидуальных команд repocop-test-* можно воспользоваться командой

repocop-test-import-tsv

Многие тесты совместно используют одни и те же данные. Примером может служить база данных rpm.db, которая создаётся в процессе работы repocop. Для каждого пакета в ней содержатся список файлов, значения полей Group:, URL:, Requires:, Provides, скрипты %postun, и т. д., то есть вся информация, которая содержится в заголовке rpm пакета.

Кроме того, логика обработки данных меняется гораздо чаще, чем структура хранения данных. Чтобы повысить повторную используемость кода и не прогонять весь репозиторий через тесты каждый раз, когда в тесте меняется логика, в repocop 0.07 введена новая сущность — коллекторы (сборщики данных). Коллекторы устроены в точности как тесты, но не возвращают никаких результатов, только собирают данные для своей базы. Собранные коллекторами данные могут использоваться в тестах при вызове скриптов <testname>/posttest.

Это позволяет дорогие по машинному времени вызовы <testname>/test сосредоточить в коллекторах, а в тестах использовать дешёвые вызовы <testname>/posttest.

Рекомендуемый формат хранения собранных коллектором данных — файл SQLite. Архитектура repocop не запрещает альтернативные форматы хранения, но разнородные форматы данных могут затруднить обработку данных тестами. Например, данные из разных файлов SQLite можно обработать одним запросом SQLite, чего не скажешь о разнородных форматах.

Предопределённые имена для файлов, входящих в тест

Имя Mode Функция
<testname>/init.sql.x 644 Инициализация схемы БД под SQLite. X — версия схемы
<testname>/upgrade.sql.Y 644 Скрипты обновления схемы БД до версии Y на SQL
<testname>/upgrade 755 Общий скрипт обновления схемы БД. Используется в случае, когда SQL недостаточно
<testname>/init 755 Инициализатор коллекторов и попакетных тестов. Запускается 1 раз при запуске repocop
<testname>/options 755 Дополнительные настройки для теста. Читается 1 раз в начале работы repocop
<testname>/filepattern 755 паттерн (egrep -f) для файлов пакета, обрабатывамых тестом.
<testname>/test 755 Обработчик пакетов. Будет запуcкаться для каждого обрабатываемого пакета
<testname>/done 755 Деструктор коллекторов и попакетных тестов. запускается 1 раз в конце работы repocop
<testname>/purge 755 Удаление устаревших записей из собственного кеша теста. Вызывается утилитами repocop-purge-*
<testname>/purge.sql 644 Удаление устаревших записей из собственной БД теста. Вызывается утилитами repocop-purge-*
<testname>/posttest 755 Обработчик коллекторов. запускается 1 раз в конце работы repocop
<testname>/description 644 Описание теста. Не используется, но возможно использование в будущем

Упаковка тестов по каталогам в rpm пакете

Имя Описание
%_datadir/repocop/pkgtests/%testname/* тест бинарных пакетов
%_libdir/repocop/pkgtests/%testname/* тест бинарных пакетов
%_datadir/repocop/pkgcollectors/%testname/* коллектор бинарных пакетов
%_libdir/repocop/pkgcollectors/%testname/* коллектор бинарных пакетов
%_datadir/repocop/srctests/%testname/* тест исходных пакетов
%_libdir/repocop/srctests/%testname/* тест исходных пакетов
%_datadir/repocop/srccollectors/%testname/* коллектор исходных пакетов
%_libdir/repocop/srccollectors/%testname/* коллектор исходных пакетов

Тесты без состояния

простейшим примером тестов являются тесты без состояния, которые помнят только текущий пакет и сразу выдают сообщение об ошибке. Таким тестам не нужны <testname>/init и <testname>/done. Они состоят из единственного скрипта <testname>/test.

<testname>/test вызывается для тех пакетов, которые ещё не обрабатывались этим тестом. Если файл <testname>/test новее, чем результаты тестов, то они удаляются как устаревшие и соответствующие пакеты проходят тест заново.

Аргументы <testname>/test:

  • REPOCOP_PKG_ROOT — директория
  • REPOCOP_PKG_KEY — внутренний id пакета в базах repocop. Используется в тестах с состоянием
  • REPOCOP_PKG — полный путь к пакету

также доступны:

  • REPOCOP_PKG_NAME
  • REPOCOP_PKG_VERSION
  • REPOCOP_PKG_RELEASE
  • REPOCOP_PKG_EPOCH

тест без состояния упаковывается в rpm как %_datadir/repocop/pkgtests/%testname/test либо как %_libdir/repocop/pkgtests/%testname/test, в зависимости от языка, на котором он написан.

Простейший тест на shell:

#!/bin/sh
grep -s -q -r $REPOCOP_PKG_NAME-buildroot $REPOCOP_PKG_ROOT/ && \
exec repocop-test-fail "found paths to buildroot:" || exec repocop-test-ok

тест не совсем корректный, так как на самом деле нужно искать $REPOCOP_SRC_NAME-buildroot (damir@)

Пример спек-файла для упаковки теста repocop без состояния.

%define testname sampletest

Name: repocop-unittest-%testname
Version: 0.01
Release: alt1
BuildArch: noarch
Packager: Igor Yu. Vlasenko <viy@altlinux.org>

Summary: %testname integration tests for repocop test platform
Group: Development/Other
License: GPL or Artistic

%description
The test warns package maintainers that ...

%prep

%build
cat > test <<'EOF'
#!/bin/bash
# enter your test here
EOF

%install
mkdir -p %buildroot%_datadir/repocop/pkgtests/%testname/
install -m 755 test %buildroot%_datadir/repocop/pkgtests/%testname/

%files
%_datadir/repocop/pkgtests/%testname

%changelog

Корректное использование сторонних утилит в тестах

Если тест вызывает для проверки пакетов сторонние утилиты, такие, как sisyphus_check или desktop-file-validate, то полученные результаты теста зависят не только от пакета и самого теста, но и от версии сторонней утилиты. Поэтому корректный тест при изменениях в сторонней утилите должен сбрасывать результаты тестов. Для сброса результатов тестов достаточно поменять timestamp у скрипта test.

Пример оформления проверки в rpm пакете с помощью rpm trigger.

%triggerin -- sisyphus_check
# if test itself is installed/updated, just keep build timestamp
[ $2 = 1 ] && exit 0 ||:
# at every sisyphus_check upgrade we should bump timestamp
# to discard cached results of old sisyphus_check
touch %_datadir/repocop/pkgtests/%testname/test

Заметим, что без дополнительной проверки

[ $2 = 1 ] && exit 0 ||:

trigger вызывался бы и при установке/обновлении самого теста. Это было бы плохо тем, что в результате невозможно было бы использовать кеш тестов repocop, доступный в песочнице repocop.altlinux.org: почти всегда на локальной машине timestamp соответствующего теста был бы новее, чем у теста, использующегося в песочнице.

Тесты с состоянием

Тест общего вида инициализирует своё состояние с помощью <testname>/init.sql.*, (в общем случае — при вызове <testname>/init). По мере прохождения тест может накапливать информацию о пакетах, используя <testname>/test, а в конце работы удалить промежуточные результаты в деструкторе <testname>/done и обработать её и сообщить о найденных ошибках в скриптах и <testname>/posttest.

Полезные переменные
Переменная Описание
REPOCOP_TEST_STATEDIR личная постоянная директория. Обычно $REPOCOP_STATEDIR/$REPOCOP_TEST_NAME
REPOCOP_STATEDIR каталог, в котором хранятся личные постоянные директории тестов. Полезен для обращения к данным других тестов/коллекторов.
REPOCOP_TEST_TMPDIR личная временная директория.
REPOCOP_TEST_NAME <testname>
REPOCOP_TEST_DBDIR каталог с базами данных SQLite установленных коллекторов.
REPOCOP_TEST_DB личная база данных SQLite теста или коллектора.

В переменной REPOCOP_TEST_STATEDIR тесту передаётся его личная постоянная директория, чтобы он мог хранить в ней свое состояние как между вызовами <testname>/test так и между вызовами repocop-run, а в переменной REPOCOP_TEST_TMPDIR тесту передается его личная временная директория, которая сохраняется между вызовами <testname>/test и в конце гарантированно удаляется силами repocop-run.

Тест общего вида может быть одновременно и коллектором, и постпроцессором, однако удобно, когда эти задачи разнесены в отдельные пакеты.

Коллекторы

Коллектор отличается от теста тем, что он никогда не вызывает repocop-test-*, и, следовательно, единственным результатом работы коллектора является создание базы данных. Также, для упаковки коллекторов предусмотрены каталоги

Каталог Описание
%_datadir/repocop/pkgcollectors/%testname/* коллектор бинарных пакетов
%_libdir/repocop/pkgcollectors/%testname/* коллектор бинарных пакетов
%_datadir/repocop/srccollectors/%testname/* коллектор исходных пакетов
%_libdir/repocop/srccollectors/%testname/* коллектор исходных пакетов

а для тестов -

Каталог Описание
%_datadir/repocop/pkgtests/%testname/* тест бинарных пакетов
%_libdir/repocop/pkgtests/%testname/* тест бинарных пакетов
%_datadir/repocop/srctests/%testname/* тест исходных пакетов
%_libdir/repocop/srctests/%testname/* тест исходных пакетов
Инициализация коллектора

Рекомендуемый формат хранения базы данных, собираемой коллектором — файл SQLite с именем <testname>.db, расположенный в REPOCOP_TEST_DBDIR. repocop в значительной мере упрощает инициализацию баз данных такого вида. При наличии файла <testname>/init.sql.x (инициализация схемы БД под SQLite. x — версия схемы.) repocop проверяет, есть ли уже файл REPOCOP_TEST_DBDIR/<testname>.db и при необходимости создаёт её из указанной схемы.

Если файл базы уже есть, то repocop запрашивает её версию командой «PRAGMA user_version». Если эта версия и число x совпадают, на этом инициализация заканчивается. Если текущая версия больше х, то происходит аварийный останов. Если текущая версия меньше х, то ищутся скрипты <testname>/upgrade.sql.Y, где Y от currrent version+1 до x, и последовательно выполняются. Если найден скрипт <testname>/upgrade, то он тоже выполняется. Если же скриптов обновления не найдено, то старая база удаляется. Также, если это тест, то его результаты тоже удаляются. repocop автоматически помечает базу версией x и при апгрейде, и при созданиии.

Альтернативно, коллектор может вести свою базу в REPOCOP_TEST_STATEDIR в каком угодно формате. В этом случае для инициализации предусмотрен скрипт <testname>/init.

Обработка коллектором пакетов

Обработка коллектором пакетов производится через вызовы <testname>/test полностью аналогично тестам без состояния. Единственное отличие в том, что коллектор использует переменную окружения REPOCOP_PKG_KEY — внутренний id пакета в базах repocop. Коллектор не должен изобретать свои собственные идентификаторы пакета, а должен сохранять всю собранную информацию с этим REPOCOP_PKG_KEY.

Завершение работы коллектора

Если после работы коллектора остался какой-то мусор, его можно удалить в скрипте <testname>/done.

Уход за базой данных коллектора

Со временем БД коллектора накапливает устаревшие записи о пакетах, которых больше нет в репозитории. Если коллектор хранит данные в базе вида REPOCOP_TEST_DBDIR/<testname>.db, то утилиты repocop-purge-* удалят из всех таблиц, содержащих колонку PKGID (название заглавными буквами) строки, соответствующие устаревшим pkgid. (pkgid — это то, что передается коллектору в переменной окружения REPOCOP_PKG_KEY). После этого дополнительно вызывается SQL скрипт <testname>/purge.sql, если он существует.

Если же коллектор использует своё собственное хранилище, для удаления устаревших записей из собственного кеша теста он должен предоставить скрипт <testname>/purge. Утилиты repocop-purge-* вызовут этот скрипт автоматически. В качестве аргумента передается одна из опций --except либо --given, с тем же значением, что и в утилитах repocop-purge-*, а на stdin будет подан список pkgid, по одному pkgid на строку.

Постпроцессоры

скрипты <testname>/posttest и <testname>/distrotest вызываются после завершения цикла работы тестов и коллекторов пакетов, и, также, возможно, после вызова утилит repocop-purge-*. Они предназначены для обработки баз данных, собранных коллекторами. Постпроцессоры также делятся на коллекторы и тесты (см. далее). Кроме того, с целью оптимизации работы repocop они дополнительно разделены еще на два класса: <testname>/posttest (посттесты) и <testname>/distrotest (дистротесты). К <testname>/posttest относятся тесты, результат работы которых зависит только от самого тестируемого пакета. Результат такого теста не меняется, пока не изменится сам пакет. К дистротестам <testname>/distrotest относятся тесты, результат работы которых зависит от состояния дистрибутива, точнее, контекста, в котором выполняется тест. Примером дистротеста является тест на файловый конфликт. Пусть пакет A конфликтует по файлам с пакетом B и дистротест показывает этот конфликт. Если пакет В изменится так, что конфликт исчезнет, то результат дистротеста для пакета A изменится, не смотря на то, что пакет A не менялся.

Как следствие, посттесты можно запускать всегда и в любом контексте, А дистротест -- только если

  • из базы вычищены старые версии пакетов утилитами repocop-purge-*
  • им обеспечен максимально возможный контекст (т.е. коллекторами repocop'а

обработан весь дистрибутив).

Поэтому по умолчанию скрипт repocop-run не запускает дистротесты. Для их запуска у него есть опция --distrotest.


Тесты-постпроцессоры

Постпроцессор — это тест, который не тестирует отдельные пакеты, а использует готовые базы данных, собранные коллекторами. Такой тест состоит из единственного скрипта <testname>/posttest. Допускается, что тест-постпроцессор может пометить каким-либо статусом только часть пакетов из присутствующих в базе. У остальных пакетов по умолчанию для этого теста будет статус skip. Поскольку при вызове repocop-test-* отсутствует естественный контекст (текущий пакет), то постпроцессор должен явно указывать пакет, которому присваивается статус. Для этого утилитам repocop-test-* передаётся опция -k|--key <pkgid>, где <pkgid> в своё время был получен соответствующим коллектором через переменную окружения REPOCOP_PKG_KEY и сохранён им в своей базе.

Пример простого теста-постпроцессора:

#!/bin/sh                                                                       
sqlite3 "$REPOCOP_TEST_DBDIR/altlinux-alternatives.db" <<EOSQL
.mode tabs
.output $REPOCOP_TEST_TMPDIR/warn
select distinct pkgid from altlinux_alternatives where altisxml>0;
.output $REPOCOP_TEST_TMPDIR/ok
select distinct pkgid from altlinux_alternatives where altisxml=0;
EOSQL
for i in `cat $REPOCOP_TEST_TMPDIR/warn`; do repocop-test-warn -k $i  "xml format of alternatives is obsolete"; done
for i in `cat $REPOCOP_TEST_TMPDIR/ok`; do repocop-test-ok -k $i; done
rm $REPOCOP_TEST_TMPDIR/*
Коллекторы-постпроцессоры

Иногда нескольким тестам-постпроцессорам для своей работы необходимо вычислить один и тот же промежуточный набор данных. в этом случае удобно выделить вычисление этих данных в отдельный скрипт <testname>/posttest, который сохраняет результаты своей работы в промежуточной базе данных для последующего использования тестами-постпроцессорами. Такие скрипты будем называть коллекторы-постпроцессоры.

Коллекторы относят к тем же типам (<testname>/posttest и <testname>/distrotest) что и тесты-постпроцессоры, которые ими пользуются. Т.е. коллектор, используемый тестами <testname>/posttest, тоже должен быть <testname>/posttest.

Тесты пакетов с исходниками

Аналогичны тестам бинарных пакетов за исключением того, что они устанавливаются в %_datadir/repocop/srctests/. Тестам передается в переменной

  • REPOCOP_PKG — полный путь к src.rpm пакету.
  • REPOCOP_PKG_ROOT — директория, в которую распаковано содержимое пакета.

(для пакетов с исходниками по умолчанию распаковывается только spec-файл. содержимомое src.rpm — нужно ли это будет кому-то?) Дополнительно в переменной REPOCOP_PKG_SPECFILE передаётся полный путь к спек-файлу. также доступны:

  • REPOCOP_PKG_NAME
  • REPOCOP_PKG_VERSION
  • REPOCOP_PKG_RELEASE
  • REPOCOP_PKG_EPOCH

и т. д., полностью аналогично тестам бинарных пакетов.

пример простейшего теста.

if OUTPUT=`rpmquery -p --requires $REPOCOP_PKG | egrep '(xorg-x11-devel|XFree86-devel)'`; then 
   exec repocop-test-warn "Please, refresh your BuildRequires: using buildreq." \
" The following obsolete dependencies blow up the build:" $OUTPUT
else 
     exec repocop-test-skip
fi

Исходный код

Можно получить в Sisyphus и git.

Разработано при поддержке Фонда содействия развитию МП НТС в рамках НИОКР 01201066526 rigft