О тестировании пользовательских запросов
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
язык, который будет использоваться для создания тестовых баз данных из файлов кода, хранящихся в этом пакете CodeQL. Дополнительные сведения см. в разделе Настройка анализа с помощью пакетов CodeQL.
Вы можете найти полезное представление о том, как тесты запросов организованы в репозитории CodeQL. Каждый язык содержит src
каталог, ql/<language>/ql/src
содержащий библиотеки и запросы для анализа баз кода. Наряду с src
каталогом test
существует каталог с тестами для этих библиотек и запросов.
Каждый test
каталог настраивается как тестовый пакет CodeQL с двумя подкаталогами:
query-tests
ряд подкаталогов с тестами для запросов, хранящихся в каталогеsrc
. Каждая подкаталога содержит тестовый код и файл ссылки на QL, указывающий запрос для тестирования.library-tests
ряд подкаталогов с тестами для файлов библиотеки QL. Каждый подкаталог содержит тестовый код и запросы, написанные как модульные тесты для библиотеки.
После создания qlpack.yml
файла необходимо убедиться, что все зависимости скачиваются и доступны в CLI. Для этого выполните следующую команду в том же каталоге, что qlpack.yml
и файл:
codeql pack install
При этом будет создан codeql-pack.lock.yml
файл, указывающий все транзитивные зависимости, необходимые для выполнения запросов в этом пакете. Этот файл должен быть возвращен в систему управления версиями.
Настройка тестовых файлов для запроса
Для каждого запроса, который требуется протестировать, необходимо создать вложенный каталог в тестовом пакете CodeQL. Затем добавьте следующие файлы в подкаталог перед выполнением тестовой команды:
-
Файл ссылки на запрос (
.qlref
файл), определяющий расположение тестового запроса. Расположение определяется относительно корневого каталога пакета CodeQL, содержащего запрос. Обычно это пакет CodeQL, указанный вdependencies
блоке тестового пакета. Дополнительные сведения см. в разделе Запрос ссылочных файлов.Вам не нужно добавлять файл ссылки на запрос, если запрос, который требуется проверить, хранится в тестовом каталоге, но обычно рекомендуется хранить запросы отдельно от тестов. Единственным исключением является модульные тесты для библиотек QL, которые, как правило, хранятся в тестовых пакетах, отдельно от запросов, которые создают оповещения или пути.
-
Пример кода, для которого требуется выполнить запрос. Это должно состоять из одного или нескольких файлов, содержащих примеры кода, который предназначен для идентификации запроса.
Вы также можете определить результаты, которые будут отображаться при выполнении запроса в примере кода, создав файл с расширением .expected
. Кроме того, можно оставить тестовую команду, чтобы создать .expected
файл.
Пример создания и тестирования запроса см. в приведенном ниже примере .
Note
.qlref
Имена .ql
файлов и .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
с числом логических процессоров.
Полные сведения обо всех параметрах, которые можно использовать при тестировании запросов, см. в разделе "тестовое выполнение".
Пример
В следующем примере показано, как настроить тест для запроса, который выполняет поиск кода Java для if
инструкций с пустыми 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. Он также объявляет, что интерфейс командной строки должен использовать 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-kotlin tests: .
-
Запустите
codeql pack install
в корне тестового каталога. При этом создаетсяcodeql-pack.lock.yml
файл, указывающий все транзитивные зависимости, необходимые для выполнения запросов в этом пакете. -
В пакете тестирования 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
файл.Если этот шаг завершается ошибкой, это связано с тем, что интерфейс командной строки не может найти пользовательский пакет данных 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 и использовать для отладки неудачных тестов. После успешного завершения тестов эта база данных удаляется на этапе хранения. Этот шаг можно переопределить,--keep-databases
выполнивtest run
параметр.
В этом случае сбой ожидался и легко исправить. Если открыть 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.