TH3
Содержание
1. Обзор
SQLite Test Harness #3 (в дальнейшем «TH3») — один из трёх наборов инструментов для тестирования SQLite. TH3 отвечает следующим целям:
TH3 может работать на встроенных платформах, где отсутствует инфраструктура рабочих станций.
TH3 тестирует SQLite в конфигурации, как развернутой в работе, используя только опубликованные и документированные интерфейсы. Другими словами, TH3 тестирует скомпилированный объектный код, а не исходный код, таким образом проверяя, что ошибки не были введены ошибками компилятора. «Тестируйте то, что вы используете, и используйте то, что вы тестируете».
TH3 проверяет реакцию SQLite на ошибки недостатка памяти, ошибки ввода-вывода на диск и отключение питания во время фиксации транзакции.
TH3 проверяет SQLite в различных конфигурациях во время выполнения (UTF8 против UTF16, различные размеры страниц, различные режимы журнала и т. д.).
TH3 достигает 100% покрытия ветвей (и 100% MC/DC) для ядра SQLite. (Покрытие тестами расширений, таких как FTS и RTREE, ниже 100%).
TH3 изначально был написан только для валидационного тестирования, но впоследствии его также использовали для тестирования и отладки при разработке, и он оказался очень полезным в этих ролях. Полное тестирование занимает менее пяти минут на рабочей станции и, следовательно, служит быстрым регрессионным тестом во время повседневного обслуживания кодовой базы SQLite.
1.1. История
TH3 возник в результате попытки протестировать SQLite на SymbianOS. До TH3 все тесты SQLite выполнялись с использованием скриптового языка TCL, но TCL не (легко) компилировался на SymbianOS, что затрудняло тестирование. Первая попытка решения этой проблемы — скриптовый язык «TH1» (Test Harness #1) — представляла собой повторную реализацию частей языка TCL в более переносимой форме, которая компилировалась и работала на SymbianOS, и этого было достаточно для выполнения тестов SQLite. TH1 не выжил как стандартный инструмент тестирования для SQLite, но он продолжал использоваться в качестве скриптового языка для настройки системы управления версиями Fossil. Также существовал «Test Harness #2», который представлял собой попытку создать простой скриптовый язык с использованием префиксной записи операторов для управления тестами. TH3 стал третьей попыткой.
Примерно в то же время некоторые производители авиационной техники проявили интерес к SQLite, что побудило разработчиков SQLite спроектировать TH3 для поддержки строгих стандартов тестирования DO-178B.
Первый код TH3 был создан 25 сентября 2008 года. Напряженные усилия в течение следующих 10 месяцев позволили TH3 достичь 100% MC/DC 25 июля 2009 года. Код TH3 продолжает совершенствоваться и расширяться.
По состоянию на 19 мая 2018 года дерево исходного кода TH3 состоит и включает в себя более 500 000 строк исходного кода в 1709 отдельных файлах.
2. Работа
TH3 — это генератор тестовых программ. Выходной данные TH3 — программа, реализованная на языке C, предназначенная для компоновки с тестируемой библиотекой SQLite. Сгенерированная тестовая программа компилируется и выполняется на целевой платформе для проверки корректной работы SQLite на этой платформе.
Входными данными для TH3 являются тестовые модули, написанные на C или SQL, и небольшие файлы конфигурации, определяющие способ инициализации SQLite. В пакет TH3 включены 1444 тестовых модуля и более 47 конфигураций (по состоянию на 19 мая 2018 года). Можно добавлять новые модули и конфигурации для настройки TH3 под специализированные приложения. Каждый раз при запуске TH3 он считывает подмножество доступных тестовых модулей и файлов конфигурации для генерации пользовательской программы на C, которая выполняет все указанные тесты во всех указанных конфигурациях. Полное тестирование SQLite обычно включает многократный запуск TH3 для генерации нескольких тестовых программ, охватывающих различные аспекты работы SQLite, затем компоновку всех тестовых программ с общей библиотекой SQLite и отдельное их выполнение на целевой платформе.
В TH3 нет произвольных ограничений. Можно сгенерировать одну тестовую программу, содержащую все тестовые модули и все файлы конфигурации. Однако такая тестовая программа может быть слишком большой для развертывания на встроенных платформах. (По состоянию на 19 мая 2018 года, полное тестирование TH3 превышает 850 000 строк и 58 МБ кода C.) TH3 предоставляет возможность разбить библиотеку тестовых модулей на меньшие, более легко усваиваемые части.
Каждый отдельный тестовый модуль может содержать десятки, сотни или тысячи отдельных тестов. Тестовые модули могут быть написаны на C или как скрипты на SQL или смесь обоих. Примерно две трети существующих тестовых модулей написаны на чистом SQL, а остальные — либо на чистом C, либо в сочетании C и SQL.
Каждый файл тестового модуля содержит заголовок, описывающий условия, при которых тест действителен. Для определенной конфигурации выполняются только те модули, которые совместимы с конфигурацией.
3. Генерация тестовой программы
Программа-генератор TH3 — это скрипт TCL под названием «mkth3.tcl». Для генерации тестовой программы достаточно запустить этот скрипт и указать имена файлов, содержащих тестовые модули и конфигурации, в командной строке. Тестовые модули — это файлы, использующие суффикс «.test», а конфигурации — файлы, использующие суффикс «.cfg». Типичный вызов mkth3.tcl может выглядеть следующим образом:
tclsh mkth3.tcl *.test *.cfg >testprog1.c
Выходные данные скрипта mkth3.tcl — это программа на языке C, содержащая все необходимое для выполнения тестов — за исключением самой библиотеки SQLite. Сгенерированная тестовая программа содержит реализации всех вспомогательных интерфейсов, используемых тестовыми модулями, и содержит процедуру main() для управления тестами. Чтобы преобразовать тестовую программу в работающий исполняемый файл, просто скомпилируйте её с SQLite:
cc -o testprog1 testprog1.c sqlite3.c
Приведенный выше шаг компиляции — просто пример. В рабочем окружении обычно необходимо указать параметры оптимизации и переключатели времени компиляции в командной строке компилятора.
Для тестирования на встроенных системах скрипт mkth3.tcl и шаги компиляции, показанные выше, выполняются на обычной рабочей станции с помощью кросс-компилятора, а затем полученная тестовая программа передаётся на устройство для выполнения.
После генерации тестовой программы её запускают без аргументов для выполнения тестов. Информация о ходе выполнения и диагностика ошибок отображаются на стандартном выходе. (Альтернативные варианты вывода могут быть реализованы с помощью опции времени компиляции для встроенных устройств, на которых отсутствует стандартный канал вывода.) Программа возвращает ноль, если ошибок нет, и ненулевое значение, если были обнаружены какие-либо проблемы.
Типичный вывод после запуска одной тестовой программы TH3 выглядит следующим образом:
With SQLite 3.8.11 2015-05-15 04:13:15 56ef98a04765c34c1c2f3ed7a6f03a732f3b886e -DSQLITE_COVERAGE_TEST -DSQLITE_NO_SYNC -DSQLITE_SYSTEM_MALLOC -DSQLITE_THREADSAFE=1 Config-begin c1. Begin c1.pager08 End c1.pager08 Begin c1.build33 End c1.build33 Begin c1.orderby01 End c1.orderby01 ... 15014 lines of output omitted .... Begin 64k.syscall01 End 64k.syscall01 Begin 64k.build01 End 64k.build01 Begin 64k.auth01 End 64k.auth01 Config-end 64k. TH3 memory used: 6373738 Config-begin wal1. Begin wal1.wal37 End wal1.wal37 Config-end wal1. TH3 memory used: 100961 All 226 VDBE coverage points reached th3: 0 errors out of 1442264 tests in 213.741 seconds. 64-bit little-endian th3: SQLite 3.8.11 2015-05-15 04:13:15 56ef98a04765c34c1c2f3ed7a6f03a732f3b886e
Вывод начинается с отчета о SQLITE_SOURCE_ID (проверен повторно с помощью sqlite3_sourceid()) для тестируемой библиотеки SQLite и параметрах времени компиляции, сообщенных sqlite3_compileoption_get(). Вывод завершается сводкой результатов теста и повторным отображением SQLITE_SOURCE_ID. Если обнаружены какие-либо ошибки, дополнительные строки содержат детали проблемы. Строки отчетов об ошибках всегда начинаются с одного пробельного символа, чтобы их можно было быстро извлечь из больших файлов вывода с помощью:
grep "^ "
По умолчанию вывод показывает начало и конец каждой комбинации конфигурации и тестового модуля. В приведенном выше примере «c1» и «64k» являются конфигурациями, а «pager08», «build33», «orderby01» и т. д. — тестовыми модулями. Опции времени компиляции и выполнения позволяют увеличить или уменьшить объём вывода. Вывод можно увеличить, показав каждый тестовый случай в каждом тестовом модуле. Вывод можно уменьшить поэтапно: опуская начала и концы тестовых модулей, опуская начала и концы конфигурации и, наконец, опуская весь вывод.
3.1. Сценарии автоматизации тестирования
TH3 поставляется с дополнительными скриптами TCL, которые помогают автоматизировать процесс тестирования на рабочих станциях. Скрипт «th3make» автоматически запускает «mkth3.tcl» и «gcc», а затем запускает полученную тестовую программу и проверяет результаты. Аргументы th3make включают все тестовые модули "*.test" и конфигурации "*.cfg", которые должны быть включены в тест. Дополнительные опции th3make могут заставить тестовую программу быть скомпилированной с использованием разных компиляторов (GCC, Clang, MSVC), использовать разные уровни подробности вывода, запустить тестовую программу под valgrind, проверить вывод на предмет покрытия с использованием gcov и так далее. Скрипт th3make также принимает имена файлов "*.rc" в качестве аргументов. Эти файлы *.rc — просто наборы других аргументов, которые обычно используются вместе для одной цели. Например, файл «quick.rc» содержит набор из восьми аргументов для th3make, выполняющих быстрое (3-минутное) полное тестирование с покрытием. Это позволяет оператору ввести «./th3make quick.rc» в качестве сокращения для ввода всех необходимых опций командной строки. Ниже приведены несколько из более чем 40 доступных файлов *.rc:
- alignmentN.rc - Эти файлы содержат опции -D для компилятора, используемые различными важными подсистемами.
- cov.rc - Опции для измерения покрытия тестами
- extensions.rc - Опции для включения FTS4, R-деревьев и STAT4.
- fast.rc - Выполнение большинства тестов, включая те, которые не нужны для покрытия, пропускаются только тесты для прогрева, используя параметры компилятора для выпуска (например: -O3)
- memdebug.rc - как test.rc, но также включите -DSQLITE_MEMDEBUG.
- min.rc - Выполнение минимального набора тестов, необходимых для 100%-ного покрытия.
- quick.rc - Выполнение всех тестов, необходимых для 100%-ного покрытия тестами, с использованием -Os и -DSQLITE_DEBUG.
- test.rc - Выполнение тех же тестов, что и в fast.rc, но без оптимизации компилятора и включением опций, таких как -DSQLITE_DEBUG и -DSQLITE_ENABLE_EXPENSIVE_ASSERT.
- test-ex.rc - длительные тесты для прогрева.
Репозиторий TH3 также включает скрипт «multitest.tcl», ещё один скрипт TCL, используемый для автоматизации тестирования TH3 на рабочих станциях. Multitest.tcl автоматически компилирует SQLite, а затем многократно выполняет ./th3make с различными выравниваниями и собирает вывод в краткую сводочную экранную информацию. Типичный запуск multitest.tcl генерирует вывод, который выглядит так:
./multitest.tcl -q --jobs 3 start-time: 2018-05-19 03:17:12 UTC file mkdir sqlite3bld cd sqlite3bld exec sh /ramdisk/sqlite/configure file copy -force config.h ../config.h exec make clean sqlite3.c file rename sqlite3.c ../sqlite3.c file rename sqlite3.h ../sqlite3.h exec make clean sqlite3.c OPTS=-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 file rename sqlite3.c ../sqlite3udl.c exec make clean sqlite3.c OPTS=-DSQLITE_SMALL_STACK=1 file rename sqlite3.c ../sqlite3ss.c cd .. ******************************************************************************* t01: cov.rc.................................................... Ok (00:03:42) t02: cov.rc ++STAT4 ++DESERIALIZE -D_HAVE_SQLITE_CONFIG_H...... Ok (00:04:45) t03: vfs-cov.rc................................................ Ok (00:03:59) t04: demo.rc................................................... Ok (00:00:05) t07: test.rc ../th3private/*.test.............................. Ok (00:00:21) t08: test.rc ../th3private/*.test ++STAT4...................... Ok (00:01:41) t05: quick.rc.................................................. Ok (00:04:26) t09: quick.rc ~TEST_REALLOC_STRESS -funsigned-char............. Ok (00:05:39) t10: quick.rc ~THREADSAFE=0 -DLONGDOUBLE_TYPE=double........... Ok (00:03:24) t06: quick.rc extensions.rc -D_HAVE_SQLITE_CONFIG_H............ Ok (00:09:03) t11: quick.rc sqlite3ss.c ~MAX_ATTACHED=125.................... Ok (00:04:39) t12: quick.rc ~BYTEORDER=0 ++RTREE............................. Ok (00:07:28) t13: quick.rc ~DISABLE_INTRINSIC ++RTREE....................... Ok (00:07:31) t16: quick.rc ~TRACE_SIZE_LIMIT=15 cov1/main16.test............ Ok (00:00:22) t14: quick.rc ~DIRECT_OVERFLOW_READ -fsigned-char.............. Ok (00:04:35) t15: quick.rc ~UNTESTABLE ~EXTRA_IFNULLROW..................... Ok (00:01:44) t17: quick.rc ~MAX_MMAP_SIZE=0................................. Ok (00:04:46) t18: quick.rc ++NULL_TRIM ++OFFSET_SQL_FUNC.................... Ok (00:04:47) t19: quick.rc ++BATCH_ATOMIC_WRITE ++DESERIALIZE............... Ok (00:05:41) t20: lean1.rc quick.rc......................................... Ok (00:03:09) t22: test.rc alignment2.rc sqlite3udl.c........................ Ok (00:44:22) t21: test.rc alignment1.rc..................................... Ok (01:02:32) t23: memdebug1.rc extensions.rc................................ Ok (01:49:58) t25: valgrind1.rc -O3 extensions.rc............................ Ok (00:56:08) t24: memdebug2.rc extensions.rc................................ Ok (01:43:34) t27: test-ex1.rc............................................... Ok (00:45:00) t26: valgrind2.rc -O3 extensions.rc............................ Ok (01:02:52) t29: test-ex3.rc............................................... Ok (00:31:48) t28: test-ex2.rc............................................... Ok (01:12:03) t30: test-ex4.rc............................................... Ok (01:09:47) t32: test.rc alignment4.rc -m32 CC=clang....................... Ok (00:48:31) t31: test.rc alignment3.rc sqlite3udl.c........................ Ok (01:22:29) t34: test.rc alignment6.rc..................................... Ok (00:35:31) t33: test.rc alignment5.rc extensions.rc....................... Ok (00:59:33) t35: test.rc alignment7.rc..................................... Ok (00:44:10) t40: fast.rc alignment2.rc sqlite3udl.c........................ Ok (00:15:46) t39: fast.rc alignment1.rc extensions.rc -m32.................. Ok (00:33:19) t36: test.rc ~MUTATION_TEST.................................... Ok (00:35:45) t42: fast.rc alignment4.rc..................................... Ok (00:13:03) t43: fast.rc alignment5.rc..................................... Ok (00:13:32) t44: fast.rc alignment6.rc..................................... Ok (00:11:41) t41: fast.rc alignment3.rc sqlite3udl.c........................ Ok (00:26:31) t45: fast.rc alignment7.rc..................................... Ok (00:12:57) t46: fast.rc -fsanitize=undefined.............................. Ok (00:38:18) ******************************************************************************* 0 failures on 44 th3makes and 198583082 tests in (07:16:01) 3 cores on bella SQLite 3.24.0 2018-05-18 17:58:33 c6071ac99cfa4b6272ac4d739fc61a85acb544f6c1c2a
Как видно выше, один запуск multitest.tcl вызывает th3make десятки раз и занимает от 12 до 24 часов процессорного времени. Средняя часть вывода показывает аргументы каждого отдельного запуска th3make, а также результат и время выполнения для этого запуска th3make. Все продукты сборки и вывод для отдельных запусков th3make сохраняются в подкаталогах для последующего анализа. Двухстрочный сводный вывод внизу показывает общее количество ошибок и тестов по всем запускам th3make, а также общее время выполнения вместе с информацией SQLITE_SOURCE_ID для версии SQLite, которая тестировалась. Эта сводная информация записывается в сводный список изменений во время финального тестирования.
В выводе multitest.tcl используются сокращения, чтобы каждый вызов th3make помещался на одной строке вывода шириной 80 символов. Начальный глагол «th3make» опускается. "~" является сокращением для "-DSQLITE_" и "++" — для "-DSQLITE_ENABLE". Таким образом, строка вывода multitest.tcl
quick.rc ~DISABLE_INTRINSIC ++RTREE
на самом деле означает
th3make quick.rc -DSQLITE_DISABLE_INTRINSIC -DSQLITE_ENABLE_RTREE
4.Покрытие тестами
Используя определенный подмножество доступных модулей тестов TH3 («тесты cov1»), SQLite получило 100% покрытие ветвей тестов и 100% MC/DC, как измерено с помощью gcov на аппаратном обеспечении Linux x86 и x86_64. Все версии SQLite с момента версии 3.6.17 (2009-08-10) были протестированы по этому стандарту. Разработчики SQLite привержены поддержанию 100% покрытия ветвей и MC/DC для всех будущих релизов SQLite.
Набор тестов cov1, используемый для достижения 100% покрытия ветвей тестов, является лишь подмножеством тестов, реализованных в настоящее время с помощью TH3. Новые модули тестов добавляются регулярно.
5.Тестирование мутаций
Дерево исходного кода TH3 содержит скрипты «mutation-test.tcl», которые автоматизируют процесс тестирования мутаций.
Скрипт mutation-test.tcl заботится обо всех деталях выполнения теста мутаций:
- Скрипт компилирует тестовую среду TH3 в машинный код («th3.o»), если это необходимо.
- Скрипт компилирует исходный файл sqlite3.c в ассемблерный язык («sqlite3.s»), если это необходимо.
- Скрипт перебирает инструкции в файле ассемблерного языка, чтобы найти операции ветвления.
- Скрипт создает копию исходного файла sqlite3.s.
- Копия редактируется для изменения инструкции ветвления на недействие или безусловный переход.
- Копия sqlite3.s собирается в sqlite3.o, а затем снова связывается с th3.o для создания исполняемого файла «th3».
- Двоичный файл «th3» запускается, и вывод проверяется на наличие ошибок.
- Скрипт отображает ход выполнения для каждого цикла предыдущего шага, а затем отображает сводку «выживших» в конце. «Выживший» — это мутация, которая не была обнаружена TH3.
Тестирование мутаций может быть медленным, так как каждый тест может занимать до 5 минут на быстром рабочем станция, и есть два теста для каждой инструкции ветвления, а также более 20 000 инструкций ветвления. Прилагаются усилия для ускорения операций. Например, TH3 скомпилирован таким образом, что он завершается как только обнаруживает первую ошибку, а так как многие мутации легко обнаруживаются, многие циклы происходят всего за несколько секунд. Тем не менее, скрипт mutation-test.tcl включает опции командной строки для ограничения диапазона тестируемых строк кода, так что тестирование мутаций нужно выполнять только на блоках кода, которые недавно изменились.
6.Лицензия TH3
Сам SQLite находится в общественном достоянии и может использоваться для любых целей. Но TH3 является проприетарным и требует лицензии.
Несмотря на то, что пользователям с открытым исходным кодом нет прямого доступа к TH3, все пользователи SQLite косвенно извлекают выгоду из TH3, так как каждая версия SQLite проверяется с помощью TH3 на нескольких платформах (Linux, Windows, WinRT, Mac, OpenBSD) перед выпуском. Таким образом, любой, использующий официальную версию SQLite, может развертывать свое приложение, будучи уверенным в том, что оно было протестировано с помощью TH3. Они просто не могут повторно запустить эти тесты без покупки лицензии TH3.
Эта страница была последний раз изменена 08.01.2022 05:02:57 UTC
SQLite is in the Public Domain.
https://sqlite.org/th3.html