Capítulo 40 — Laboratório de verificação II
Mapa da aula
Aula 40 publicada. Mapa, exemplo, EX079.
flowchart TD
N0["40.1 Injeção de falhas"]
N1["40.2 Oráculos e classificação"]
N2["40.3 Sementes, taxas e cobertura"]
N3["40.5 Atividade prática: Laboratório 15"]
N4["Síntese do capítulo"]
N0 --> N1 --> N2 --> N3 --> N4
N4 --> EX["Exemplo resolvido"]
EX --> Q["Exercício EX079"]
Desenho lógico
flowchart LR
N0["40.1 Injeção de falhas"]
N1["40.2 Oráculos e classificação"]
N2["40.3 Sementes, taxas e cobertura"]
N3["40.5 Atividade prática: Laboratório 15"]
N4["Síntese do capítulo"]
N0 --> N1 --> N2 --> N3 --> N4 --> Q["EX079"]
[40.1 Injeção de falhas]
|
v
[40.2 Oráculos e classificação]
|
v
[40.3 Sementes, taxas e cobertura]
|
v
[40.5 Atividade prática: Laboratório 15]
|
v
[Síntese do capítulo]
|
v
[Exemplo resolvido] --> [Exercício EX079]
Objetivos de aprendizagem e conexão
Ao fim deste capítulo você será capaz de (1) projetar e executar uma campanha de injeção de falhas com semente contra um controle de segurança; (2) classificar os resultados e calcular as taxas de detecção por classe de falha; (3) encontrar lacunas entre o que um controle detecta e o que um requisito exige; e (4) relatar uma campanha de forma reprodutível. Ele estende o Capítulo 30 às falhas ambientais e aos ataques e prepara o projeto final (capítulos 44 a 47).
40.1 Injeção de falhas
A injeção de falhas introduz deliberadamente falhas — mensagens corrompidas, descartadas, atrasadas, repetidas ou reordenadas; reinícios de processos; saltos de relógio; esgotamento de recursos — para observar como um sistema se comporta. Ela testa o tratamento de erros que os testes comuns raramente alcançam. Uma campanha especifica o modelo de falhas (quais falhas, a que taxas), o sistema sob teste, o oráculo (qual é o comportamento correto para cada falha) e as medições. Para o TMRP, a campanha do receptor neste capítulo injeta corrupção, repetição, atraso e descarte. Cada falha tem um oráculo. Os resultados são contados por classe.
40.2 Oráculos e classificação
Para cada falha injetada, defina o resultado esperado: corrompida → rejeitada como corrompida; repetida → rejeitada como repetição; atrasada além da janela de atualidade → rejeitada como inativa; descartada → detectada como lacuna (ou não, se o projeto não detecta lacunas). Classifique os resultados observados contra os esperados. Uma falha que produz "ok" quando deveria ter sido rejeitada é uma falha silenciosa — a classe mais importante a encontrar. Para o receptor do TMRP, a classe dos descartes é aquela em que o oráculo expôs uma lacuna: o projeto não tinha resultado esperado para uma mensagem perdida, porque ninguém tinha perguntado o que deveria acontecer.
40.3 Sementes, taxas e cobertura
Defina a semente do gerador de falhas, registre-a e relate as contagens por classe de falha. Escolha taxas que produzam eventos suficientes de cada classe para serem significativos; uma campanha de 500 mensagens com 5% por classe de falha dá cerca de 25 eventos de cada — o bastante para encontrar falhas sistemáticas, não o bastante para estimar com precisão as raras. Estenda a campanha para as classes que preocupam especialmente. A campanha do TMRP usa a semente quarenta, quinhentas mensagens e cinco por cento por classe de falha, de modo que cada classe produz eventos suficientes para mostrar o comportamento sistemático. O projeto final estende a campanha a dez mil mensagens em sete classes de falha, incluindo reinício e reordenação.
40.4 Exemplo resolvido: campanha do receptor de telemetria (sintético)
O Laboratório 15 envia 500 mensagens com a semente 40; cada uma tem 80% de chance de não ter falha e 5% de cada: corrupção, repetição de uma mensagem válida anterior, atraso de 120 s (janela de atualidade de 60 s) e descarte. Resultados: toda mensagem corrompida foi rejeitada como corrompida; toda repetição, como repetição; toda mensagem atrasada, como inativa; nenhuma falha produziu um "ok" silencioso. Mas os descartes são invisíveis para o receptor: 21 mensagens foram perdidas e o receptor não gerou nada. A verificação de contador do receptor rejeita contadores antigos, mas não alarma diante de lacunas. O requisito R7 (alarmes em até 60 s) implica que a perda dos dados de uma estação precisa, ela própria, ser visível. Mudança de projeto: alarmar quando nenhuma mensagem válida chegar de uma estação por 60 s, e registrar em log as lacunas de contador. A campanha é executada de novo depois da mudança, com a mesma semente.
40.5 Atividade prática: Laboratório 15
# Lab 15 - fault-injection campaign against the telemetry receiver (synthetic, seeded, offline)
import random, hmac, hashlib, struct
KEY = b"k" * 32
def seal(c, lvl, ts):
b = struct.pack(">QHI", c, lvl, ts); return b + hmac.new(KEY, b, hashlib.sha256).digest()[:16]
def receive(m, state, now, max_age=60):
b, tag = m[:14], m[14:]
if len(m) != 30 or not hmac.compare_digest(tag, hmac.new(KEY, b, hashlib.sha256).digest()[:16]): return "corrupt"
c, lvl, ts = struct.unpack(">QHI", b)
if c <= state["last"]: return "replay"
if now - ts > max_age: return "stale"
state["last"] = c; return "ok"
rng = random.Random(40); state = {"last": 0}; tally = {}; sent = []
for i in range(1, 501):
now = 10 * i; m = seal(i, 300, now); fault = rng.choices(["none", "corrupt", "replay", "delay", "drop"], [80, 5, 5, 5, 5])[0]
if fault == "corrupt": m = m[:5] + bytes([m[5] ^ 0x10]) + m[6:]
if fault == "replay" and sent: m = rng.choice(sent)
if fault == "drop": tally[("drop", "lost")] = tally.get(("drop", "lost"), 0) + 1; continue
arrive = now + (120 if fault == "delay" else 1)
out = receive(m, state, arrive)
tally[(fault, out)] = tally.get((fault, out), 0) + 1
if fault == "none": sent.append(m)
for k in sorted(tally): print(k, tally[k])
Saída esperada:
('corrupt', 'corrupt') 14
('delay', 'stale') 22
('drop', 'lost') 21
('none', 'ok') 419
('replay', 'replay') 24
Toda mensagem corrompida, repetida e atrasada terminou na classe que seu oráculo previa, e nenhuma falha produziu uma aceitação silenciosa. As mensagens descartadas são a constatação: vinte e uma se perderam e o receptor não gerou nada, porque as verificações de contador só rejeitam mensagens antigas. Esse resultado levou ao alarme de estação inativa, que dispara quando nenhuma mensagem válida chega de uma estação por sessenta segundos, e à constatação de revisão F2. A campanha é então executada de novo com a mesma semente para confirmar a mudança.
40.6 Erros comuns e limites
- Modelos de falhas limitados ao que o projetista esperava.
- Sem oráculo, de modo que os resultados não podem ser julgados.
- Campanhas sem semente.
- Tratar "nenhuma falha silenciosa observada" como prova.
- Não executar a campanha de novo depois das correções.
A primeira campanha do TMRP mostrou o primeiro erro: os descartes eram silenciosos porque os projetistas nunca listaram a perda de dados como uma falha que o receptor deveria perceber. Executar de novo depois de acrescentar o alarme de estação inativa é o modo como a correção é confirmada. Sua semente é registrada, de modo que a nova execução é comparável. A classe dos descartes agora é mantida em todas as execuções.
Exercícios — capítulo 40
EX079 — Detecção de lacunas. Objetivo: fechar a lacuna dos descartes. Entradas: Laboratório 15. Passos: acrescente a detecção de lacunas (um salto de contador maior que 1 registra gap) e execute de novo com a mesma semente; relate quantos eventos de lacuna são registrados e por que o número pode diferir do número de descartes. Evidência esperada: código e saída. Rubrica: 3 = implementado corretamente; explica que descartes consecutivos produzem um único evento de lacuna e que repetições e mensagens rejeitadas também afetam a continuidade do contador; 2 = implementado, sem explicação; 1 = não executado; 0 = nada.
EX080 — Estenda o modelo de falhas. Objetivo: acrescentar falhas. Entradas: Laboratório 15. Passos: acrescente duas classes de falha — reordenação (trocar duas mensagens consecutivas) e reinício do receptor (zerar state) —, defina os oráculos, execute e relate as falhas silenciosas. Evidência esperada: código, oráculos e resultados. Rubrica: 3 = a reordenação faz a mensagem anterior ser rejeitada como repetição (aceitável ou não — argumentado), o reinício permite repetições (falha silenciosa), a menos que o estado seja persistido; 2 = uma classe; 1 = sem oráculo; 0 = nada.
Síntese do capítulo
A injeção de falhas exercita o tratamento de erros que os testes comuns deixam passar. Defina com antecedência o modelo de falhas e o oráculo, use sementes e conte, classifique os resultados e cace as falhas silenciosas. O Laboratório 15 mostra o resultado típico: o controle rejeita o que foi projetado para rejeitar e é cego para o que ninguém listou — aqui, a perda de dados.
Continue estudando — capítulo 40 de 50
← Capítulo 39 · Índice de capítulos do curso · Capítulo 41 →
Siga para a próxima lição escrita.