Примечание: Эта статья была перенесена с веб-сайта документации CodeQL в январе 2023 г.
Сведения о тестировании пользовательских запросов
CodeQL предоставляет простую платформу тестирования для автоматического тестирования регрессии запросов. Протестируйте запросы, чтобы убедиться, что они работают должным образом.
Во время теста запроса CodeQL сравнивает результаты, которые пользователь ожидает получить от запроса, с фактически созданными. Если ожидаемые и фактические результаты отличаются, тест запроса завершается сбоем. Чтобы исправить тест, следует выполнить итерацию по запросу и ожидаемым результатам до тех пор, пока фактические и ожидаемые результаты точно не будут совпадать. В этом разделе показано, как создавать тестовые файлы и выполнять в них тесты с помощью test run
подкоманды.
Настройка тестового пакета CodeQL для пользовательских запросов
Все тесты CodeQL должны храниться в специальном пакете "тест" CodeQL. То есть каталог для тестовых файлов с файлом qlpack.yml
, который определяет:
name: <name-of-test-pack>
version: 0.0.0
dependencies:
<codeql-libraries-and-queries-to-test>: "*"
extractor: <language-of-code-to-test>
Значение dependencies
указывает пакеты CodeQL, содержащие тестируемые запросы.
Как правило, эти пакеты разрешаются из источника, поэтому указывать фиксированную версию пакета не требуется. Определяет extractor
язык, используемый CLI для создания тестовых баз данных из файлов кода, хранящихся в этом пакете CodeQL. Дополнительные сведения см. в разделе Сведения о пакетах CodeQL.
Может оказаться полезным посмотреть, как организованы тесты запросов в репозитории CodeQL. Каждый язык имеет src
каталог , ql/<language>/ql/src
который содержит библиотеки и запросы для анализа баз кода. Наряду с каталогом src
test
есть каталог с тестами для этих библиотек и запросов.
Каждый test
каталог настраивается как тестовый пакет CodeQL с двумя подкаталогами:
query-tests
ряд подкаталогов с тестами для запросов, хранящихся в каталогеsrc
. Каждый подкаталог содержит тестовый код и файл ссылки QL, указывающий тестируемый запрос.library-tests
ряд подкаталогов с тестами для файлов библиотеки QL. Каждый подкаталог содержит тестовый код и запросы, написанные как модульные тесты для библиотеки.
Настройка тестовых файлов для запроса
Для каждого запроса, который требуется протестировать, необходимо создать вложенный каталог в тестовом пакете CodeQL. Затем добавьте следующие файлы в подкаталог перед выполнением тестовой команды:
-
Файл ссылки на запрос (
.qlref
файл), определяющий расположение проверяемого запроса. Расположение определяется относительно корня пакета CodeQL, содержащего запрос. Обычно это пакет CodeQL, указанныйdependencies
в блоке тестового пакета. Дополнительные сведения см. в разделе Запрос ссылочных файлов.Не нужно добавлять файл ссылки на запрос, если тестируемый запрос хранится в тестовом каталоге, но обычно рекомендуется хранить запросы отдельно от тестов. Единственным исключением являются модульные тесты для библиотек QL, которые обычно хранятся в пакетах тестирования отдельно от запросов, создающих оповещения или пути.
-
Пример кода, для которого требуется выполнить запрос. Он должен состоять из одного или нескольких файлов, содержащих примеры кода, для идентификации в котором предназначен запрос.
Вы также можете определить результаты, которые должны отображаться при выполнении запроса к примеру кода, создав файл с расширением .expected
. Кроме того, можно оставить тестовую команду, чтобы создать .expected
файл.
Пример создания и тестирования запроса см. в примере ниже.
Важно: Файлы .ql
, .qlref
и .expected
должны иметь согласованные имена.
Если вы хотите напрямую указать .ql
сам файл в тестовой команде, он должен иметь то же базовое имя, что и соответствующий .expected
файл. Например, если запрос имеет значение MyJavaQuery.ql
, ожидаемый файл результатов должен иметь значение MyJavaQuery.expected
.
Если вы хотите указать .qlref
файл в команде, он должен иметь то же базовое имя, что и соответствующий .expected
файл, но сам запрос может иметь другое имя.
Имена примеров файлов кода не обязательно должны соответствовать другим тестовым файлам. Все примеры файлов кода, найденные рядом с файлом .qlref
(или .ql
) и в любых подкаталогах, будут использоваться для создания тестовой базы данных. Поэтому для простоты рекомендуется не сохранять тестовые файлы в каталогах, которые являются предками друг друга.
Работает codeql test run
Тесты запросов CodeQL выполняются с помощью следующей команды:
codeql test run <test|dir>
Аргумент <test|dir>
может быть одним или несколькими из следующих:
- Путь к файлу
.ql
. - Путь к файлу
.qlref
, который ссылается на.ql
файл. - Путь к каталогу, в который будет выполняться рекурсивный поиск по
.ql
файлам и.qlref
.
Также можно указать:
--threads:
при необходимости — количество потоков, используемых при выполнении запросов. По умолчанию используется1
параметр . Можно указать больше потоков для ускорения выполнения запросов. При указании0
число потоков совпадает с количеством логических процессоров.
Полные сведения обо всех параметрах, которые можно использовать при тестировании запросов, см. в справочной документации по тестового запуска.
Пример
В следующем примере показано, как настроить тест для запроса, который ищет в коде if
Java операторы с пустыми then
блоками. Он включает шаги по добавлению пользовательского запроса и соответствующих тестовых файлов для разделения пакетов CodeQL за пределами вашего репозитория CodeQL. Это гарантирует, что при обновлении библиотек CodeQL или извлечении другой ветви вы не будете перезаписывать пользовательские запросы и тесты.
Подготовка запросов и тестовых файлов
-
Разработка запроса. Например, следующий простой запрос находит пустые
then
блоки в коде Java:import java from IfStmt ifstmt where ifstmt.getThen() instanceof EmptyStmt select ifstmt, "This if statement has an empty then."
-
Сохраните запрос в файле с именем
EmptyThen.ql
в каталоге вместе с другими пользовательскими запросами. Например,custom-queries/java/queries/EmptyThen.ql
. -
Если вы еще не добавили пользовательские запросы в пакет CodeQL, создайте пакет CodeQL. Например, если пользовательские запросы Java хранятся в , добавьте
qlpack.yml
файл со следующим содержимым в :custom-queries/java/queries``custom-queries/java/queries
name: my-custom-queries dependencies: codeql/java-queries: "*"
Дополнительные сведения о пакетах CodeQL см. в разделе Сведения о пакетах CodeQL.
-
Создайте пакет CodeQL для тестов Java, добавив
qlpack.yml
файл со следующим содержимымcustom-queries/java/tests
вdependencies
, обновив в соответствии с именем пакета пользовательских запросов CodeQL:В следующем
qlpack.yml
файле указано, чтоmy-github-user/my-query-tests
зависитmy-github-user/my-custom-queries
от версии, больше или равной 1.2.3 и меньше 2.0.0. Он также объявляет, что CLI должен использовать Javaextractor
при создании тестовых баз данных. В строкеtests: .
объявляется, что все.ql
файлы в пакете должны выполняться как тесты приcodeql test run
выполнении с параметром--strict-test-discovery
. Как правило, тестовые пакеты не содержатversion
свойства . Это не позволит вам случайно опубликовать их.name: my-github-user/my-query-tests dependencies: my-github-user/my-custom-queries: ^1.2.3 extractor: java tests: .
-
В пакете тестирования Java создайте каталог, содержащий тестовые файлы, связанные с
EmptyThen.ql
. Например,custom-queries/java/tests/EmptyThen
. -
В новом каталоге создайте
EmptyThen.qlref
, чтобы определить расположениеEmptyThen.ql
. Путь к запросу должен быть указан относительно корня пакета CodeQL, содержащего запрос. В этом случае запрос находится в каталоге верхнего уровня пакета CodeQL с именемmy-custom-queries
, который объявляется как зависимость дляmy-query-tests
.EmptyThen.qlref
Поэтому должен просто содержатьEmptyThen.ql
. -
Создайте фрагмент кода для тестирования. Следующий код Java содержит пустой
if
оператор в третьей строке. Сохраните его вcustom-queries/java/tests/EmptyThen/Test.java
.class Test { public void problem(String arg) { if (arg.isEmpty()) ; { System.out.println("Empty argument"); } } public void good(String arg) { if (arg.isEmpty()) { System.out.println("Empty argument"); } } }
Выполнение теста
Чтобы выполнить тест, перейдите в custom-queries
каталог и выполните команду codeql test run java/tests/EmptyThen
.
При выполнении теста выполняется следующая команда:
-
Находит один тест в каталоге
EmptyThen
. -
Извлекает базу данных CodeQL из файлов,
.java
хранящихся в каталогеEmptyThen
. -
Компилирует запрос, на который
EmptyThen.qlref
ссылается файл.Если этот шаг завершается ошибкой, это связано с тем, что CLI не может найти пользовательский пакет CodeQL. Повторно выполните команду и укажите расположение пользовательского пакета CodeQL, например:
codeql test run --search-path=java java/tests/EmptyThen
Сведения о сохранении пути поиска в рамках конфигурации см. в разделе Указание параметров команд в файле конфигурации CodeQL.
-
Выполняет тест путем выполнения запроса и создания
EmptyThen.actual
файла результатов. -
Проверяет наличие
EmptyThen.expected
файла для сравнения с файлом.actual
результатов. -
Сообщает о результатах теста — в данном случае это сбой:
0 tests passed; 1 tests failed:
. Сбой теста, так как мы еще не добавили файл с ожидаемыми результатами запроса.
Просмотр выходных данных теста запроса
CodeQL создает в каталоге следующие файлы EmptyThen
:
EmptyThen.actual
— файл, содержащий фактические результаты, созданные запросом.EmptyThen.testproj
— тестовая база данных, которую можно загрузить в VS Code и использовать для отладки неудачных тестов. После успешного завершения тестов эта база данных удаляется на этапе обслуживания. Этот шаг можно переопределить, выполнив командуtest run
с параметром--keep-databases
.
В этом случае сбой был ожидаемым и его легко исправить. Если открыть EmptyThen.actual
файл, вы увидите результаты теста:
| Test.java:3:5:3:22 | stmt | This if statement has an empty then. |
Этот файл содержит таблицу со столбцом для расположения результата, а также отдельные столбцы для каждой select
части предложения, выводимой запросом.
Так как результаты являются ожидаемыми, мы можем обновить расширение файла, чтобы определить его как ожидаемый результат для этого теста (EmptyThen.expected
).
Если вы повторно запустите тест сейчас, выходные данные будут похожими, но они будут завершены путем создания отчета: All 1 tests passed.
.
Если результаты запроса изменяются, например при изменении инструкции select
для запроса, тест завершится ошибкой. Для неудачных результатов выходные данные ИНТЕРФЕЙСА командной строки содержат унифицированный дифф файлов EmptyThen.expected
и EmptyThen.actual
.
Этих сведений может быть достаточно для отладки тривиальных сбоев тестов.
Для сбоев, которые труднее отлаживать, можно импортировать EmptyThen.testproj
в CodeQL для VS Code, выполнить EmptyThen.ql
и просмотреть результаты в Test.java
примере кода. Дополнительные сведения см. в разделе Анализ проектов в справке CodeQL для VS Code.