Skip to main content

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

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

Кто может использовать эту функцию?

CodeQL доступен для следующих типов репозитория:

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

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 или извлекаете другую ветвь, вы не перезаписываете пользовательские запросы и тесты.

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

  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. Он также объявляет, что интерфейс командной строки должен использовать 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. Запустите codeql pack install в корне тестового каталога. При этом создается codeql-pack.lock.yml файл, указывающий все транзитивные зависимости, необходимые для выполнения запросов в этом пакете.

  6. В пакете тестирования Java создайте каталог, содержащий тестовые файлы, связанные с EmptyThen.ql. Например, custom-queries/java/tests/EmptyThen.

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

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

    Если этот шаг завершается ошибкой, это связано с тем, что интерфейс командной строки не может найти пользовательский пакет данных 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 и использовать для отладки неудачных тестов. После успешного завершения тестов эта база данных удаляется на этапе хранения. Этот шаг можно переопределить, --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.

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