Регрессионные тесты

Регрессионные тесты представляют собой исчерпывающий набор проверок реализации SQL в QHB. Они тестируют как стандартные операции SQL, так и расширенные возможности QHB.



Выполнение тестов

Регрессионные тесты можно выполнять на уже установленном и работающем сервере либо используя временную инсталляцию внутри дерева сборки. Более того, существуют «параллельный» и «последовательный» режимы выполнения тестов. Последовательный метод выполняет каждый тестовый скрипт отдельно, тогда как параллельный метод запускает несколько серверных процессов, чтобы выполнить группы тестов параллельно. Параллельное тестирование добавляет уверенности, что межпроцессное взаимодействие и блокировки работают корректно.

Выполнение тестов на временной инсталляции

Чтобы запустить параллельные регрессионные тесты после сборки, но до установки, введите:

make check

в каталоге верхнего уровня. (Или можно перейти в /usr/local/qhb/test/regress и выполнить команду там.) По завершении вы должны увидеть что-то вроде:


=======================
 All 193 tests passed.
=======================

или примечание о тестах, в которых произошел сбой. Прежде чем предположить, что «сбой» представляет серьезную проблему, ознакомьтесь с разделом Оценка тестирования ниже.

Поскольку этот метод тестирования выполняется на временном сервере, он не будет работать, если вы выполнили сборку под пользователем root, так как сервер не запустится от имени root. Рекомендуется не делать сборку из-под root или же проводить тестирование после завершения установки.

Если вы сконфигурировали QHB для установки в месте, где уже существует предыдущая инсталляция QHB, и вы выполняете make check до установки новой версии, вы можете столкнуться с тем, что тесты завершаются сбоем, поскольку новые программы пытаются использовать уже установленные разделяемые библиотеки. (Типичные симптомы — жалобы на неопределенные символы.) Если вы хотите выполнить тестирование до перезаписи старой инсталляции, вам понадобится проводить сборку с configure --disable-rpath. Однако этот вариант не рекомендуется использовать для окончательной инсталляции.

Параллельное регрессионное тестирование запускает довольно много процессов под вашим идентификатором пользователя. В настоящее время максимум параллельной обработки составляет двадцать параллельных тестовых скриптов, что означает сорок процессов: это серверный процесс и процесс psql для каждого тестового скрипта. Поэтому если ваша система устанавливает ограничение на количество процессов для каждого пользователя, позаботьтесь о том, чтобы этот предел составлял не меньше пятидесяти процессов или около того, иначе в параллельном тестировании вы можете получить кажущиеся случайными сбои. Если вы не имеете права увеличить это предел, можно снизить степень параллелизма, установив параметр MAX_CONNECTIONS. Например:

make MAX_CONNECTIONS=10 check

выполняет не больше десяти тестов параллельно.


Выполнение тестов на существующей инсталляции

Чтобы запустить тесты после установки (см. главу Установка), инициализируйте каталог данных и запустите сервер, как показано в главе Настройка и эксплуатация сервера, затем введите:

make installcheck

или для параллельного тестирования:

make installcheck-parallel

Ожидается, что тесты будут соединяться с сервером на локальном хосте с номером порта по умолчанию, если иное не задано переменными среды PGHOST и PGPORT. Тесты будут выполняться в базе данных с именем regression; любая существующая база данных с таким именем будет удалена.

Также тесты будут на короткое время создавать некоторые объекты на уровне кластера, такие как роли, табличные пространства и подписки. Имена этих объектов будут начинаться с regress_. Остерегайтесь использовать режим installcheck в инсталляции, где такие имена могут иметь существующие глобальные объекты.


Дополнительные комплекты тестов

Команды make check и make installcheck запускают только «базовые» регрессионные тесты, которые проверяют встроенную функциональность сервера QHB. Исходный пакет содержит множество дополнительных комплектов тестов, большая часть которых касается дополнительной функциональности, например, дополнительных процедурных языков.

