Примечание: Эта статья была перенесена с веб-сайта документации 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
. Кроме того, можно оставить команду test, чтобы создать .expected
файл.
Пример создания и тестирования запроса см. в примере ниже.
Важно: Файлы .ql
, .qlref
и .expected
должны иметь согласованные имена.
Если вы хотите напрямую указать .ql
сам файл в команде test, он должен иметь то же базовое имя, что и соответствующий .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 хранятся в
custom-queries/java/queries
, добавьтеqlpack.yml
файл со следующим содержимым в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
для запроса, тест завершится ошибкой. Для неудачных результатов выходные данные CLI содержат унифицированный diff EmptyThen.expected
файлов и EmptyThen.actual
.
Этих сведений может быть достаточно для отладки тривиальных сбоев тестов.
Для сбоев, которые сложнее отлаживать, можно импортировать EmptyThen.testproj
в CodeQL для VS Code, выполнить EmptyThen.ql
и просмотреть результаты в Test.java
примере кода. Дополнительные сведения см. в разделе Анализ проектов в справке по CodeQL для VS Code.