Примечание: Эта статья была перенесена с веб-сайта документации По 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. Он также объявляет, что интерфейс командной строки должен использовать 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 включают единый различенный диффенд EmptyThen.expected файлов и EmptyThen.actual .
Этих сведений может быть достаточно для отладки тривиальных сбоев тестов.
Для сбоев, которые сложнее отлаживать, можно импортировать EmptyThen.testproj в CodeQL для VS Code, выполнить EmptyThen.qlи просмотреть результаты в Test.java примере кода. Дополнительные сведения см. в разделе Анализ проектов в справке по CodeQL для VS Code.