Чтобы запустить все комплекты тестов (включая базовые), применимые к модулям, выбранным для сборки, введите одну из этих команд на самом верху дерева сборки:

make check-world
make installcheck-world

Эти команды запускают тесты, используя временные серверы или уже установленный сервер соответственно, аналогично вышеописанным командам make check и make installcheck. Остальные аспекты также аналогичны изложенным выше для каждого метода. Обратите внимание, что make check-world собирает отдельный экземпляр (временный каталог данных) для каждого модуля, поэтому ей требуется больше времени и дискового пространства, чем make installcheck-world.

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

make check-world -j8 >/dev/null

где значение -j примерно равно или чуть больше количества доступных ядер. Отказ от вывода в stdout убирает избыток сообщений, которые не представляют интереса, когда вы хотите просто убедиться в успешности тестирования. (В случае ошибки сообщений в stderr обычно достаточно, чтобы определить, где искать проблему.)

Как вариант, вы можете запускать отдельные комплекты тестов, введя make check или make installcheck в подходящий подкаталог дерева сборки. Имейте в виду, что make installcheck предполагает, что вы уже установили соответствующие модули, а не только основной сервер.

Дополнительные тесты, которые можно выбрать таким способом:

  • Регрессионные тесты для дополнительных процедурных языков. Эти тесты расположены в каталоге /usr/local/qhb/pl.

  • Регрессионные тесты для модулей contrib, расположенные в каталоге share/extension. Не для всех модулей contrib существуют тесты.

  • Регрессионные тесты для библиотеки интерфейса ECPG, расположенные в /usr/local/qhb/interfaces/ecpg/test.

  • Тесты для поддерживаемых ядром методов аутентификации, расположенные в /usr/local/qhb/test/authentication. (Дополнительные тесты, связанные с аутентификацией, см. ниже.)

  • Тесты для нагрузочного тестирования параллельных сеансов, расположенные в /usr/local/qhb/test/isolation.

  • Тесты для восстановления после сбоя и физической репликации, расположенные в /usr/local/qhb/test/recovery.

  • Тесты для логической репликации, расположенные в /usr/local/qhb/test/subscription.

  • Тесты клиентских программ, расположенные в каталоге /usr/local/qhb/bin.

При использовании режима installcheck эти тесты будут создавать и удалять тестовые базы данных с именами, включающими слово regression, например, pl_regression или contrib_regression. Остерегайтесь использовать режим installcheck в инсталляции, где такие имена могут иметь какие-либо не тестовые базы данных.

Некоторые комплекты тестов не запускаются по умолчанию — либо потому, что их небезопасно выполнять в многопользовательской системе, либо потому, что им требуется специальное программное обеспечение. Вы можете выбрать, какие именно комплекты тестов запустить дополнительно, установив в переменной PG_TEST_EXTRA (она может быть переменной make или среды) их список через пробел, например:

make check-world PG_TEST_EXTRA='kerberos ldap ssl'

В настоящее время поддерживаются следующие значения:

kerberos
Запускает комплект тестов, проверяющих функциональность Kerberos/GSSAPI, в подкаталоге /usr/local/qhb/test/kerberos. Эти тесты требуют наличия полной инсталляции MIT Kerberos, включая инструментальные средства на стороне сервера и клиента, и открывают прослушивающие сокеты TCP/IP.

ldap
Запускает комплект тестов, проверяющих функциональность LDAP, в подкаталоге /usr/local/qhb/test/ldap. Эти тесты требуют наличия полной инсталляции OpenLDAP , включая инструментальные средства на стороне сервера и клиента. Кроме того, этот комплект тестов создает сервер LDAP, принимающий подключения по TCP/IP на localhost без какого-либо фактического управления доступом.

ssl
Запускает комплект тестов для регрессионного тестирования поддержки SSL в подкаталоге /usr/local/qhb/test/ssl. Они проверяют как функциональность на стороне клиента (т. е. сертификаты сервера), так и функциональность на стороне сервера (т. е. подтверждение сертификата). Эти тесты открывают прослушивающие сокеты TCP/IP.

