Estou criando um serviço sobre o armazenamento de dados do Google App Engine, que é um armazenamento de dados eventualmente consistente. Para minha aplicação, isso está bem.
No entanto, estou desenvolvendo testes que fazem coisas como o objeto PUT e, em seguida, o objeto GET e a verificação de propriedades no objeto retornado. Infelizmente, como o armazenamento de dados é eventualmente consistente, esses testes simples não são reproduzíveis.
Como você testa um serviço eventualmente consistente?
google-app-engine
eventual-consistency
google-cloud-datastore
Doug Richardson
fonte
fonte
How can I reproducibly test an eventually consistent service?
Você não pode. Você precisa remover a palavra "reproduzível" ou a palavra "eventualmente"; você não pode ter os dois.Respostas:
Considere os requisitos não funcionais ao projetar seus testes funcionais - se o seu serviço tiver um requisito não funcional de "Consistente dentro de x (segundos / minutos / etc)", basta executar as solicitações PUT, aguarde x e, em seguida, as solicitações GET.
Nesse ponto, se os dados ainda não 'chegaram', você pode considerar que a solicitação PUT não é compatível com seus requisitos.
fonte
Você realmente deseja que seus testes sejam rápidos e consistentes. Se você começar a criar testes que ocasionalmente falhem devido a uma consistência eventual, ignorará o teste quando ele falhar e, de que serve?
Crie um serviço falso que lide com as solicitações PUT e GET, mas tenha uma operação adicional para torná-lo consistente. Seu teste é então:
Isso permite que você teste o comportamento do seu software quando o GET recupera com êxito o objeto PUT. Também permite testar o comportamento do seu software quando o GET não encontra o objeto (ou o objeto correto) devido ao serviço ainda não ser consistente. Apenas deixe de fora a ligação para
make_consistent()
.Ainda vale a pena ter testes que interagem com o serviço real, mas eles devem ser executados fora do fluxo de trabalho de desenvolvimento normal, pois nunca serão 100% confiáveis (por exemplo, se o serviço estiver inoperante). Esses testes devem ser usados para:
fonte
OK então. "O que você está testando" é a questão principal.
Nesse caso, você deve zombar dos serviços do Google e sempre retornar uma resposta.
Nesse caso, você deve zombar dos serviços do Google e sempre retornar o erro transitório antes da resposta correta
Você deve injetar os serviços reais do Google e executar o teste. Mas! O código que você está testando deve ter a manipulação (nova tentativa) de Erro Transitório incorporada. Portanto, você deve obter uma resposta consistente. (a menos que o Google seja muito mal comportado)
fonte
Use um dos seguintes:
Infelizmente, você precisa escolher valores mágicos (N ou duração do sono) para ambas as técnicas.
fonte
Pelo que entendi, o armazenamento de dados do Google Cloud permite consultas fortemente consistentes e eventualmente consistentes .
O problema é que as consultas fortemente consistentes são bastante limitadas à taxa (algo com o qual você pode conviver durante o teste).
Uma possibilidade pode ser colocar suas consultas no armazenamento de dados em um wrapper que permita uma consistência forte para fins de teste.
Por exemplo, você poderia ter métodos chamados
start_debug_strong_consistency()
eend_debug_strong_consistency()
.O método start criaria uma chave que pode ser usada como chave ancestral para todas as consultas subseqüentes, e o método final excluiria a chave.
A única alteração nas consultas reais que você está testando seria chamar
setAncestor(your_debug_key)
se essa chave existir.fonte
Uma abordagem, que é legal em teoria, mas pode nem sempre ser prática, é tornar todas as operações de gravação no sistema em teste idempotentes . Isso significa que, supondo que seu código de teste teste as coisas em uma ordem seqüencial fixa, você pode tentar novamente todas as leituras e gravações individualmente até obter o resultado esperado, tentando novamente até que o tempo limite definido no código de teste seja excedido. Ou seja, faça a ação A1, tentando novamente se necessário até que o resultado seja B1, faça a ação A2, tentando novamente se necessário até que o resultado seja B2 e assim por diante.
Então você não precisa se preocupar em verificar as condições prévias das operações de gravação, porque as operações de gravação já as estão verificando e você apenas as tenta novamente até que sejam bem-sucedidas!
Use os mesmos tempos limite "padrão", tanto quanto possível, que podem ser aumentados se todo o sistema ficar mais lento e substituir os padrões individualmente ao tentar novamente operações particularmente lentas.
fonte
Um serviço como o Google App Engine Datastore é baseado na replicação de dados em vários pontos de presença espalhados globalmente (POP). Qualquer teste de integração para um serviço eventualmente consistente é realmente um teste da taxa de replicação desse serviço em seu conjunto de POPs. A taxa na qual o conteúdo é espalhado para cada POP em um determinado serviço não será a mesma para todos os POP dentro do serviço, dependendo de vários fatores, como o método de replicação e vários problemas de transporte da Internet - estes são dois exemplos que representam a maioria dos relatórios em qualquer serviço de armazenamento de dados eventualmente consistente (pelo menos essa foi a minha experiência enquanto eu trabalhava para uma CDN importante).
Para testar efetivamente a replicação de um objeto em uma determinada plataforma, você precisa definir o teste para solicitar o mesmo objeto recentemente colocado de cada um dos POPs do serviço. Estou sugerindo testar a lista de POPs uma a cinco vezes ou até que todos os POPs na sua lista de POPs relatem o objeto. Aqui está um conjunto de intervalos nos quais você pode ajustar o teste que você pode ajustar: 1, 5, 60 minutos, 12 horas, 25 horas depois de colocá-lo no armazenamento de dados. A chave é registrar os resultados em cada intervalo para posterior análise e análise, a fim de ter uma idéia da capacidade de um determinado serviço de replicar objetos globalmente. Frequentemente, os serviços de armazenamento de dados apenas puxam uma cópia local para um POP depois que ela é solicitada localmente [o roteamento é feito via protocolo BGP e é por isso que seu teste precisa solicitar o objeto de cada POP específico para que seja globalmente válido para uma determinada plataforma] . No caso do armazenamento de dados do Google, você deve configurar o teste para consultar um determinado objeto em "mais de 70 pontos de presença em 33 países"; você provavelmente precisará obter a lista de URLs de endereços específicos de POP no Suporte do Google [ref:https://cloud.google.com/about/locations/ ] ou se o Google estiver usando o Fastly para replicação, suporte rapidamente [ https://www.fastly.com/resources ].
Algumas vantagens deste método: 1) Você terá uma ideia da plataforma de replicação de um determinado serviço, conhecerá seus pontos fortes e fracos como um todo em uma escala global [como foi durante o teste de integração]. 2) Para qualquer objeto que você testar, você terá uma ferramenta disponível para aquecer o conteúdo [faça a primeira solicitação que cria a cópia em um determinado POP local] - fornecendo assim uma maneira de garantir que o conteúdo seja espalhado globalmente antes que seus clientes o solicitem. em qualquer lugar da terra.
fonte
Tenho experiência com o armazenamento de dados do Google App Engine. Rodando localmente, surpreendentemente, geralmente é mais "eventualmente" do que "consistente". O exemplo mais simples: crie uma nova entidade e, em seguida, recupere-a. Muitas vezes, nos últimos 5 anos, vi o SDK em execução local não encontrar a nova entidade imediatamente, mas depois de meio segundo.
No entanto, rodando contra os servidores reais do Google, eu não vi esse comportamento. Eles tentam fazer com que seu cliente do Datastore sempre seja executado no mesmo servidor do lado deles, portanto, geralmente quaisquer alterações são refletidas imediatamente nas consultas.
Meu conselho para os testes de integração é executá-los nos servidores reais e, provavelmente, você não precisará colocar nenhuma pesquisa ou atraso falso para obter seus resultados.
fonte