Testes de integração em projetos OSS - como lidar com terceiros com autenticação?

10

Um dos meus projetos de hobby (de código aberto) é uma ferramenta de backup que faz backups offline de repositórios do GitHub, Bitbucket etc.
Chama a API dos hosters para obter uma lista de repositórios e, em seguida, usa Git / Mercurial / o que clonar / puxe os repositórios para o computador local.

Então, eu tenho testes de integração onde estou chamando a API do GitHub, com autenticação.
(e quando o recurso de clonagem / extração for concluído, provavelmente haverá testes que clonam os repositórios do GitHub e também precisam ser autenticados)

Criei um usuário e uma organização especialmente para serem usados ​​nesses testes de integração.

Problema: não posso simplesmente codificar as senhas em algum lugar do código-fonte, porque é de código aberto e o código é público no GitHub.


O que estou fazendo agora

Nos testes, estou obtendo todos os nomes de usuário, senhas e nomes de repositório de variáveis ​​de ambiente.
Aqui está um exemplo :

config.Name = TestHelper.EnvVar("GithubApiTests_Name");
config.Password = TestHelper.EnvVar("GithubApiTests_PW");

( TestHelper.EnvVaré um método auxiliar que obtém o valor de uma variável de ambiente e gera uma exceção quando ela não existe)

Então, eu tenho um arquivo em lotes que define essas variáveis ​​de ambiente.
O real ( environment-variables.bat) é chamado no meu script de construção e antes de executar os testes, mas ignorado no controle de origem, portanto, não está realmente no meu repositório.

O que está no controle de origem é environment-variables.bat.sampleque define as mesmas variáveis ​​de ambiente, mas com senhas falsas:

rem copy/rename this file to environment-variables.bat

echo Setting environment variables for integration tests...

set GithubApiTests_Name=scm-backup-testuser
set GithubApiTests_OrgName=scm-backup-testorg
set GithubApiTests_PW=not-the-real-password
set GithubApiTests_Repo=scm-backup

Para que eu possa clonar o repositório na minha máquina, renomear esse arquivo environment-variables.bat, substituir a senha falsa pela real e todos os testes de integração funcionarão.

Isso funciona com a integração contínua também - estou usando o AppVeyor, e lá posso definir essas variáveis ​​de ambiente na interface da web .


O que eu não gosto nisso

Eu acho que não é uma boa solução para um projeto OSS, e especialmente não para este projeto:

Em teoria, um colaborador do meu projeto seria capaz de executar os testes de integração agora mesmo:

  • criando seu próprio usuário e organização de teste no GitHub
  • criando alguns repositórios de teste
  • criando sua própria versão environment-variables.batcom valores diferentes

O problema é que meu aplicativo poderá fazer backup de vários hosts de código-fonte.
No momento, ele suporta apenas o GitHub, mas será fácil adicionar suporte para mais hosts, adicionando algumas classes que implementam as interfaces corretas.

Portanto, quando eu implementar o suporte para mais hosters posteriormente, o número de variáveis ​​de ambiente aumentará.
Para poder executar todos os testes de integração, um colaborador em potencial criaria seus próprios usuários, organizações e repositórios de testes no GitHub, Bitbucket, GitLab, .... e quem sabe quantos mais e adicionar todos eles à sua environment-variables.batversão.

Existe uma solução melhor como fazer isso em um projeto em que o código é público?

Sei que outros projetos fazem algo semelhante ao que estou fazendo atualmente.
O Octokit.net , por exemplo, possui um script para configurar variáveis ​​de ambiente para testes de integração que estão chamando a API do GitHub.
Mas eles precisam apenas de um usuário e uma organização, e eu precisarei de muito mais.

Talvez eu não precise de uma solução que permita que um colaborador execute todos os testes de integração.
Por exemplo, se alguém quiser contribuir com o suporte ao GitHub do meu projeto, ele só precisará executar os testes de integração do GitHub.
Então, talvez eu só precise de uma maneira sensata de poder dividir meus testes de integração em um número infinito de "grupos" (?) E dizer "e agora executar todos os testes que pertencem ao grupo 'Github'".

Christian Specht
fonte

Respostas:

2

Acho que sua configuração atual está correta, mas faria alguns ajustes.

Para poder executar todos os testes de integração, um colaborador em potencial criaria seus próprios usuários, organizações e repositórios de testes no GitHub, Bitbucket, GitLab, .... e quem sabe quanto mais, e adicionaria todos eles às variáveis ​​de ambiente versão .bat.

Sim, isso é verdade, mas os colaboradores não precisam necessariamente executar todos os testes de integração antes de criar um PR no seu projeto. Depois que um PR é criado, o IC executa o conjunto completo de testes.

É comum ter um conjunto de testes que, de alguma forma, não é possível executar facilmente. Para muitas organizações, eles mantêm conjuntos de testes que levam dias para serem executados - portanto, os desenvolvedores devem executar seletivamente testes fáceis de executar e levar o código adiante para testes mais rigorosos. Estou sugerindo a mesma abordagem.

Para colaboradores regulares / confiáveis, você pode torná-los colaboradores reais em seu projeto, o que deve permitir que eles executem o IC em suas filiais antes de fazer um PR.

Dito isto, você não está impedindo que os colaboradores executem o conjunto completo de testes. Eles podem fornecer suas próprias credenciais do GitHub ou criar suas próprias contas de teste, e contribuidores regulares provavelmente farão isso.

Os ajustes que sugiro são:

Primeiro, faça a maioria dos seus testes de unidade de cobertura de teste. Estes devem cobrir todos os ramos da sua base de código.

Segundo, escreva testes de integração nos quais o ponto final é ridicularizado. Você pode até simular a camada de transporte dessa API e simular fluxos de solicitação / resposta HTTP iniciando um serviço falso do GitHub Rest. Por exemplo (no pseudo código):

// Test failed authentication to GitHub
val server = new WebServer("localhost", 9453, { request =>
    return Response(401, "unauthenticated")
})
server.start()
val backupService = new GitHubBackupService("http://localhost:9453")
backupService.backup must throw UnauthenticatedException()
server.stop()

Esses testes serão mais complexos, mas permitirão que você

  1. Teste sem criar contas e repositórios falsos
  2. Teste as condições de falha que seriam difíceis de simular com o GitHub real. Por exemplo, 502 respostas, tempos limite de conexão, corpos de resposta incomuns / incomparáveis.

Terceiro, desative todos os testes que precisam de conhecimentos especiais para executar em uma compilação normal. Na maioria das ferramentas de gerenciamento de compilação, há uma maneira de separar testes de integração ou marcar testes e executá-los seletivamente. Os colaboradores devem poder criar e testar o software sem nenhuma configuração anterior. O conjunto de testes completo deve ser executado após cada compilação no IC.

Por fim, documente os testes e como executá-los na documentação de teste para que os colaboradores possam optar por executá-los.

Samuel
fonte