Тесты функциональности, которая не поддерживается в текущей конфигурации сборки, не запускаются, даже если они указаны в PG_TEST_EXTRA.

Кроме того, существуют дополнительные тесты, которые будут запускаться make check-world, но не make installcheck-world. Это связано с тем, что они устанавливают расширения, неподходящие для производственной среды, или имеют иные побочные эффекты, которые считаются нежелательными для рабочей инсталляции. При желании можно выполнить в подкаталогах с этими тестами make install и make installcheck, но делать это с не тестовым сервером не рекомендуется.


Локаль и кодировка

По умолчанию тесты, выполняющиеся на временной инсталляции, используют локаль, определенную в текущей среде, и соответствующую кодировку базы данных, выбранную при выполнении qhb_bootstrap (или initdb). Может быть полезно протестировать различные локали, установив подходящие переменные среды, например:

make check LANG=C
make check LC_COLLATE=en_US.utf8 LC_CTYPE=fr_CA.utf8

По причинам реализации установка переменной LC_ALL для этой цели не работает; все остальные переменные среды, относящиеся к локали, работают.

При тестировании на существующей инсталляции локаль определяется существующим кластером базы данных и не может быть установлена отдельно для выполнения теста.

Также можно явно выбрать кодировку базы данных, установив переменную ENCODING, например:

make check LANG=C ENCODING=EUC_JP

Установка кодировки базы данных таким способом обычно имеет смысл только для локали C; в противном случае кодировка выбирается автоматически из локали, и указание кодировки, не соответствующей локали, приведет к ошибке.

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


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

При выполнении комплекта регрессионных тестов можно использовать пользовательские параметры сервера, которые задаются в переменной среды PGOPTIONS (для параметров, которые это позволяют):

make check PGOPTIONS="-c force_parallel_mode=regress -c work_mem=50MB"

При выполнении на временной инсталляции пользовательские параметры также можно установить, предоставив предварительно написанный файл qhb.conf:

echo 'log_checkpoints = on' > test_qhb.conf
echo 'work_mem = 50MB' >> test_qhb.conf
make check EXTRA_REGRESS_OPTS="--temp-config=test_qhb.conf"

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


Дополнительные тесты

Комплект основных регрессионных тестов содержит несколько тестовых файлов, которые не запускаются по умолчанию, поскольку они могут зависеть от платформы или выполняться слишком. Вы можете запустить те или иные дополнительные тестовые файлы, установив переменную EXTRA_TESTS. Например, запустить тест numeric_big:

make check EXTRA_TESTS=numeric_big

Тестирование сервера горячего резерва

Исходный пакет также содержит регрессионные тесты для статического поведения сервера горячего резерва. Для этих тестов требуются работающий основной сервер и работающий резервный сервер, принимающий новые изменения WAL от основного (используя либо трансляцию файлов журнала, либо потоковую репликацию). Эти серверы не создаются для вас автоматически, равно как и настройка репликации здесь не описывается. Пожалуйста, сверьтесь с различными разделами данного руководства, посвященными необходимым командам и смежным вопросам.

Для запуска тестирования сервера горячего резерва сначала создайте базу данных regression на основном сервере:

psql -h primary -c "CREATE DATABASE regression"

Затем на основном сервере в базе данных regression запустите предварительный скрипт /usr/local/qhb/test/regress/sql/hs_primary_setup.sql, например:

psql -h primary -f /usr/local/qhb/test/regress/sql/hs_primary_setup.sql regression

Разрешите этим изменениям распространиться на резервный сервер.

Теперь сделайте так, чтобы при тестировании подключение по умолчанию у базы данных выполнялось к резервному серверу (например, установив переменные среды PGHOST и PGPORT). Наконец, выполните make standbycheck в каталоге регрессионных тестов:

