Banco de dados do painel VTS

Para oferecer suporte a um painel de integração contínua que seja escalável, de alto desempenho e flexível, o back-end do VTS Dashboard deve ser cuidadosamente projetado com um forte entendimento da funcionalidade do banco de dados. O Google Cloud Datastore é um banco de dados NoSQL que oferece garantias de ACID transacionais e consistência eventual, bem como consistência forte em grupos de entidades. No entanto, a estrutura é muito diferente dos bancos de dados SQL (e até mesmo do Cloud Bigtable); em vez de tabelas, linhas e células, existem tipos, entidades e propriedades.

As seções a seguir descrevem a estrutura de dados e os padrões de consulta para criar um back-end eficaz para o serviço da Web VTS Dashboard.

Entidades

As seguintes entidades armazenam resumos e recursos de execuções de teste VTS:

  • Entidade de Teste . Armazena metadados sobre execuções de teste de um teste específico. Sua chave é o nome do teste e suas propriedades incluem a contagem de falhas, contagem de aprovação e lista de quebras de casos de teste de quando os trabalhos de alerta o atualizam.
  • Entidade de execução de teste . Contém metadados de execuções de um teste específico. Ele deve armazenar os carimbos de data e hora de início e término do teste, o ID da compilação de teste, o número de casos de teste aprovados e reprovados, o tipo de execução (por exemplo, pré-envio, pós-envio ou local), uma lista de links de log, o host nome da máquina e contagens de resumo de cobertura.
  • Entidade de informações do dispositivo . Contém detalhes sobre os dispositivos usados ​​durante a execução de teste. Inclui o ID de compilação do dispositivo, nome do produto, destino de compilação, ramificação e informações de ABI. Isso é armazenado separadamente da entidade de execução de teste para dar suporte a execuções de teste de vários dispositivos de um modo um para muitos.
  • Entidade de execução do ponto de criação de perfil . Resume os dados coletados para um determinado ponto de criação de perfil em uma execução de teste. Ele descreve os rótulos de eixo, nome do ponto de criação de perfil, valores, tipo e modo de regressão dos dados de criação de perfil.
  • Entidade de Cobertura . Descreve os dados de cobertura reunidos para um arquivo. Ele contém as informações do projeto Git, o caminho do arquivo e a lista de contagens de cobertura por linha no arquivo de origem.
  • Entidade de Execução de Caso de Teste . Descreve o resultado de um caso de teste específico de uma execução de teste, incluindo o nome do caso de teste e seu resultado.
  • Entidade de Favoritos do Usuário . Cada assinatura de usuário pode ser representada em uma entidade contendo uma referência ao teste e o ID do usuário gerado a partir do serviço de usuário do App Engine. Isso permite uma consulta bidirecional eficiente (ou seja, para todos os usuários inscritos em um teste e para todos os testes favoritos de um usuário).

Agrupamento de entidades

Cada módulo de teste representa a raiz de um grupo de entidades. As entidades de execução de teste são filhas desse grupo e pais para entidades de dispositivo, entidades de ponto de criação de perfil e entidades de cobertura relevantes para o respectivo ancestral de teste e execução de teste.

Figura 1 . Ancestralidade da entidade de teste.

Ponto-chave: Ao projetar relacionamentos de ancestralidade, você deve equilibrar a necessidade de fornecer mecanismos de consulta eficazes e consistentes em relação às limitações impostas pelo banco de dados.

Benefícios

O requisito de consistência garante que as operações futuras não vejam os efeitos de uma transação até que ela seja confirmada e que as transações no passado sejam visíveis para as operações atuais. No Cloud Datastore, o agrupamento de entidades cria ilhas de forte consistência de leitura e gravação dentro do grupo, que neste caso são todas as execuções de teste e dados relacionados a um módulo de teste. Isso oferece os seguintes benefícios:

  • Leituras e atualizações para testar o estado do módulo por trabalhos de alerta podem ser tratadas como atômicas
  • Visão consistente garantida dos resultados do caso de teste nos módulos de teste
  • Consultas mais rápidas em árvores ancestrais

Limitações

A gravação em um grupo de entidades a uma taxa mais rápida que uma entidade por segundo não é recomendada, pois algumas gravações podem ser rejeitadas. Desde que os trabalhos de alerta e o upload não ocorram a uma taxa superior a uma gravação por segundo, a estrutura é sólida e garante uma consistência forte.

Em última análise, o limite de uma gravação por módulo de teste por segundo é razoável porque as execuções de teste geralmente levam pelo menos um minuto, incluindo a sobrecarga da estrutura VTS; a menos que um teste esteja sendo executado consistentemente simultaneamente em mais de 60 hosts diferentes, não pode haver um gargalo de gravação. Isso se torna ainda mais improvável, pois cada módulo faz parte de um plano de teste que geralmente leva mais de uma hora. Anomalias podem ser facilmente tratadas se os hosts executarem os testes ao mesmo tempo, causando rajadas curtas de gravações nos mesmos hosts (por exemplo, capturando erros de gravação e tentando novamente).

