IoT onde você não esperou (parte 3). Construindo um modelo de simulação

Como eu já disse na última parte , ao desenvolver um projeto de IoT, os protocolos para interagir com dispositivos são bastante instáveis ​​e as chances de perder contato com dispositivos de teste após a atualização do firmware eram bastante grandes. Várias equipes estavam envolvidas no desenvolvimento, e havia um requisito estrito - não perder a capacidade de testar a camada de negócios do aplicativo, mesmo que o piscar dos dispositivos interrompa todo o fluxo de trabalho com sensores.

imagem

Para que os analistas de negócios testem suas hipóteses em dados mais ou menos semelhantes à realidade, construímos um modelo de simulação do dispositivo. Assim, se o dispositivo quebrasse devido a um novo firmware e os dados precisassem ser recebidos com urgência, lançamos um modelo de simulação em vez de um dispositivo real na rede, que perseguia os dados no formato antigo e produzia o resultado.

Além disso, a vantagem do modelo era que a empresa nunca compraria um grande lote de dispositivos apenas para testar uma hipótese. Por exemplo, a equipe de análise de negócios decidiu que a previsão do tempo de preenchimento do contêiner deveria funcionar de maneira diferente. E para testar sua hipótese, ninguém vai correr para comprar 10.000 sensores.

Desenvolvimento de um modelo de simulação


O modelo de simulação em si era o seguinte: O

imagem

estado e o comportamento da lata de lixo são descritos por uma máquina de estado regular. Primeiro, inicializamos a máquina de estado com o estado `VAZIO (nível = 0)` e podemos executar algumas ações nela, ou seja, jogar lixo no contêiner. Agora você precisa decidir se o contêiner permanece vazio `(nível? MAX_LEVEL)` ou está cheio` (nível> = MAX_LEVEL) `. Se o segundo, o estado muda para `COMPLETO '.

Alguém pode descarregar o lixo de um contêiner cheio ou o zelador chegou para limpar sua bagunça, e precisamos decidir em que estado mudar. O estado `CHOICE` é responsável por escolher uma ação - na terminologia de uma máquina de estado, algo semelhante a um bloco if.

Outro recipiente pode queimar e o estado da máquina de estado muda para `FIRE`. Além disso, o contêiner pode cair e sua condição se torna `FALL '(no relatório, falei sobre os motivos inesperados que a queda do contêiner pode causar). Mas há outro estado `LOST ', válido a partir de qualquer outro estado - ele é definido quando a conexão é perdida.

Uma máquina desse tipo descreve quase todo o comportamento do contêiner e o sensor nele. Mas isso não é suficiente para fazer um modelo de simulação, porque sabemos sobre os possíveis estados e transições a partir deles, mas não sabemos qual é a probabilidade desses eventos e quando eles ocorrerão.

De fato, verificou-se que a probabilidade de eventos dependia da hora do dia, porque:

  • transportadoras não trabalham à noite;
  • as pessoas jogam mais lixo em determinadas horas (de manhã antes do trabalho e à noite).

Portanto, possibilitamos à equipe de análise de negócios personalizar o comportamento da simulação. Foi possível definir a probabilidade de um evento em uma determinada hora do dia.

Teste de estresse simples e intuitivo


A imitação em si tem muitas vantagens, e uma delas é o teste de carga barato. É barato porque a imitação é, de fato, um encadeamento separado que inicia a máquina de estados, aplica eventos a ela e os próprios eventos são enviados ao servidor real.

Portanto, a simulação para o back-end não é diferente do sensor real. E se precisarmos executar 1000 sensores, execute 1000 threads e trabalhe. Além disso, a simulação é dimensionada perfeitamente.

imagem

Por um lado, é bastante rude testar a carga, mas, por outro lado, a simulação tornou possível conduzir muitos dados próximos da realidade para todo o projeto. E não se esqueça dos desenvolvedores chineses talentosos que ignoraram protocolos padrão como o MQTT e cortaram o protocolo em cima dos soquetes. Portanto, tivemos que fazer nossa própria implementação de um servidor que aceite dados nos soquetes sob esse protocolo proprietário.