cd src/test/regress
make standbycheck

Также, чтобы протестировать поведение резервного сервера, можно сгенерировать на основном сервере некоторые экстремальные условия, применив скрипт /usr/local/qhb/test/regress/sql/hs_primary_extremes.sql.



Оценка тестирования

Некоторые правильно установленные и полностью функциональные инсталляции QHB могут вызывать «сбой» в некоторых из этих регрессионных тестов из-за специфических для платформы артефактов, таких как различное представление чисел с плавающей запятой и формулировка сообщений. В настоящее время тесты оцениваются с помощью простого сравнения diff с выходными данными, сгенерированными в эталонной системе, поэтому результаты чувствительны к небольшим различиям между системами. Когда сообщается о «сбое» в тесте, всегда проверяйте разницу между ожидаемыми и фактическими результатами; возможно, вы обнаружите, что разница не существенна. Тем не менее мы все же стремимся поддерживать точные эталонные файлы на всех поддерживаемых платформах, чтобы можно было ожидать прохождения всех тестов.

Актуальные результаты регрессионных тестов хранятся в файлах каталога /usr/local/qhb/test/regress/results. Тестовый скрипт использует команду diff, чтобы сравнить каждый файл результата с ожидаемыми результатами, хранящимися в каталоге /usr/local/qhb/test/regress/expected. Все различия сохраняются для проверки в /usr/local/qhb/test/regress/regression.diffs. (При выполнении комплекта тестов, отличного от основного, эти файлы, разумеется, появляются в соответствующем подкаталоге, а не в /usr/local/qhb/test/regress.)

Если вам не нравятся параметры, используемые в diff по умолчанию, установите переменную среды PG_REGRESS_DIFF_OPTS, например PG_REGRESS_DIFF_OPTS='-c'. (Или, если хотите, можете запустить diff самостоятельно.)

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


Различия в сообщениях об ошибках

Некоторые регрессионные тесты предусматривают применение заведомо недопустимых входных значений. Сообщения об ошибках могут исходить как из кода QHB, так и из системных подпрограмм платформы хоста. В последнем случае сообщения могут различаться в зависимости от платформы, но должны отражать одинаковую информацию. Эти различия в сообщениях приводят к «сбою» регрессионного теста, который можно устранить при проверке.


Разница локалей

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

Чтобы запустить тесты на другой локали при использовании метода тестирования на временной инсталляции, передайте в командной строке make подходящие переменные среды, относящиеся к локали, например:

make check LANG=de_DE.utf8

(Драйвер регрессионного теста обнуляет LC_ALL, поэтому выбор локали с помощью этой переменной не работает.) Чтобы не использовать локаль, либо обнулите все переменные среды, относящиеся к локали (или установите их в C), либо выполните следующую специальную команду:

make check NO_LOCALE=1

При выполнении тестов на существующей инсталляции настройки локали определяются этой инсталляцией. Чтобы изменить это, инициализируйте кластер баз данных с другой локалью, передав qhb_bootstrap (или initdb) соответствующие параметры.

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


Разница в дате и времени

Большая часть результатов проверки даты и времени зависит от часового пояса среды. Эталонные файлы генерируются для пояса PST8PDT (Беркли, Калифорния), поэтому если проводить тесты не с этим часовым поясом, появятся мнимые сбои. Драйвер регрессионного теста устанавливает в переменной среды PGTZ значение PST8PDT, что обычно гарантирует получение корректных результатов.


Разница в числах с плавающей запятой

Некоторые тесты предусматривают вычисление 64-битных чисел с плавающей запятой (double precision) из столбцов таблицы. Наблюдались различия в результатах при использовании математических функций для столбцов double precision. Тесты float8 и geometry особенно предрасположены выдавать небольшие различия между платформами или даже между настройками оптимизации компилятора. Чтобы определить реальную значимость этих отличий, которые обычно начинаются с десятого знака после запятой, нужно сравнивать их глазами.

