Testy integracji w projektach OSS - jak obsługiwać uwierzytelnianie stron trzecich?

10

Jednym z moich hobby (open source) jest narzędzie do tworzenia kopii zapasowych, które tworzy kopie zapasowe w trybie offline repozytoriów z GitHub, Bitbucket itp.
Wywołuje API hostów, aby uzyskać listę repozytoriów, a następnie używa Git / Mercurial / cokolwiek do klonowania / przeciągnij repozytoria na komputer lokalny.

Mam więc testy integracyjne, w których dzwonię do interfejsu GitHub API z uwierzytelnianiem.
(a kiedy funkcja klonowania / ściągania zostanie zakończona, prawdopodobnie będą testy, które klonują repozytoria z GitHub i również muszą zostać uwierzytelnione)

Stworzyłem użytkownika i organizację specjalnie do użytku w tych testach integracyjnych.

Problem: Nie mogę po prostu zakodować hasła gdzieś w kodzie źródłowym, ponieważ jest to oprogramowanie typu open source, a kod jest publiczny w GitHub.


Co ja teraz robię

W testach uzyskuję wszystkie nazwy użytkowników, hasła i nazwy repozytoriów ze zmiennych środowiskowych.
Oto przykład :

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

( TestHelper.EnvVarjest metodą pomocniczą, która pobiera wartość zmiennej środowiskowej i zgłasza wyjątek, gdy ona nie istnieje)

Następnie mam plik wsadowy, który ustawia te zmienne środowiskowe.
Prawdziwy one ( environment-variables.bat) jest wywoływany w moim skrypcie kompilacji i przed wykonaniem testów, ale jest ignorowany w kontroli źródła, więc tak naprawdę nie ma go w moim repozytorium.

Co jest w to kontrola źródłowego environment-variables.bat.sample, który ustanawia te same zmienne środowiskowe, ale z fałszywymi hasłami:

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

Mogę więc sklonować repozytorium na moim komputerze, zmienić nazwę tego pliku na environment-variables.bat, zastąpić fałszywe hasło prawdziwym, a wszystkie testy integracji będą działać.

Działa to również z Continuous Integration - używam AppVeyor i tam mogę ustawić te zmienne środowiskowe w interfejsie internetowym .


Co mi się w tym nie podoba

Myślę, że nie jest to dobre rozwiązanie dla projektu OSS, a szczególnie nie dla tego projektu:

Teoretycznie osoba, która przyczyniła się do mojego projektu, mogłaby teraz uruchomić testy integracyjne poprzez:

  • tworzenie własnego użytkownika testowego i organizacji testowej na GitHub
  • tworzenie niektórych repozytoriów testowych
  • tworząc własną wersję environment-variables.bato różnych wartościach

Problem polega na tym, że moja aplikacja będzie mogła wykonać kopię zapasową wielu hostów kodu źródłowego.
Obecnie obsługuje tylko GitHub, ale łatwo będzie dodać obsługę większej liczby hostów, dodając kilka klas, które implementują odpowiednie interfejsy.

Kiedy później zaimplementuję obsługę większej liczby hostów, liczba zmiennych środowiskowych wzrośnie.
Aby móc przeprowadzić wszystkie testy integracyjne, potencjalny współpracownik utworzyłby własnych użytkowników, organizacje i repozytoria testów w GitHub, Bitbucket, GitLab, .... i kto wie, o ile więcej, i dodałby je wszystkie do swojej environment-variables.batwersji.

Czy jest lepsze rozwiązanie, jak to zrobić w projekcie, w którym kod jest publiczny?

Wiem, że inne projekty robią coś podobnego do tego, co obecnie robię.
Na przykład Octokit.net ma skrypt do ustawiania zmiennych środowiskowych na potrzeby testów integracyjnych wywołujących interfejs API GitHub.
Ale potrzebują tylko jednego użytkownika i jednej organizacji, a ja będę potrzebować znacznie więcej.

Może nie potrzebuję rozwiązania, które umożliwiłoby współautorowi przeprowadzenie wszystkich testów integracyjnych.
Na przykład, jeśli ktoś chciałby przyczynić się do obsługi GitHub w moim projekcie, musiałby tylko móc uruchomić testy integracyjne GitHub.
Więc może potrzebuję rozsądnego sposobu, aby móc podzielić moje testy integracyjne na nieskończoną liczbę „grup” (?), A następnie powiedzieć „i teraz wykonać wszystkie testy, które należą do grupy„ Github ””.

Christian Specht
źródło

Odpowiedzi:

2

Myślę, że twoja obecna konfiguracja jest w porządku, ale dokonałbym kilku zmian.

Aby móc przeprowadzić wszystkie testy integracyjne, potencjalny współpracownik stworzyłby własnych użytkowników, organizacje i repozytoria testów w GitHub, Bitbucket, GitLab, .... i kto wie, o ile więcej, i dodałby je wszystkie do swoich zmiennych środowiskowych wersja bat.

Tak, to prawda, ale autorzy niekoniecznie muszą przeprowadzić wszystkie testy integracyjne przed utworzeniem PR w projekcie. Po utworzeniu PR CI uruchomi pełny zestaw testów.

Często zdarza się, że zestaw testowy jest w jakiś sposób niemożliwy do uruchomienia. W wielu organizacjach utrzymują pakiety testowe, których uruchomienie zajmuje kilka dni - dlatego programiści muszą selektywnie uruchamiać testy, które są łatwe do uruchomienia, i przesuwać kod do przodu, aby przeprowadzić bardziej rygorystyczne testy. Sugeruję to samo podejście.

Dla stałych / zaufanych współpracowników możesz uczynić ich faktycznymi współpracownikami w twoim projekcie, co powinno pozwolić im uruchomić CI w swoim oddziale przed dokonaniem PR.

To powiedziawszy, nie powstrzymujesz współpracowników przed uruchomieniem pełnego zestawu testów. Mogą podać własne poświadczenia GitHub lub utworzyć własne konta testowe, a regularni współpracownicy prawdopodobnie to zrobią.

Dostosowania, które sugeruję, to:

Najpierw wykorzystaj większość swoich testów pokrycia testowego. Powinny one obejmować wszystkie gałęzie twojej bazy kodu.

Po drugie, napisz testy integracji, w których drwi punkt końcowy. Możesz nawet wyśmiewać warstwę transportową tych interfejsów API i symulować przepływy żądań / odpowiedzi HTTP, uruchamiając fałszywą usługę GitHub Rest. Na przykład (w pseudo kodzie):

// 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()

Te testy będą bardziej złożone, ale na to pozwolą

  1. Testuj bez tworzenia fałszywych kont i repozytoriów
  2. Testuj warunki awarii, które trudno byłoby zasymulować za pomocą prawdziwego GitHub. Na przykład odpowiedzi 502, przekroczenia limitu czasu połączenia, nietypowe / niemożliwe do rozdzielenia treści odpowiedzi.

Po trzecie, wyłącz wszelkie testy wymagające specjalnej wiedzy przed uruchomieniem w normalnej wersji. W większości narzędzi do zarządzania kompilacjami istnieje sposób na oddzielne testy integracyjne lub testy tagów i selektywne ich uruchamianie. Współtwórcy powinni mieć możliwość budowania i testowania oprogramowania bez uprzedniej konfiguracji. Pełny zestaw testów powinien działać po każdej kompilacji w CI.

Na koniec udokumentuj testy i sposób ich uruchomienia w dokumentacji testu, aby współtwórcy mogli je uruchomić.

Samuel
źródło