Esse servidor precisava ser multiencadeado, pois existem muitos sensores de entrada. e essa parte também precisa ser testada separadamente, usando testes de desempenho. Você pode usar o JMeter (escreva um script de teste típico), o JMH / JCStress (teste de peças isoladas e faça uma referência mais fina) ou qualquer outra coisa sua. Quando você toma uma decisão em uma situação semelhante, aconselho a ouvir profissionais, por exemplo, Alexei Shipilev. No JPoint 2017, ele falou muito friamente sobre como fazer benchmarks de coisas diferentes e o que você precisa pensar ao fazer testes de desempenho.


Escolhemos a opção de fazer algo nosso, já que o projeto tinha uma abordagem atípica ao controle de qualidade - não temos uma equipe de testadores separada e a própria equipe de back-end testou a funcionalidade. Ou seja, a pessoa que escreveu o servidor de soquete teve que cobrir o código com unidades comuns, testes de integração e desempenho.

Tivemos uma pequena ferramenta que nos permitiu descrever rapidamente o cenário de carregamento e executá-lo na quantidade certa de encadeamentos paralelos:

StressTestRunner.test()
                .mode(ExecutionMode.EXECUTOR_MODE)
                .threads(THREADS_COUNT)
                .iterations(MESSAGES_COUNT)
                .timeout(5, TimeUnit.SECONDS)
                .run(() -> sensor.send(MESSAGE));

Awaitility.await()
          .atMost(5, TimeUnit.SECONDS)
          .untilAsserted(() ->
            verifyReceived(MESSAGES_COUNT)
          );

Dizemos quantos threads você precisa executar, quantas mensagens enviar, quanto tempo deve levar e enviamos dados para o soquete em cada thread. Resta apenas esperar que nosso servidor processe corretamente todos esses dados. Apenas algumas linhas de código foram liberadas que podem ser gravadas por qualquer desenvolvedor de back-end.

Emulação de problemas de rede


Com a ajuda da imitação, conseguimos simular trabalhos de baixa qualidade e específicos com soquetes. Os cartões SIM GSM nos sensores não têm endereços IP “brancos” e podemos receber dados de diferentes IPs 50 vezes por dia. E muitas vezes acontecia que a conexão foi aberta, começamos a transferir dados, o endereço IP muda e o servidor abre uma nova conexão sem fechar a antiga. Se não levarmos isso em consideração, em alguns dias ficaremos sem portas livres no servidor.

imagem

Houve também um problema com diferentes sensores de velocidade. Um dispositivo lento pode abrir uma conexão e congelar por um tempo, enquanto um dispositivo rápido envia algo. E tudo isso precisa ser processado corretamente. Na imitação, simular uma situação semelhante é fácil usando pausas.

imagem

Isso é apenas parte dos cenários que podem ser incorporados ao modelo.

achados


Parece-me que é precisamente a possibilidade de simulação que distingue fortemente a IoT de outros projetos. Simular o comportamento do dispositivo é mais fácil que o comportamento humano. Na entrada, obtemos valores determinísticos que se correlacionam bem com nosso modelo, e não ações humanas aleatórias. Como o comportamento dos dispositivos é logicamente mais fácil de descrever do que o comportamento das pessoas, o teste do sistema se torna mais fácil.

Vimos alguns aspectos diferentes do desenvolvimento na IoT.

imagem

Se você pulou as duas partes anteriores deste artigo, pode encontrá-las aqui:

IoT onde você não esperou (Parte 1) - A área de assunto e problemas da
IoT onde você não esperou (Parte 2) - Arquitetura de aplicativos e testes de IoT de coisas específicas

Github com as ferramentas de teste em questão.

. , Heisenbug , IoT. , ! JPoint, . Heisenbug JPoint 6 . !

All Articles