Некоторые системы отображают минус ноль как -0, тогда как другие отображают просто 0.

Некоторые системы сигнализируют об ошибках в pow() и exp() не по тому механизму, какой ожидает текущий код QHB.


Разница в сортировке строк

Возможно, вам встретятся различия в том, что одни и те же строки выводятся в ином порядке, нежели в файле ожидаемых результатов. В большинстве случаев это не является, строго говоря, ошибкой. Большая часть скриптов регрессионных тестов не настолько педантична, чтобы использовать ORDER BY для каждого отдельного SELECT, и поэтому в их результате порядок строк не конкретизируется согласно спецификации SQL. На практике, поскольку мы имеем дело с одинаковыми запросами, выполняющимися для одних и тех же данных на одном и том же программном обеспечении, мы обычно получаем результаты в одинаковом порядке на всех платформах, так что отсутствие ORDER BY не является проблемой. Однако некоторые запросы действительно выявляют межплатформенные различия в сортировке. При тестировании на уже установленном сервере разница в сортировке также может быть вызвана тем, что локаль установлена не в C, или в каких-то параметрах заданы значения не по умолчанию, например, пользовательские значения в work_mem или параметры стоимости планировщика.

Поэтому, если вы видите различия в сортировке строк, не стоит об этом беспокоиться, если только в запросе не фигурирует условие ORDER BY, которое нарушает ваш результат. Причина, по которой это условие не было явно добавлено во все запросы регрессионных тестов, чтобы избавиться от таких ошибок раз и навсегда, заключается в том, что это снизит полезность регрессионных тестов, а не наоборот. В этом случае они бы имели тенденцию выполнять планы запросов, выдающих отсортированные результаты, и исключать запросы без сортировки.


Недостаточная глубина стека

Если тест errors приводит к краху сервера при выполнении команды select infinite_recurse(), это означает, что предел платформы для размера стека процесса меньше, чем показывает параметр max_stack_depth. Это можно исправить, запустив сервер с увеличенным пределом размера стека (рекомендованное значение по умолчанию для max_stack_depth составляет 4 МБ). Если вы не можете этого сделать, в качестве альтернативы можно уменьшить значение параметра max_stack_depth.

На платформах, поддерживающих функцию getrlimit(), сервер должен автоматически выбирать безопасное значение max_stack_depth; поэтому, если вы не переопределяли это значение вручную, сбой такого типа является ошибкой, подлежащей регистрации.


Тест «случайных результатов»

Тестовый скрипт random предназначен для получения случайных результатов. В очень редких случаях это приводит к сбоям в регрессионном тестировании. Выполнение:

diff results/random.out expected/random.out

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


Параметры конфигурации

При выполнении тестирования на существующей инсталляции некоторые нестандартные значения параметров могут вызвать сбои в тестах. Например, изменение таких параметров, как enable_seqscan или enable_indexscan может вызвать изменения в плане, которые повлияют на результаты тестов, использующих EXPLAIN.



Вариантные сравнительные файлы

Поскольку некоторые тесты заведомо выдают результаты, зависящие от среды, мы предоставили способы задавать вариантные «ожидаемые» файлы результата. Каждый регрессионный тест может иметь несколько сравнительных файлов, показывающих возможные результаты на разных платформах. Существует два независимых механизма для определения, какой именно сравнительный файл будет использоваться для каждого теста.

Первый механизм позволяет выбирать сравнительные файлы для конкретных платформ. Имеется файл сопоставления /usr/local/qhb/test/regress/resultmap, который определяет, какой сравнительный файл применить для каждой платформы. Чтобы устранить ложные «сбои» тестирования для конкретной платформы, сначала нужно выбрать или создать вариант файла результата, а затем добавить строку в файл resultmap.

Каждая строка в файле сопоставления имеет следующую форму:

testname:output:platformpattern=comparisonfilename