Considerações de dimensionamento

Uma execução de teste não precisa necessariamente ter o teste como seu pai (por exemplo, pode ter alguma outra chave e ter nome de teste, hora de início do teste como propriedades); no entanto, isso trocará uma consistência forte por consistência eventual. Por exemplo, o trabalho de alerta pode não ver um instantâneo mutuamente consistente das execuções de teste mais recentes em um módulo de teste, o que significa que o estado global pode não representar uma representação totalmente precisa da sequência de execuções de teste. Isso também pode afetar a exibição de execuções de teste em um único módulo de teste, que pode não ser necessariamente um instantâneo consistente da sequência de execução. Eventualmente, o instantâneo será consistente, mas não há garantias de que os dados mais recentes serão.

Casos de teste

Outro gargalo potencial são os grandes testes com muitos casos de teste. As duas restrições operacionais são a taxa de transferência máxima de gravação dentro de um grupo de entidades de uma por segundo, juntamente com um tamanho máximo de transação de 500 entidades.

Uma abordagem seria especificar um caso de teste que tenha uma execução de teste como ancestral (semelhante a como os dados de cobertura, dados de perfil e informações do dispositivo são armazenados):

Figura 2 . Casos de teste descendem de execuções de teste (NÃO RECOMENDADO).

Embora essa abordagem ofereça atomicidade e consistência, ela impõe fortes limitações aos testes: se uma transação estiver limitada a 500 entidades, um teste não poderá ter mais de 498 casos de teste (supondo que não haja cobertura ou dados de perfil). Se um teste exceder isso, uma única transação não poderá gravar todos os resultados do caso de teste de uma vez, e dividir os casos de teste em transações separadas poderá exceder a taxa de transferência máxima de gravação do grupo de entidades de uma iteração por segundo. Como esta solução não será bem dimensionada sem sacrificar o desempenho, ela não é recomendada.

No entanto, em vez de armazenar os resultados dos casos de teste como filhos da execução de teste, os casos de teste podem ser armazenados independentemente e suas chaves fornecidas para a execução de teste (uma execução de teste contém uma lista de identificadores para suas entidades de casos de teste):

Figura 3 . Casos de teste armazenados independentemente (RECOMENDADO).

À primeira vista, isso pode parecer quebrar a forte garantia de consistência. No entanto, se o cliente tiver uma entidade de execução de teste e uma lista de identificadores de caso de teste, ele não precisará construir uma consulta; em vez disso, ele pode obter diretamente os casos de teste por seus identificadores, o que sempre garante a consistência. Essa abordagem alivia muito a restrição no número de casos de teste que uma execução de teste pode ter enquanto ganha consistência forte sem ameaçar a escrita excessiva dentro de um grupo de entidades.

Padrões de acesso a dados

O VTS Dashboard usa os seguintes padrões de acesso a dados:

  • Favoritos do usuário . Pode ser consultado usando um filtro de igualdade nas entidades favoritas do usuário que têm o objeto Usuário do App Engine específico como uma propriedade.
  • Listagem de teste . Consulta simples de entidades de teste. Para reduzir a largura de banda para renderizar a página inicial, uma projeção pode ser usada nas contagens de aprovação e reprovação para omitir a lista potencialmente longa de IDs de casos de teste com falha e outros metadados usados ​​pelos trabalhos de alerta.
  • Testes executados . A consulta de entidades de execução de teste requer uma classificação na chave (timestamp) e possível filtragem nas propriedades de execução de teste, como ID de compilação, contagem de passagem etc. Ao realizar uma consulta ancestral com uma chave de entidade de teste, a leitura é fortemente consistente. Neste ponto, todos os resultados do caso de teste podem ser recuperados usando a lista de IDs armazenados em uma propriedade de execução de teste; isso também é garantido como um resultado fortemente consistente pela natureza das operações de obtenção do armazenamento de dados.
  • Dados de perfil e cobertura . A consulta de dados de perfil ou cobertura associados a um teste pode ser feita sem também recuperar outros dados de execução de teste (como outros dados de perfil/cobertura, dados de caso de teste etc.). Uma consulta de ancestral usando as chaves de entidade de teste e execução de teste recuperará todos os pontos de criação de perfil registrados durante a execução de teste; ao filtrar também o nome do ponto de criação de perfil ou o nome do arquivo, uma única entidade de criação de perfil ou de cobertura pode ser recuperada. Pela natureza das consultas de ancestrais, essa operação é fortemente consistente.

Para obter detalhes sobre a interface do usuário e capturas de tela desses padrões de dados em ação, consulte VTS Dashboard UI .