
⏰ 🔥 Um proxy TCP para simular condições de rede e sistema para testes de caos e resiliência
Toxiproxy é um framework para simular condições de rede. Ele foi feito especificamente para funcionar em ambientes de teste, CI e desenvolvimento, com suporte a adulteração determinística de conexões, mas também com suporte a caos aleatório e customização. Toxiproxy é a ferramenta que você precisa para provar com testes que sua aplicação não tem pontos únicos de falha. Nós o usamos com sucesso em todos os ambientes de desenvolvimento e teste na Shopify desde outubro de 2014. Veja nosso [post no blog][blog] sobre resiliência para mais informações.
O uso do Toxiproxy consiste em duas partes. Um proxy TCP escrito em Go (o que este repositório contém) e um cliente que se comunica com o proxy via HTTP. Você configura sua aplicação para que todas as conexões de teste passem pelo Toxiproxy e então pode manipular a saúde delas via HTTP. Veja Uso abaixo sobre como configurar seu projeto.
Por exemplo, para adicionar 1000ms de latência à resposta do MySQL a partir do cliente Ruby:```ruby Toxiproxy[:mysql_master].downstream(:latency, latency: 1000).apply do Shop.first # this takes at least 1s end
Para derrubar todas as instâncias Redis:```ruby
Toxiproxy[/redis/].down do
Shop.first # this will throw an exception
end
While the examples in this README are currently in Ruby, there's nothing stopping you from creating a client in any other language (see Clientes).
As soluções existentes que encontramos não forneciam o tipo de API dinâmica de que precisávamos para
testes de integração e unitários. Ferramentas Linux como nc e outras não são
multiplataforma e exigem root, o que as torna problemáticas em ambientes de teste,
desenvolvimento e CI.
Vamos percorrer um exemplo com um aplicativo Rails. Observe que o Toxiproxy não está de forma alguma amarrado ao Ruby, ele foi apenas nosso primeiro caso de uso. Você pode ver o exemplo completo em sirupsen/toxiproxy-rails-example. Para começar imediatamente, pule para Uso.
Para nosso blog popular, por algum motivo estamos armazenando as tags das nossas postagens no
Redis e as próprias postagens no MySQL. Podemos ter uma classe Post que
inclui alguns métodos para manipular tags em um Redis set:```ruby
class Post < ActiveRecord::Base
def tags TagRedis.smembers(tag_key) end
def add_tag(tag) TagRedis.sadd(tag_key, tag) end
def remove_tag(tag) TagRedis.srem(tag_key, tag) end
def tag_key "post:tags:#{self.id}" end end
Decidimos que gerar erro ao escrever no armazenamento de tags
(adicionar/remover) é aceitável. No entanto, se o armazenamento de tags estiver indisponível, devemos ser
capazes de ver o post sem tags. Poderíamos simplesmente capturar o
`Redis::CannotConnectError` em torno da chamada Redis `SMEMBERS` no método `tags`
method. Vamos usar o Toxiproxy para testar isso.
Como já instalamos o Toxiproxy e ele está rodando em nossa máquina, podemos
pular para o passo 2. É aqui que precisamos garantir que o Toxiproxy tenha um mapeamento para
as tags do Redis. Em `config/boot.rb` (antes que qualquer conexão seja feita), adicionamos:```ruby
require 'toxiproxy'
Toxiproxy.populate([
{
name: "toxiproxy_test_redis_tags",
listen: "127.0.0.1:22222",
upstream: "127.0.0.1:6379"
}
])
Então, em config/environments/test.rb, definimos o TagRedis como um cliente Redis que se conecta ao Redis por meio do Toxiproxy adicionando esta linha:```ruby
TagRedis = Redis.new(port: 22222)
Todas as chamadas no ambiente de teste agora passam pelo Toxiproxy. Isso significa que podemos
adicionar um teste de unidade onde simulamos uma falha:```ruby
test "should return empty array when tag redis is down when listing tags" do
@post.add_tag "mammals"
# Take down all Redises in Toxiproxy
Toxiproxy[/redis/].down do
assert_equal [], @post.tags
end
end
O teste falha com Redis::CannotConnectError. Perfeito! O Toxiproxy derrubou
o Redis com sucesso durante a duração do closure. Vamos corrigir o método tags
para que ele seja resiliente:```ruby
def tags
TagRedis.smembers(tag_key)
rescue Redis::CannotConnectError
[]
end
Os testes passam! Agora temos um teste unitário que prova que buscar as tags quando o Redis
está fora do ar retorna um array vazio, em vez de lançar uma exceção. Para uma cobertura
completa, você também deve escrever um teste de integração que envolva a busca da
página inteira do post do blog quando o Redis está fora do ar.
O aplicativo de exemplo completo está em
[sirupsen/toxiproxy-rails-example](https://github.com/sirupsen/toxiproxy-rails-example).
## Uso
Configurar um projeto para usar o Toxiproxy consiste em três etapas:
1. Instalando o Toxiproxy
2. Populando o Toxiproxy
3. Usando o Toxiproxy
### 1. Instalando o Toxiproxy
**Linux**
Consulte [`Releases`](https://github.com/Shopify/toxiproxy/releases) para os binários e pacotes de sistema mais recentes para sua arquitetura.
**Ubuntu**```bash
$ wget -O toxiproxy-2.1.4.deb https://github.com/Shopify/toxiproxy/releases/download/v2.1.4/toxiproxy_2.1.4_amd64.deb
$ sudo dpkg -i toxiproxy-2.1.4.deb
$ sudo service toxiproxy start
OS X
Com Homebrew:```bash $ brew tap shopify/shopify $ brew install toxiproxy
Ou com [MacPorts](https://www.macports.org/):```bash
$ port install toxiproxy
Windows