Testar consultas personalizadas
CodeQL fornece uma estrutura de teste simples para testes automatizados de regressão de consultas. Teste as consultas para garantir que elas se comportem conforme o esperado.
Durante um teste de consulta, CodeQL compara os resultados que o usuário espera que a consulta produza com os realmente produzidos. Se os resultados esperados e reais forem diferentes, o teste de consulta falhará. Para corrigir o teste, você deve iterar na consulta e nos resultados esperados até que os resultados reais e os resultados esperados correspondam exatamente. Este tópico mostra como criar arquivos de teste e executar testes neles usando o subcomando test run.
Configurando um pacote de teste CodeQL para consultas personalizadas
Todos os CodeQL testes devem ser armazenados em um pacote especial de "teste CodeQL ". Ou seja, um diretório de arquivos de teste com um arquivo qlpack.yml que defina:
name: <name-of-test-pack>
version: 0.0.0
dependencies:
<codeql-libraries-and-queries-to-test>: "*"
extractor: <language-of-code-to-test>
O dependencies valor especifica os CodeQL pacotes que contêm consultas a serem testadas.
Normalmente, esses pacotes serão resolvidos na origem e, portanto, não é necessário especificar uma versão fixa do pacote. Define extractor qual idioma a CLI usará para criar bancos de dados de teste a partir dos arquivos de código armazenados neste CodeQL pacote. Para obter mais informações, consulte Como personalizar a análise com pacotes CodeQL.
Você pode achar útil examinar a forma como os testes de consulta são organizados no CodeQL repositório. Cada linguagem tem um diretório src, o ql/<language>/ql/src, que contém bibliotecas e consultas para analisar bases de código. Junto com o diretório src, há um diretório test com testes para essas bibliotecas e consultas.
Cada test diretório é configurado como um pacote de teste CodeQL com dois subdiretórios:
-
`query-tests` uma série de subdiretórios com testes para consultas armazenadas no diretório `src`. Cada subdiretório contém código de teste e um arquivo de referência QL que especifica a consulta a ser testada. -
`library-tests` uma série de subdiretórios com testes para arquivos da biblioteca QL. Cada subdiretório contém códigos de teste e consultas que foram gravadas como testes de unidade para uma biblioteca.
Depois de criar o arquivo qlpack.yml, é necessário baixar todas as dependências e disponibilizá-las para a CLI. Faça isso executando o seguinte comando no mesmo diretório do arquivo qlpack.yml:
codeql pack install
Isso gera um arquivo codeql-pack.lock.yml que especifica todas as dependências transitivas necessárias para executar consultas neste pacote. É preciso fazer check-in desse arquivo no controle do código-fonte.
Como configura os arquivos de teste para uma consulta
Para cada consulta que você deseja testar, você deve criar um subdiretório no pacote de teste CodeQL . Depois, adicione os seguintes arquivos ao subdiretório antes de executar o comando de teste:
-
Um arquivo de referência de consulta (
.qlrefarquivo) que define o local da consulta a ser testada. O local é definido em relação à raiz do CodeQL pacote que contém a consulta. Normalmente, esse é um CodeQL pacote especificado nodependenciesbloco do pacote de teste. Para obter mais informações, consulte Arquivos de referência de consulta.Você não precisará adicionar um arquivo de referência de consulta se a consulta que deseja testar estiver armazenada no diretório de teste, mas uma boa prática é armazenar as consultas separadamente dos testes. A única exceção são os testes de unidade para bibliotecas QL, que costumam ser armazenados em pacotes de teste, separados das consultas que geram alertas ou caminhos.
-
O código de exemplo no qual você deseja executar a consulta. Isso deve consistir em um ou mais arquivos contendo exemplos de código que a consulta foi projetada para identificar.
Você também pode definir os resultados esperados ao executar a consulta no código de exemplo, criando um arquivo com a extensão .expected. Como alternativa, você pode deixar o comando de teste para criar o arquivo .expected.
Para obter um exemplo mostrando como criar e testar uma consulta, veja o exemplo abaixo.
Observação
Os seus arquivos .ql, .qlref, e .expected devem ter nomes consistentes:
- Se você quiser especificar diretamente o próprio arquivo
.qlno comando de teste, ele precisará ter o mesmo nome base que o arquivo correspondente.expected. Por exemplo, se a consulta forMyJavaQuery.ql, o arquivo de resultados esperado precisará serMyJavaQuery.expected. - Se você quiser especificar um arquivo
.qlrefno comando, ele deverá ter o mesmo nome base que o arquivo correspondente.expected, mas a consulta em si poderá ter um nome diferente. - Os nomes dos arquivos de código de exemplo não precisam ser consistentes com os outros arquivos de teste. Todos os arquivos de código de exemplo encontrados ao lado do arquivo
.qlref(ou.ql) e nos subdiretórios serão usados para criar um banco de dados de teste. Portanto, para simplificar, recomendamos que você não salve os arquivos de teste em diretórios que sejam ancestrais uns dos outros.
Em execução codeql test run
CodeQL Os testes de consulta são executados executando o seguinte comando:
codeql test run <test|dir>
O argumento <test|dir> pode ser um ou mais destes:
- Caminho para um arquivo
.ql. - Caminho para um arquivo
.qlrefque faz referência a um arquivo.ql. - Caminho para um diretório que será pesquisado recursivamente para arquivos
.qle.qlref.
Você também pode especificar:
-
`--threads:` opcionalmente, o número de threads a serem usadas na execução de consultas. A opção padrão é `1`. Você pode especificar mais threads para acelerar a execução da consulta. A especificação `0` corresponde o número de threads ao número de processadores lógicos.
Para obter detalhes completos sobre todas as opções que você pode usar ao testar consultas, consulte execução de teste.
Exemplo
O exemplo a seguir mostra como configurar um teste para uma consulta que pesquisa código Java em busca de instruções if que tenham blocos vazios then. O procedimento inclui etapas para adicionar a consulta personalizada e os arquivos de teste correspondentes a pacotes separados fora do checkout do repositório CodeQL. Isso garante que, ao atualizar as CodeQL bibliotecas ou fazer check-out de um branch diferente, você não substituirá suas consultas e testes personalizados.
Preparar uma consulta e arquivos de teste
-
Desenvolva a consulta. Por exemplo, a consulta simples a seguir localiza blocos vazios
thenno código Java:import java from IfStmt ifstmt where ifstmt.getThen() instanceof EmptyStmt select ifstmt, "This if statement has an empty then." -
Salve a consulta em um arquivo chamado
EmptyThen.qlem um diretório com outras consultas personalizadas. Por exemplo,custom-queries/java/queries/EmptyThen.ql. -
Se você ainda não adicionou suas consultas personalizadas a um CodeQL pacote, crie um CodeQL pacote agora. Por exemplo, se as consultas Java personalizadas forem armazenadas no
custom-queries/java/queries, adicione um arquivoqlpack.ymlcom o seguinte conteúdo acustom-queries/java/queries:name: my-custom-queries dependencies: codeql/java-queries: "*"Para obter mais informações sobre CodeQL pacotes, consulte Como personalizar a análise com pacotes CodeQL.
-
Crie um CodeQL pacote para seus testes Java adicionando um arquivo
qlpack.ymlcom o seguinte conteúdo emcustom-queries/java/tests, atualizando odependenciespara corresponder ao nome do seu CodeQL pacote de consultas personalizadas:O arquivo
qlpack.ymla seguir informa quemy-github-user/my-query-testsdepende demy-github-user/my-custom-queriesem uma versão igual ou superior a 1.2.3 e inferior a 2.0.0. Ele também declara que a CLI deve usar o Javaextractorao criar bancos de dados de teste. A linhatests: .declara que todos os arquivos.qlno pacote devem ser executados como testes quandocodeql test runé executado com a opção--strict-test-discovery. Normalmente, os pacotes de teste não contêm uma propriedadeversion. Isso impede que você os publique acidentalmente.name: my-github-user/my-query-tests dependencies: my-github-user/my-custom-queries: ^1.2.3 extractor: java-kotlin tests: . -
Execute
codeql pack installna raiz do diretório de teste. Isso gera um arquivocodeql-pack.lock.ymlque especifica todas as dependências transitivas necessárias para executar consultas neste pacote. -
No pacote de teste Java, crie um diretório para conter os arquivos de teste associados a
EmptyThen.ql. Por exemplo,custom-queries/java/tests/EmptyThen. -
No novo diretório, crie
EmptyThen.qlrefpara definir o local deEmptyThen.ql. O caminho para a consulta deve ser especificado em relação à raiz do CodeQL pacote que contém a consulta. Nesse caso, a consulta está no diretório de nível superior do CodeQL pacote nomeadomy-custom-queries, que é declarado como uma dependência paramy-query-tests. Portanto,EmptyThen.qlrefdeve simplesmente conterEmptyThen.ql. -
Crie um snippet de código para ser testado. O código Java a seguir contém uma instrução vazia
ifna terceira linha. Salve-o emcustom-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"); } } }
Executar o teste
Para executar o teste, acesse o diretório custom-queries e execute codeql test run java/tests/EmptyThen.
Ao ser executado, o teste:
-
Localizará um teste no diretório
EmptyThen. -
Extrai o CodeQL banco de dados dos
.javaarquivos armazenados noEmptyThendiretório. -
Compilará a consulta referenciada pelo arquivo
EmptyThen.qlref.Se essa etapa falhar, é porque a CLI não consegue localizar seu pacote personalizado CodeQL . Execute novamente o comando e especifique o local do pacote personalizado CodeQL , por exemplo:
codeql test run --search-path=java java/tests/EmptyThenPara obter informações sobre como salvar o caminho de pesquisa como parte da sua configuração, consulte Como especificar opções de comando em um arquivo de configuração do CodeQL.
-
Executará o teste executando a consulta e gerando um arquivo de resultados
EmptyThen.actual. -
Verificará se há um arquivo
EmptyThen.expecteda ser comparado com o arquivo de resultados.actual. -
Relatará os resultados do teste. Neste caso, uma falha:
0 tests passed; 1 tests failed:. O teste falhou porque ainda não adicionamos um arquivo com os resultados esperados da consulta.
Exibir a saída do teste de consulta
CodeQL gera os seguintes arquivos no `EmptyThen` diretório:
*
EmptyThen.actual, um arquivo que contém os resultados reais gerados pela consulta.
*
EmptyThen.testproj, um banco de dados de teste no VS Code qual você pode carregar e usar para depurar testes com falha. Quando os testes são concluídos com êxito, esse banco de dados é excluído em uma etapa de manutenção. Você pode substituir essa etapa executando test run com a opção --keep-databases.
Nesse caso, a falha era esperada e fácil de ser corrigida. Se você abrir o arquivo EmptyThen.actual, verá os resultados do teste:
| Test.java:3:5:3:22 | stmt | This if statement has an empty then. |
Esse arquivo contém uma tabela, com uma coluna de local do resultado, juntamente com colunas separadas para cada parte da cláusula select que a consulta gera.
Como os resultados são o esperado, podemos atualizar a extensão de arquivo para definir isso como o resultado esperado desse teste (EmptyThen.expected).
Se você executar novamente o teste agora, a saída será semelhante, mas será concluída relatando: All 1 tests passed..
Se os resultados da consulta forem alterados, por exemplo, se você revisar a instrução select da consulta, o teste falhará. Para resultados com falha, a saída da CLI inclui uma comparação unificada dos arquivos EmptyThen.expected e EmptyThen.actual.
Essas informações podem ser suficientes para depurar falhas de teste triviais.
Para falhas mais difíceis de depurar, você pode importar EmptyThen.testproj para CodeQL no VS Code, executar EmptyThen.ql e exibir os resultados no código de exemplo Test.java. Para obter mais informações, consulte Como gerenciar bancos de dados do CodeQL.
Leitura adicional
-
[ CodeQL consultas](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).