Blogue ·
Um agente real, um gateway de testes
Cinco rondas fecharam com a mesma reserva: não provado no fio. Fechá-la exigiu um agente real, uma palavra-passe plantada e duas medições que nada mediam.
Por Provibr
Cinco rondas seguidas fecharam o relatório com uma versão da mesma frase: a alteração de protocolo é aditiva, os testes unitários estão verdes, e nada disso foi exercitado contra um agente real. Adaptadores de monitorização, o envelope selado, as atualizações automáticas do agente, um passo de automação que espera por um comando. Os cinco estavam corretos tanto quanto se podia ver, e os cinco traziam uma reserva que a ronda seguinte herdava.
Essa reserva custa pouco a escrever e acumula-se. Cada ronda acrescenta uma, ninguém está errado, e ao fim de cinco resta uma pilha de comportamento que só existiu numa bancada de ensaio. Esta ronda serviu para retirar a pilha em vez de a aumentar: sem função nova, sem alteração de protocolo, sem publicação. Oitenta e duas medições contra um agente real.
A montagem, numa frase
Um binário de agente real, compilado para o mesmo destino que distribuímos, assinado com uma chave de desenvolvimento, a correr dentro de um contentor descartável numa máquina que não é o portátil de ninguém, a falar com um gateway de testes por um túnel inverso, com sete serviços descartáveis no laço local para medir e uma segunda cópia do mesmo binário inscrita como sonda alojada.
Tudo nessa frase carrega peso. O binário é o que distribuímos e não uma compilação de teste, porque as falhas interessantes moram na serialização e no TLS, não na lógica. O gateway é de propósito uma instância de desenvolvimento em portos diferentes, porque o de produção escuta nos óbvios, e um agente que batesse ao lado errado daria uma tarde muito má. Os serviços são contentores descartáveis do software real em versões reais e não imitações, porque todo o sentido do exercício é que as imitações são exatamente o que já tínhamos.
Os serviços de base de dados receberam uma palavra-passe canário, e essa escolha tornou possível a secção seguinte.
| Grupo | Medições | O que resolve |
|---|---|---|
| Adaptadores de monitorização | 44 | Seis protocolos de base de dados e de diretório, credenciais certas e erradas, e o estado de regra que daí resulta |
| Atualizações automáticas | 19 | Planear, aplicar, reiniciar e recusar uma compilação adulterada |
| Passo de automação | 11 | Um comando que termina dentro da espera e outro que não |
| Sonda alojada | 4 | O mesmo binário inscrito como sonda de plataforma em vez de agente de cliente |
| Fonte ausente | 4 | Um agente desligado produz um estado próprio, nunca uma avaria falsa |
Uma procura com um valor plantado
A afirmação que mais queríamos pôr à prova é uma negação: um segredo de monitorização viaja selado e nunca é escrito na linha do comando, no registo de eventos, no barramento de mensagens nem em qualquer dos dois registos de processo.
As negações são as afirmações que falham em silêncio. As palavras-passe não foram portanto cadeias aleatórias cuja ausência nada prova; foram valores plantados, escolhidos para que uma única ocorrência em qualquer sítio fosse inconfundível. Depois foram varridas sete camadas: as cargas de comando guardadas, a tabela de eventos, a configuração de verificação guardada, os resultados guardados, o barramento de mensagens em texto e na sua forma codificada, o registo do gateway e o do agente. Ao todo, cerca de meio milhão de caracteres de material.
Zero ocorrências, que é a resposta desejada e também a que dá uma procura avariada.
A mesma procura foi por isso lançada sobre um ficheiro que de certeza continha a palavra, e encontrou-a. Esse controlo positivo é a diferença entre «procurámos e não havia nada» e «não procurámos». Custa uma linha e é a linha mais valiosa do guião.
Outras duas exigências cobrem a mesma falha pelo outro lado: a execução tem de observar pelo menos uma dúzia de comandos de verificação reais e várias dezenas de mensagens do barramento antes de poder concluir seja o que for. Ambas estiveram a vermelho a certa altura da ronda, em passagens que de outro modo teriam anunciado uma varredura limpa sobre absolutamente nada. Uma varredura que não encontra infrações num conjunto vazio não é prova, e parece exatamente um êxito.
Duas maneiras de estar a verde sem medir
Ambas aconteceram nesta ronda, em guiões escritos por quem conhece este modo de falha e escreve sobre ele com regularidade.
A primeira: uma consulta selecionou uma coluna e o código leu depois outra propriedade nas linhas do resultado. Numa linguagem com tipos isso é um erro; aqui é undefined, para sempre, em silêncio, e qualquer comparação com esse valor falha de um modo que parece uma asserção que nunca dispara em vez de uma que é sempre verdadeira. A verificação anunciou êxito porque não tinha nada a comparar.
A segunda: um teste de pertença contra uma lista vazia. É uma afirmação sobre nada, satisfaz-se trivialmente, e é o estado final natural de qualquer guião cuja etapa anterior produziu zero linhas em silêncio. Ambas se cobrem por pouco: verificar a forma do que se obteve e verificar que o conjunto a examinar não está vazio.
Cinco nomes de coluna nesses guiões foram adivinhados em vez de consultados. Esses falharam com estrondo, que é a variante barata do mesmo erro, mas é o mesmo erro: um comando diz como se chama uma coluna, e a versão em que um palpite acaba numa lista que ninguém executa é a versão que sobrevive à revisão.
Um agente que recusa inscrever-se duas vezes
A meio dos testes de atualização o agente deixou de voltar. De fora parecia um ciclo de reinício, e a primeira hora foi para o caminho de atualização.
O agente fazia exatamente o que devia. A inscrição escreve um ficheiro de estado, e o guião de instalação gerado verifica esse ficheiro e recusa inscrever-se de novo se ele estiver presente. Reinscrever um anfitrião já inscrito substitui uma identidade, e fazê-lo por acidente é como uma máquina perde o certificado e o cofre num só passo. O nosso ciclo de supervisão, escrito para a ocasião, não tinha essa porta, e cada tentativa de reinício chocava com a recusa própria e correta do agente.
A lição não é sobre a porta. É sobre o facto de uma recusa correta e um defeito terem, de longe, a mesma forma, e de o que os separa ser ler o que a outra parte disse de facto em vez do que o sintoma sugeria.
Dos mesmos dias vieram mais três surpresas, as três decisões de desenho a encontrar a realidade:
As horas de atualização planeadas vivem numa grelha de cinco minutos, imposta por uma restrição de base de dados. «Daqui a um minuto», que é o que quer quem escreve um teste, não existe. O que torna isso praticável é uma janela de recuperação: uma hora falhada ainda é executada durante um quarto de hora depois. É também por isso que uma medição repetida dentro desse mesmo quarto de hora tem de escolher uma hora de grelha por usar, já que cada hora é reclamada de forma única por agente e uma segunda passagem sobre a mesma é recusada com razão.
Uma verificação TCP vem com TLS ligado. Apontada a um porto sem cifra, falha com um erro de TLS, o que está certo e se lê como uma verificação avariada até se olhar para o que é um valor por omissão.
E a linha de auditoria de um passo de automação cuja espera expirou congela no estado que o fluxo viu. O comando passou a tempo esgotado sessenta milissegundos depois e a linha continuou a dizer o que dizia. Isso não é um defeito da linha, é um defeito do comentário por cima, que prometia ler ali o desfecho final. Essa promessa foi retirada e respondida como deve ser noutro sítio.
Um aviso que agrupa e uma contagem que diz zero
O mais afiado dos achados pequenos. Depois de uma atualização bem sucedida a plataforma escreve um aviso. A medição contou os avisos criados desde o início da execução e obteve zero.
Os avisos agrupam. Uma segunda ocorrência do mesmo incrementa um contador na linha existente e deixa intacta a sua marca de criação, que é justamente o desejável num painel: «este agente caiu» com um número ao lado em vez de quarenta linhas. É também exatamente o que faz com que uma contagem sobre a marca de criação nada anuncie enquanto o aviso está ali à vista.
A medição estava errada, o produto estava certo, e a única razão por que se sabe em que sentido era é que alguém abriu o painel em vez de acreditar na consulta. Toda a agregação tem uma forma, e um teste que não a conhece põe à prova a sua própria suposição.
O que anotaríamos
- «Não provado no fio» é uma dívida, e acumula-se. Uma ronda consegue carregá-la. Cinco rondas são uma pilha de comportamento que nunca existiu fora da bancada.
- Provar uma negação com um valor plantado e um controlo positivo. Sem ele, zero ocorrências e uma procura avariada são indistinguíveis.
- Dar a cada varredura um chão. Verificar que a entrada não está vazia antes de concluir seja o que for sobre ela.
- Uma recusa correta parece um defeito de longe. Ler o que a outra parte disse antes de reescrever a nossa.
- Não adivinhar um nome de coluna, um valor por omissão nem uma grelha. Os três estão a um comando de distância, e o palpite que chega a uma lista é o que nunca dispara.
- Conhecer a forma do que se conta. As linhas agrupadas não trazem a marca de criação pela qual se filtra.
Para que fique claro: nesta ronda nada foi publicado. Nenhuma alteração de produto, nenhuma alteração de protocolo, nenhuma publicação do agente. O que saiu daqui é que cinco reservas desapareceram e um punhado de pequenos defeitos foram corrigidos, e a limpeza foi recontada em vez de suposta: sem linhas sobrantes, sem contentores sobrantes, sem ficheiros sobrantes.
Algumas coisas ficaram por provar. O caminho de injeção da automação foi exercitado pelo seu núcleo e não pelo painel, os adaptadores não correram a partir de uma sonda alojada, e continua a não haver medição contra um hipervisor real.
Do trabalho de plataforma na Provibr. Porque é que o segredo de monitorização é selado a cada tentativa está em um segredo que viaja uma só vez, e como uma atualização assinada do agente recusa uma compilação adulterada está em como uma atualização assinada do agente se recusa a si própria.