Интеграционные тесты в проектах OSS - как обращаться с третьими лицами с аутентификацией?

10

Один из моих (с открытым исходным кодом) хобби-проектов - это инструмент резервного копирования, который делает автономные резервные копии репозиториев из GitHub, Bitbucket и т. Д.
Он вызывает API хостеров, чтобы получить список репозиториев, а затем использует Git / Mercurial / что угодно для клонирования / вытащить репозитории на локальный компьютер.

Поэтому у меня есть интеграционные тесты, где я вызываю GitHub API с аутентификацией.
(и когда функция клонирования / извлечения будет завершена, вероятно, будут тесты, которые клонируют репозитории из GitHub, и также должны пройти аутентификацию)

Я создал пользователя и организацию специально для использования в этих интеграционных тестах.

Проблема: я не могу просто жестко закодировать пароли где-нибудь в исходном коде, потому что это открытый исходный код, и код общедоступен на GitHub.


Что я делаю сейчас

В тестах я получаю все имена пользователей, пароли и имена репозиториев из переменных среды.
Вот пример :

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

( TestHelper.EnvVarэто вспомогательный метод, который получает значение переменной среды и выдает исключение, когда она не существует)

Затем у меня есть командный файл, который устанавливает эти переменные среды.
Функция real one ( environment-variables.bat) вызывается в моем сценарии сборки и перед выполнением тестов, но игнорируется в системе контроля версий, поэтому на самом деле ее нет в моем хранилище.

Что находится в системе управления версиями является environment-variables.bat.sample, который устанавливает те же переменные окружения, но с фальшивыми паролями:

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

Таким образом, я могу клонировать репозиторий на мою машину, переименовать этот файл в environment-variables.bat, заменить поддельный пароль реальным, и все интеграционные тесты будут работать.

Это также работает с Continuous Integration - я использую AppVeyor, и там я могу установить эти переменные среды в веб-интерфейсе .


Что мне не нравится в этом

Я думаю, что это не хорошее решение для проекта OSS, и особенно не для этого проекта:

Теоретически, участник моего проекта сможет запустить интеграционные тесты прямо сейчас:

  • создание собственного тестового пользователя и тестовой организации на GitHub
  • создание некоторых тестовых репозиториев
  • создавая свою собственную версию environment-variables.batс разными ценностями

Проблема в том, что мое приложение сможет создавать резервные копии нескольких хостов исходного кода.
Прямо сейчас он поддерживает только GitHub, но будет легко добавить поддержку большего количества хостеров, добавив несколько классов, которые реализуют правильные интерфейсы.

Поэтому, когда я реализую поддержку большего количества хостеров позже, число переменных среды будет расти.
Чтобы иметь возможность выполнить все интеграционные тесты, потенциальный участник должен создать своих собственных пользователей, организации и репозитории для тестов в GitHub, Bitbucket, GitLab, .... и кто знает, сколько еще, и добавить их всех в свою environment-variables.batверсию.

Есть ли лучшее решение, как это сделать в проекте, где код является открытым?

Я знаю, что другие проекты делают нечто похожее на то, что я делаю сейчас.
Например , у Octokit.net есть скрипт для настройки переменных среды для интеграционных тестов, которые вызывают GitHub API.
Но им нужен только один пользователь и одна организация, а мне нужно намного больше.

Может быть, мне не нужно решение, которое позволяет участнику фактически запускать все интеграционные тесты.
Например, если кто-то захочет внести свой вклад в поддержку моего проекта GitHub, ему нужно только иметь возможность запускать интеграционные тесты GitHub.
Поэтому, возможно, мне просто нужен разумный способ, чтобы разделить мои интеграционные тесты на бесконечное количество «групп» (?), А затем сказать «и теперь выполнить все тесты, принадлежащие группе« Github »».

Кристиан Шпехт
источник

Ответы:

2

Я думаю, что ваша текущая настройка просто отлично, но я бы сделал несколько корректировок.

Чтобы выполнить все интеграционные тесты, потенциальный участник должен создать своих собственных пользователей, организации и репозитории для тестов в GitHub, Bitbucket, GitLab, .... и кто знает, сколько еще, и добавить их всех в свои переменные среды .bat версия.

Да, это правда, но участники не обязательно должны запускать все интеграционные тесты, прежде чем создавать PR в своем проекте. Как только PR создан, CI запустит полный набор тестов.

Распространено иметь набор тестов, который так или иначе не может быть легко запущен. Для многих организаций они поддерживают наборы тестов, на выполнение которых уходят дни, поэтому разработчики должны выборочно запускать тесты, которые легко запустить, и продвигать код вперед для более тщательного тестирования. Я предлагаю такой же подход.

Для постоянных / доверенных участников вы можете сделать их фактическими участниками вашего проекта, что должно позволить им запускать CI в своей ветке перед созданием PR.

Тем не менее, вы не мешаете авторам запускать полный набор тестов. Они могут предоставить свои собственные учетные данные GitHub или создать свои собственные тестовые учетные записи, и постоянные участники, вероятно, сделают это.

Я предлагаю следующие корректировки:

Во-первых, сделайте большинство ваших тестовых юнит-тестов. Они должны охватывать все ветви вашей кодовой базы.

Во-вторых, напишите интеграционные тесты, в которых проверяется конечная точка. Вы даже можете смоделировать транспортный уровень этих API и моделировать потоки HTTP-запросов / ответов, запустив поддельную службу GitHub Rest. Например (в псевдокоде):

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

Эти тесты будут более сложными, но позволят вам

  1. Тестирование без создания поддельных учетных записей и репозиториев
  2. Тестируйте условия неудачи, которые было бы трудно смоделировать на реальном GitHub. Например, 502 ответа, время ожидания соединения, необычные / не разбираемые тела ответа.

В-третьих, отключите любые тесты, которые требуют специальных знаний, от запуска под нормальной сборкой. В большинстве инструментов управления сборкой есть способ разделить интеграционные тесты или пометить тесты и выборочно запустить их. Участники должны иметь возможность собирать и тестировать программное обеспечение без предварительной настройки. Полный набор тестов должен запускаться после каждой сборки в CI.

Наконец, документируйте тесты и их запуск в документации по тестам, чтобы участники могли выбрать их запуск.

Самуил
источник