É uma especificação completa do ambiente de execução de testes.
Contexto
A linguagem Bazel BUILD inclui regras que podem ser usadas para definir testar programas em várias linguagens.
Os testes são executados usando bazel test
.
Os usuários também podem executar binários de teste diretamente. Isso é permitido, mas não aprovado, portanto, tal invocação não aderirá às autorizações descritas abaixo.
Os testes precisam ser herméticos, ou seja, precisam acessar apenas esses recursos. em que eles têm uma dependência declarada. Se os testes não forem devidamente herméticos elas não fornecerão resultados historicamente reproduzíveis. Pode ser um problema significativo para a descoberta do culpado (determinar qual mudança quebrou um teste), auditoria da engenharia de versão e isolamento de recursos de testes (automáticos estruturas de teste não devem usar DDoS em um servidor porque alguns testes acabam se comunicando ).
Objetivo
O objetivo desta página é estabelecer formalmente o ambiente de execução para e comportamento esperado dos testes do Bazel. Ela também impõe requisitos aos usuários no executor e no sistema de build.
A especificação do ambiente de teste ajuda os autores de testes a evitar confiar em comportamento não especificado e, assim, dá à infraestrutura de teste mais liberdade para fazer alterações na implementação. A especificação aperta alguns buracos que permitem que muitos testes sejam aprovados, apesar de não serem adequadamente herméticos, determinista e reentrante.
O objetivo desta página é ser regulatório e autoritativo. Se esse a especificação e o comportamento implementado do executor de testes discordam, especificação tem precedência.
Especificação proposta
As palavras-chave "PRECISA", "NÃO PODE", "OBRIGATÓRIO", "DEVERÁ", "NÃO DEVE", "DEVERIA", "NÃO DEVE", "RECOMENDADO", "PODE" e "OPCIONAL" sejam interpretadas como descritos no IETF RFC 2119.
Finalidade dos testes
A finalidade dos testes do Bazel é confirmar propriedades dos arquivos de origem. fez check-in no repositório. Nesta página, "arquivos de origem" inclui dados de teste, saídas ouro e qualquer outra coisa mantida sob controle de versão). Um usuário escreve um para declarar uma invariante que espera ser mantida. Outros usuários execute o teste mais tarde para verificar se a invariante foi corrompida. Se o teste depende de alguma variável além dos arquivos de origem (não herméticas), o valor é reduzido, porque os usuários posteriores não podem ter certeza de que as alterações são responsáveis. quando o teste para de ser aprovado.
Portanto, o resultado de um teste depende apenas de:
- arquivos de origem em que o teste tem uma dependência declarada
- produtos do sistema de build em que o teste tem uma dependência declarada.
- recursos com comportamento garantido pelo executor de testes que permaneçam constantes.
Atualmente, esse comportamento não é aplicado. No entanto, os executores de testes reservam o direito de incluir essa restrição no futuro.
Papel do sistema de build
As regras de teste são análogas às regras binárias, pois cada uma delas precisa gerar um executável neste programa. Para algumas linguagens, esse é um programa stub que combina uma arcabouço de linguagem específica com o código de teste. As regras de teste precisam produzir outras e saída de dados. Além do executável de teste principal, o executor de testes precisará de um manifesto do runfiles, que são arquivos de entrada que devem ser disponibilizados ao teste em tempo de execução e pode precisar de informações sobre tipo, tamanho e e as tags de um teste.
O sistema de build pode usar os arquivos de execução para entregar código e dados. (Este pode ser usada como uma otimização para diminuir cada binário de teste, compartilhando arquivos em testes, por exemplo, com o uso de links dinâmicos. O sistema de build precisa garantir que o executável gerado carregue esses arquivos pelos arquivos de execução. imagem fornecida pelo executor de testes, em vez de referências fixadas no código a valores absolutos os locais na árvore de origem ou de saída.
Papel do executor de testes
Do ponto de vista do executor, cada teste é um programa que pode ser
invocada com execve()
. Pode haver outras maneiras de executar testes. por exemplo,
um IDE pode permitir a execução de testes Java em andamento. No entanto, o resultado
de executar o teste como um processo autônomo precisa ser considerado autoritativo. Se
um processo de teste é executado até a conclusão e termina normalmente com um código de saída de
zero, o teste foi aprovado. Qualquer outro resultado é considerado uma falha no teste. Em
específico, gravar as strings PASS
ou FAIL
em stdout não tem
significância para o executor de testes.
Se um teste demorar muito para ser executado, exceder algum limite de recursos ou runner de outra forma detectar um comportamento proibido, ele poderá encerrar o teste e a execução como uma falha. O executor não pode informar que o teste foi aprovado após enviar um sinal para o processo de teste ou para qualquer filho dele.
Todo o destino do teste (não métodos ou testes individuais) recebe uma quantidade limitada
tempo necessário até a conclusão. O limite de tempo de um teste é baseado no
timeout
de acordo
à seguinte tabela:
timeout | Limite de tempo (s) |
---|---|
short | 60 |
moderada | 300 |
long | 900 |
eterno | 3600 |
Os testes que não especificam um tempo limite explicitamente têm um implícito com base no
size
do teste da seguinte forma:
tamanho | Rótulo de tempo limite implícito |
---|---|
pequeno | short |
médio | moderada |
grande | long |
enorme | eterno |
Uma "grande" teste sem configuração de tempo limite explícito vai receber a atribuição 900 segundos para executar. Uma "média" teste com um tempo limite de "curto" será alocado 60 segundos.
Ao contrário de timeout
, size
também determina o pico de uso presumido de
outros recursos (como RAM) ao executar o teste localmente, conforme descrito em
Definições comuns.
Todas as combinações de rótulos size
e timeout
são legais, então um "enorme" testar
pode ser declarado com um tempo limite "curto". Provavelmente, isso ajudaria
coisas horríveis muito rapidamente.
Os testes podem retornar arbitrariamente rápido, independentemente do tempo limite. O teste não é penalizado por um tempo limite muito generoso, embora um aviso possa ser emitido: você deve Em geral, defina o tempo limite o máximo possível, sem inconsistência.
O tempo limite do teste pode ser substituído pela flag --test_timeout
do Bazel quando
manualmente em condições conhecidas por serem lentas. O
Os valores de --test_timeout
estão em segundos. Por exemplo, --test_timeout=120
.
define o tempo limite do teste como dois minutos.
Há também um limite inferior recomendado para tempos limite de teste, como segue:
timeout | Tempo mínimo (s) |
---|---|
short | 0 |
moderada | 30 |
long | 300 |
eterno | 900 |
Por exemplo, se um modelo seja concluído em 5,5 segundos, defina timeout =
"short"
ou size = "small"
. Como usar o Bazel --test_verbose_timeout_warnings
a opção de linha de comando mostrará os testes cujo tamanho especificado é muito grande.
Tamanhos e tempos limite de teste são especificados no arquivo BUILD de acordo com especificação aqui. Se não especificado, o tamanho padrão do teste será "médio".
Se o processo principal de um teste sai, mas alguns dos filhos ainda estão em execução, o executor de testes deve considerar a execução concluída e contá-la como um sucesso ou com base no código de saída observado do processo principal. O executor de testes pode acabar com processos inapropriados. Os testes não podem vazar processos dessa maneira.
Fragmentação de testes
Os testes podem ser carregados em paralelo com a fragmentação de testes. Consulte
--test_sharding_strategy
e shard_count
para
ativar a fragmentação de testes. Quando a fragmentação está ativada, o executor de testes é iniciado uma vez
por fragmento. A variável de ambiente TEST_TOTAL_SHARDS
é o número de fragmentos, e TEST_SHARD_INDEX
é o
índice de fragmento, começando em 0. Os corredores usam essas informações para selecionar quais testes
executar, por exemplo, com uma estratégia round-robin. Nem todos os executores de testes são compatíveis
fragmentação. Se um executor oferecer suporte à fragmentação, precisará criar ou atualizar a última
data de modificação do arquivo especificado por
TEST_SHARD_STATUS_FILE
Caso contrário, se
--incompatible_check_sharding_support
estiver ativado, o Bazel vai falhar no teste se for fragmentado.
Condições iniciais
Ao executar um teste, o executor de testes precisa estabelecer determinados valores pelas condições
O executor de testes precisa invocar cada teste com o caminho para o executável do teste em
argv[0]
: Esse caminho precisa ser relativo e estar abaixo do diretório atual do teste
(que está na árvore de arquivos de execução, conforme abaixo). O executor de testes não deve passar
outros argumentos a um teste, a menos que o usuário o solicite explicitamente.
O bloco de ambiente inicial será composto da seguinte maneira:
Variável | Valor | Status |
---|---|---|
HOME |
valor de $TEST_TMPDIR |
recomendado |
LANG |
unset | obrigatório |
LANGUAGE |
unset | obrigatório |
LC_ALL |
unset | obrigatório |
LC_COLLATE |
unset | obrigatório |
LC_CTYPE |
unset | obrigatório |
LC_MESSAGES |
unset | obrigatório |
LC_MONETARY |
unset | obrigatório |
LC_NUMERIC |
unset | obrigatório |
LC_TIME |
unset | obrigatório |
LD_LIBRARY_PATH |
lista de diretórios separada por dois-pontos contendo bibliotecas compartilhadas | opcional |
JAVA_RUNFILES |
valor de $TEST_SRCDIR |
descontinuado |
LOGNAME |
valor de $USER |
obrigatório |
PATH |
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:. |
Recomendado |
PWD |
$TEST_SRCDIR/workspace-name |
Recomendado |
SHLVL |
2 |
recomendado |
TEST_INFRASTRUCTURE_FAILURE_FILE |
caminho absoluto para um arquivo privado em um diretório gravável (este arquivo só devem ser usadas para informar falhas originadas do processo infraestrutura, não como um mecanismo geral para relatar falhas instáveis de testes. Nesse contexto, a infraestrutura de teste é definida como ou bibliotecas que não são específicas para testes, mas que podem causar falhas no teste defeituosos. A primeira linha é o nome da infraestrutura de teste que causou a falha. O segundo foi um componente e a descrição da falha. As linhas adicionais serão ignoradas. | opcional |
TEST_LOGSPLITTER_OUTPUT_FILE |
caminho absoluto para um arquivo privado em um diretório gravável (usado para gravar registro do protobuffer do logsplitter). | opcional |
TEST_PREMATURE_EXIT_FILE |
caminho absoluto para um arquivo privado em um diretório gravável (usado para
capturando chamadas para exit() ) |
opcional |
TEST_RANDOM_SEED |
Se a opção --runs_per_test for usada,
TEST_RANDOM_SEED está definido como run number.
(começando com 1) para cada execução de teste individual. |
opcional |
TEST_RUN_NUMBER |
Se a opção --runs_per_test for usada,
TEST_RUN_NUMBER está definido como run number.
(começando com 1) para cada execução de teste individual. |
opcional |
TEST_TARGET |
O nome do alvo que está sendo testado. | opcional |
TEST_SIZE |
O size de teste |
opcional |
TEST_TIMEOUT |
O teste timeout em segundos |
opcional |
TEST_SHARD_INDEX |
índice de fragmento, se sharding for usado |
opcional |
TEST_SHARD_STATUS_FILE |
caminho do arquivo a ser tocado para indicar suporte a sharding |
opcional |
TEST_SRCDIR |
caminho absoluto para a base da árvore de arquivos de execução | obrigatório |
TEST_TOTAL_SHARDS |
total
shard count ,
se sharding for usado |
opcional |
TEST_TMPDIR |
caminho absoluto para um diretório gravável particular | obrigatório |
TEST_WORKSPACE |
o nome do espaço de trabalho do repositório local | opcional |
TEST_UNDECLARED_OUTPUTS_DIR |
caminho absoluto para um diretório gravável particular, usado para gravar dados
resultados de teste). Todos os arquivos gravados no
O diretório TEST_UNDECLARED_OUTPUTS_DIR será compactado, e
adicionado a um arquivo outputs.zip em
bazel-testlogs |
opcional |
TEST_UNDECLARED_OUTPUTS_ANNOTATIONS_DIR |
caminho absoluto para um diretório gravável particular, usado para gravar dados
teste os arquivos .part e .pb da anotação de saída). |
opcional |
TEST_WARNINGS_OUTPUT_FILE |
caminho absoluto para um arquivo privado em um diretório gravável (usado para gravar testar avisos de destino) | opcional |
TESTBRIDGE_TEST_ONLY |
de
--test_filter ,
se especificado |
opcional |
TZ |
UTC |
obrigatório |
USER |
valor de getpwuid(getuid())->pw_name |
obrigatório |
XML_OUTPUT_FILE |
Local em que as ações de teste precisam gravar um arquivo de saída XML do resultado do teste. Caso contrário, o Bazel gera um arquivo de saída XML padrão que encapsula o registro de teste. como parte da ação de teste. O esquema XML é baseado Esquema de resultados de teste JUnit | opcional |
BAZEL_TEST |
Indica que o executável de teste está sendo acionado por bazel test . |
obrigatório |
O ambiente pode conter entradas adicionais. Os testes não podem depender presença, ausência ou valor de qualquer variável de ambiente não listada acima.
O diretório de trabalho inicial será $TEST_SRCDIR/$TEST_WORKSPACE
.
Os IDs do processo atual, do grupo de processos, da sessão e do processo pai são não especificado. O processo pode ou não ser um líder do grupo de processos ou uma sessão líder. O processo pode ou não ter um terminal de controle. O processo pode ter zero ou mais processos filhos em execução ou não coletados. O processo não deve ter várias linhas de execução quando o código de teste ganhar o controle.
O descritor do arquivo 0 (stdin
) estará aberto para leitura, mas o que estiver anexado a
não foi especificado. Os testes não podem ler esses dados. Descritores de arquivo 1 (stdout
) e 2
(stderr
) devem estar abertas para escrita, mas estão anexadas a
não especificado. Pode ser um terminal, um pipe, um arquivo normal ou qualquer outra coisa para
quais caracteres podem ser escritos. Eles podem compartilhar uma entrada na tabela de arquivos abertos
ou seja, não podem buscar independentemente. Os testes não podem herdar
outros descritores de arquivos abertos.
O umask inicial precisa ser 022
ou 027
.
Nenhum alarme ou timer de intervalo deve estar pendente.
A máscara inicial dos sinais bloqueados precisa estar vazia. Todos os sinais devem ser definidos como a ação padrão.
Os limites de recursos iniciais, flexíveis e rígidos, precisam ser definidos da seguinte maneira:
Recurso | Limite |
---|---|
RLIMIT_AS |
ilimitado |
RLIMIT_CORE |
não especificado |
RLIMIT_CPU |
ilimitado |
RLIMIT_DATA |
ilimitado |
RLIMIT_FSIZE |
ilimitado |
RLIMIT_LOCKS |
ilimitado |
RLIMIT_MEMLOCK |
ilimitado |
RLIMIT_MSGQUEUE |
não especificado |
RLIMIT_NICE |
não especificado |
RLIMIT_NOFILE |
No mínimo 1024 |
RLIMIT_NPROC |
não especificado |
RLIMIT_RSS |
ilimitado |
RLIMIT_RTPRIO |
não especificado |
RLIMIT_SIGPENDING |
não especificado |
RLIMIT_STACK |
ilimitado ou 2.044 KB <= rlim <= 8.192 KB |
Os tempos de processo iniciais (como retornados por times()
) e a utilização de recursos
(conforme retornado por getrusage()
) não são especificados.
A prioridade e a política de programação inicial não foram especificadas.
Papel do sistema host
Além dos aspectos do contexto do usuário sob controle direto do teste runner, o sistema operacional em que os testes são executados precisa atender a certos propriedades para que uma execução de teste seja válida.
Sistema de arquivos
O diretório raiz observado por um teste pode ou não ser o diretório raiz real.
/proc
será montado.
Todas as ferramentas de build estão presentes nos caminhos absolutos em /usr
usados por um
instalação local.
Os caminhos que começam com /home
podem não estar disponíveis. Os testes não devem acessar nenhuma
desses caminhos.
/tmp
precisa ser gravável, mas os testes precisam evitar o uso desses caminhos.
Os testes não podem presumir que há um caminho constante disponível para os respectivos usar.
Os testes não podem assumir que os horários estão ativados para qualquer sistema de arquivos montado.
Usuários e grupos
A raiz de usuários, ninguém e unittest precisam existir. Os grupos raiz, ninguém e eng deve existir.
Os testes precisam ser executados como um usuário não raiz. Os IDs de usuário reais e eficazes devem ser igual; da mesma forma para IDs de grupo. Além disso, os IDs de usuário, de grupo, nome de usuário e nome do grupo não foram especificados. O conjunto de IDs de grupos suplementares é não especificado.
Os IDs de usuário e de grupo atuais devem ter nomes correspondentes que podem ser
recuperado com getpwuid()
e getgrgid()
. O mesmo pode não ser verdadeiro para
IDs de grupos complementares.
O usuário atual precisa ter um diretório principal. Pode não ser gravável. Os testes precisam e não tentar gravar nele.
Rede
O nome do host não foi especificado. Ele pode ou não conter um ponto. Resolver a nome do host deve fornecer um endereço IP do host atual. Como resolver o corte do nome do host após o primeiro ponto também deve funcionar. O localhost precisa ser resolvido pelo nome do host.
Outros recursos
Os testes recebem pelo menos um núcleo da CPU. Outros podem estar disponíveis, mas isto não está garantida. Outros aspectos de desempenho desse núcleo não foram especificados. Você pode aumente a reserva para um número maior de núcleos de CPU adicionando a tag "cpu:n" (em que n é um número positivo) a uma regra de teste. Se uma máquina tiver menos total de núcleos de CPU do que o solicitado, o Bazel ainda vai executar o teste. Se um teste usa fragmentação, cada fragmento reserva uma quantidade de núcleos especificados aqui.
Os testes podem criar subprocessos, mas não processar grupos ou sessões.
Há um limite no número de arquivos de entrada que um teste pode consumir. Esse limite é sujeito a mudanças, mas atualmente está na faixa de dezenas de milhares de entradas.
Hora e data
A hora e a data atuais não foram especificadas. O fuso horário do sistema não foi especificado.
O X Windows pode ou não estar disponível. Os testes que precisam de um servidor X serão iniciados Xvfb.
Testar a interação com o sistema de arquivos
Todos os caminhos de arquivo especificados nas variáveis de ambiente de teste apontam para algum lugar da sistema de arquivos local, salvo especificação em contrário.
Os testes devem criar arquivos apenas nos diretórios especificados por
$TEST_TMPDIR
e $TEST_UNDECLARED_OUTPUTS_DIR
(se definidos).
Esses diretórios estarão vazios inicialmente.
Os testes não podem tentar remover, usar "chmod" ou alterar esses diretórios.
Esses diretórios podem ser links simbólicos.
O tipo de sistema de arquivos de $TEST_TMPDIR/.
permanece não especificado.
Os testes também podem gravar arquivos .part no
$TEST_UNDECLARED_OUTPUTS_ANNOTATIONS_DIR
para anotar arquivos de saída não declarados.
Em casos raros, um teste pode ser forçado a criar arquivos em /tmp
. Por exemplo:
limites de tamanho de caminho para soquetes de domínio Unix
normalmente exigem a criação do soquete em /tmp
. O Bazel não vai conseguir
rastrear esses arquivos; o teste em si deve ser hermético, para usar
caminhos para evitar colisão com outros, executando testes e não relacionados ao mesmo tempo
processos e limpar os arquivos criados no /tmp
.
Alguns frameworks de teste conhecidos, como
JUnit4 TemporaryFolder
ou Use o TempDir
, tenha
suas próprias maneiras de criar um diretório temporário em /tmp
. Esses testes
incluem uma funcionalidade que limpa arquivos em /tmp
. Portanto, você pode usar
eles, mesmo que criem arquivos fora de TEST_TMPDIR
.
Os testes precisam acessar entradas pelo mecanismo runfiles ou outras partes do o ambiente de execução que se destina especificamente a criar arquivos de entrada disponíveis.
Os testes não podem acessar outras saídas do sistema de build em caminhos inferidos de o local do próprio executável.
Não é especificado se a árvore dos arquivos de execução contém arquivos regulares, simbólicos
links ou uma mistura. A árvore de arquivos de execução pode conter links simbólicos para diretórios.
Os testes precisam evitar o uso de caminhos que contenham componentes ..
nos arquivos de execução.
árvore.
Nenhum diretório, arquivo ou link simbólico na árvore de arquivos de execução (incluindo caminhos que
links simbólicos transversais) deve ser gravável. (Segue que o trabalho inicial
não pode ser gravável.) Os testes não podem presumir que qualquer parte do
Os arquivos runfiles são graváveis ou pertencem ao usuário atual. Por exemplo, chmod
e chgrp
podem
falhar).
A árvore dos arquivos de execução (incluindo caminhos que atravessam links simbólicos) não pode mudar durante a execução do teste. Os diretórios pais e as montagens do sistema de arquivos não podem mudar de qualquer forma que afete o resultado da resolução de um caminho nos arquivos de execução árvore.
Para capturar a saída antecipada, um teste pode criar um arquivo no caminho especificado pelo
TEST_PREMATURE_EXIT_FILE
na inicialização e remova-a ao sair. Se o Bazel perceber o
quando o teste for concluído, ele assumirá que o teste foi encerrado prematuramente e
marcá-lo como falhado.
Convenções de tag
Algumas tags nas regras de teste têm um significado especial. Consulte também
Bazel Build Encyclopedia no atributo tags
(link em inglês).
Tag | Significado |
---|---|
exclusive |
executar nenhum outro teste ao mesmo tempo |
external |
O teste tem uma dependência externa. desativar o armazenamento em cache de teste |
large |
Convenção test_suite ; conjunto de testes grandes |
manual * |
não inclua destino de teste em padrões de destino curinga, como
:... , :* ou :all |
medium |
Convenção test_suite ; pacote de testes médios |
small |
Convenção test_suite ; um conjunto de testes pequenos |
smoke |
Convenção test_suite ; ou seja, ele deve ser executado antes
confirmar alterações de código no sistema de controle de versões |
Arquivos de execução
A seguir, suponha que há uma regra *_binary() rotulada
//foo/bar:unittest
, com uma dependência de ambiente de execução na regra rotulada
//deps/server:server
.
Local
O diretório runfiles de um //foo/bar:unittest
de destino é o diretório
$(WORKSPACE)/$(BINDIR)/foo/bar/unittest.runfiles
. Esse caminho é conhecido como
o runfiles_dir
.
Dependências
O diretório runfiles é declarado como uma dependência em tempo de compilação do
*_binary()
. O próprio diretório de arquivos de execução depende do conjunto de
arquivos que afetam a regra *_binary()
ou qualquer um dos ambientes de compilação ou execução dela
dependências. A modificação de arquivos de origem não afeta a estrutura do
runfiles e, portanto, não aciona a recriação.
Índice
O diretório runfiles contém o seguinte:
- Links simbólicos para dependências de tempo de execução: cada OutputFile e CommandRule que
é uma dependência do ambiente de execução da regra
*_binary()
é representada por um no diretório runfiles. O nome do link simbólico é$(WORKSPACE)/package_name/rule_name
: Por exemplo, o link simbólico para o servidor se chamaria$(WORKSPACE)/deps/server/server
, e o caminho completo seria$(WORKSPACE)/foo/bar/unittest.runfiles/$(WORKSPACE)/deps/server/server
. O destino do link simbólico é o OutputFileName() do OutputFile ou CommandRule, expresso como um caminho absoluto. Assim, o destino o link simbólico pode ser$(WORKSPACE)/linux-dbg/deps/server/42/server
. - Links simbólicos para subarquivos de execução: para cada
*_binary()
Z em um ambiente de execução. de*_binary()
C, há um segundo link nos arquivos de execução de C para os arquivos de execução de Z. O nome do link simbólico é$(WORKSPACE)/package_name/rule_name.runfiles
: O destino do link simbólico é diretório runfiles. Por exemplo, todos os subprogramas compartilham um arquivo de execução diretório.