Имя теста (testname) — это просто имя конкретного модуля регрессионного теста. Значение output показывает, какой выходной файл проверять. Для стандартных регрессионных тестов это всегда out. Значение соответствует расширению выходного файла. Шаблон платформы (platformpattern) — это шаблон в стиле Unix-утилиты expr (то есть регулярное выражение с неявным ^ якорем в начале). Этот шаблон сопоставляется с именем платформы, которое выводится из config.guess. Имя сравнительного файла (comparisonfilename) — это базовое имя замещающего сравнительного файла для результата.

Пример: в некоторых системах отсутствует работающая функция strtof, для которой с нашим обходным приемом возникают ошибки округления в регрессионном тесте float4. Поэтому мы предоставляем вариант сравнительного файла float4-misrounded-input.out, содержащий результаты, ожидаемые в таких системах. Чтобы замаскировать сообщение о ложном «сбое» на платформах HP-UX 10, файл resultmap содержит строку:

float4:out:hppa.*-hp-hpux10.*=float4-misrounded-input.out

которая запустит наш файл на любой машине, где вывод config.guess совпадает с hppa.*-hp-hpux10.*. При необходимости в других строках resultmap будут выбираться варианты сравнительного файла для других платформ.

Второй механизм выбора для вариантных сравнительных файлов гораздо более автоматический: он просто использует наиболее соответствующий из нескольких предлагаемых сравнительных файлов. Скрипт драйвера регрессионного теста рассматривает стандартный сравнительный файл для теста, имя_теста.out, и вариантные файлы имя_теста_цифра.out (где цифра — любое одноразрядное число от 0 до 9). Если какой-нибудь из этих файлов полностью совпадает, тест считается пройденным; в противном случае для создания отчета об ошибке используется файл с наименьшим различием. (Если в resultmap содержится запись для конкретного теста, то в базовое имя_теста подставляется имя вариантного файла, заданное в resultmap.)

Например, для теста char сравнительный файл char.out содержит результаты, ожидаемые для локалей C и POSIX, тогда как файл char_1.out содержит результаты в том порядке, в каком они располагаются во многих других локалях.

Механизм наибольшего соответствия был разработан, чтобы справляться с результатами, зависящими от локали, но его можно использовать в любой ситуации, когда результаты теста сложно предсказать, исходя только из названия платформы. Ограниченность этого механизма заключается в том, что драйвер теста не может сказать, какой вариант действительно «корректный» для текущей среды; он просто выберет тот вариант, который покажется ему наиболее подходящим. Поэтому безопаснее всего использовать этот механизм только для вариантных результатов, которые вы готовы считать равно допустимыми во всех контекстах.



Проверка тестового покрытия

Исходный код QHB можно скомпилировать с инструментами определения тестового покрытия, благодаря чему появляется возможность проверить, какие части кода покрываются регрессионными тестами или любым другим комплектом тестов, выполняемым в коде. В настоящее время эта возможность поддерживается при компиляции с GCC и требует наличия программ gcov и lcov.

Типичный рабочий процесс выглядит так:

./configure --enable-coverage ... OTHER OPTIONS ...
make
make check # или другой комплект тестов
make coverage-html

Затем откройте в своем HTML-браузере страницу coverage/index.html.

Если у вас нет lcov или вы предпочитаете HTML-отчету текстовый вывод, вы можете выполнить

make coverage

вместо make coverage-html и получить выходные файлы .gcov для каждого исходного файла, относящегося к тесту. (Команды make coverage и make coverage-html перезапишут файлы друг друга, поэтому при одновременном их использовании может возникнуть путаница.)

Перед созданием отчета о тестовом покрытии можно запустить несколько различных тестов; счетчики выполнений будут накапливать значения. Если вы хотите сбросить счетчики выполнения между тестами, выполните:

make coverage-clean

Если вы хотите получить отчет о покрытии только для части дерева кода, можно запустить команду make coverage-html или make coverage в подкаталоге.

После завершения проверки выполните очистку с помощью make distclean.