Skip to main content
Мы публикуем частые обновления нашей документации, и перевод этой страницы, возможно, еще выполняется. Актуальные сведения см. в документации на английском языке.

Тестирование пользовательских запросов

Вы можете настроить тесты для запросов CodeQL, чтобы убедиться, что они продолжают возвращать ожидаемые результаты в новых выпусках CodeQL CLI.

GitHub CodeQL лицензируется на уровне пользователя после установки. CodeQL можно использовать только для определенных задач в соответствии с лицензионными ограничениями. Дополнительные сведения см. в разделе Сведения о CodeQL CLI.

Если у вас есть учетная запись GitHub Enterprise и лицензия на GitHub Advanced Security, вы можете использовать CodeQL для автоматического анализа, непрерывной интеграции и непрерывной поставки. Вы можете создать корпоративную учетную запись, обратившись в отдел продаж. Дополнительные сведения см. в разделе Сведения о GitHub Advanced Security.

Примечание: Эта статья была перенесена с веб-сайта документации 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 или проверка другой ветви вы не будете перезаписывать пользовательские запросы и тесты.

Подготовка запросов и тестовых файлов

  1. Разработка запроса. Например, следующий простой запрос находит пустые then блоки в коде Java:

    import java
    
    from IfStmt ifstmt
    where ifstmt.getThen() instanceof EmptyStmt
    select ifstmt, "This if statement has an empty then."
    
  2. Сохраните запрос в файл с именем EmptyThen.ql в каталоге вместе с другими пользовательскими запросами. Например, custom-queries/java/queries/EmptyThen.ql.

  3. Если вы еще не добавили пользовательские запросы в пакет CodeQL, создайте пакет CodeQL. Например, если пользовательские запросы Java хранятся в custom-queries/java/queries, добавьте qlpack.yml файл со следующим содержимым в custom-queries/java/queries:

    name: my-custom-queries
    dependencies:
      codeql/java-queries: "*"
    

    Дополнительные сведения о пакетах CodeQL см. в разделе Сведения о пакетах CodeQL.

  4. Создайте пакет 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 должен использовать Java extractor при создании тестовых баз данных. В строке 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: .
    
  5. В пакете тестирования Java создайте каталог, содержащий тестовые файлы, связанные с EmptyThen.ql. Например, custom-queries/java/tests/EmptyThen.

  6. В новом каталоге создайте EmptyThen.qlref , чтобы определить расположение EmptyThen.ql. Путь к запросу должен быть указан относительно корня пакета CodeQL, содержащего запрос. В этом случае запрос находится в каталоге верхнего уровня пакета CodeQL с именем my-custom-queries, который объявлен как зависимость для my-query-tests. EmptyThen.qlref Поэтому должен просто содержать EmptyThen.ql.

  7. Создайте фрагмент кода для тестирования. Следующий код 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.

При выполнении теста выполняется следующая команда:

  1. Находит один тест в каталоге EmptyThen .

  2. Извлекает базу данных CodeQL из файлов, .java хранящихся в каталоге EmptyThen .

  3. Компилирует запрос, на который ссылается EmptyThen.qlref файл.

    Если этот шаг завершается сбоем, это связано с тем, что CLI не может найти пользовательский пакет CodeQL. Повторно выполните команду и укажите расположение пользовательского пакета CodeQL, например:

    codeql test run --search-path=java java/tests/EmptyThen

    Сведения о сохранении пути поиска в рамках конфигурации см. в разделе Указание параметров команды в файле конфигурации CodeQL.

  4. Выполняет тест, выполняя запрос и создавая EmptyThen.actual файл результатов.

  5. Проверяет наличие EmptyThen.expected файла для сравнения с файлом .actual результатов.

  6. Сообщает о результатах теста — в этом случае это ошибка: 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.

Дополнительные материалы