Тестирование пользовательских запросов
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 , содержащие запросы для тестирования.
Как правило, эти пакеты будут разрешены из источника, поэтому не нужно указывать фиксированную версию пакета. Он определяет, какой язык будет использовать CLI для создания тестовых баз данных из кодовых файлов, 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 файл.
Пример создания и тестирования запроса см. в приведенном ниже примере .
Примечание.
`.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` с числом логических процессоров.
Полные сведения обо всех параметрах, которые можно использовать при тестировании запросов, см. в разделе тестовое выполнение.
Пример
В следующем примере показано, как настроить тест для запроса, который выполняет поиск кода 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файл.Если этот шаг не сработает, значит, 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 for VS Code, выполнить EmptyThen.ql, и посмотреть результаты в Test.java примерном коде. Дополнительные сведения см. в разделе Управление базами данных CodeQL.
Дополнительные материалы
-
[ CodeQL запросов](https://codeql.github.com/docs/writing-codeql-queries/codeql-queries/#codeql-queries) -
[AUTOTITLE](/code-security/codeql-for-vs-code/using-the-advanced-functionality-of-the-codeql-for-vs-code-extension/testing-codeql-queries-in-vs-code).