Pact - это инструмент для тестирования контрактов - типа интеграционного тестирования, который позволяет гарантировать, что сервисы могут взаимодействовать друг с другом. В этом сообщении блога будет немного подробно рассказано о работе с аутентификацией при проверке провайдера, поэтому предполагается, что вы уже имеете некоторые знания о тестировании контрактов. Если вы хотите узнать об этом больше, я настоятельно рекомендую вам посетить https://docs.pact.io/ - официальную документацию Пакта.

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

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

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

Как мы можем это решить?

customProviderHeaders - заголовки для всех запросов

В то время это было единственное, что предлагал Pact. Они предоставили вам способ вставлять статический заголовок в каждый запрос, который будет воспроизводиться провайдером. Вы добавляете ключ customProviderHeaders к параметрам, которые вы передаете для проверки своих пактов, с массивом различных заголовков, которые вы хотите вставить в качестве значения:

Хотя это может решить проблему для некоторых типов аутентификации, для нас это не помогло. Нам нужен был способ динамического создания аутентификации на основе определенных свойств запроса, поскольку для этой конкретной службы запросы использовали подпись AWS. Этот вид аутентификации динамически генерируется на основе нескольких деталей запроса, таких как хост, путь, метод и регион AWS.

Наше оригинальное решение

Сначала мы связались с разработчиками Пакта по их слабому каналу. В то время Pact не поддерживал способ динамического создания этой аутентификации (т. Е. Знать, какой запрос он воспроизводит, в то время, когда он вводит заголовки). Они попросили меня открыть запрос функции на их странице Github.

А пока мне нужен обходной путь! Мы решили перестать получать контракты напрямую от Pact Broker, а вместо этого делать это из локальной папки (конечно, в CI). Затем мы могли бы сами получать контракты от Pact Broker в ловушке Before, анализировать их и динамически изменять, добавляя правильные заголовки для каждого запроса, который мы просматривали в цикле. Я не буду вдаваться в подробности того, как мы это реализовали, потому что, как я объясню позже, команда Пакта уже решила эту проблему, и нам больше не нужен этот обходной путь. Я оставлю вам небольшой код, который содержит скелет нашего подхода (по сравнению с приведенным выше):

Где generateTempPact была функцией, которая получила пакт от Pact Broker, проанализировала его, динамически вставила заголовки и затем поместила его по пути, указанному в параметрах поставщика.

Команда Пакта спешит на помощь! - лучшее решение

Как я уже упоминал, они попросили меня опубликовать запрос функции по их проблемам с Github. И они действительно дошли до этого! Мне очень понравилось открытое общение их разработчиков. Они не только быстро отреагировали, но и реализовали решение проблемы!

Подход, который они выбрали, который мне очень нравится, заключается в том, чтобы представить концепцию requestFilters, которая определяется в параметрах поставщика. Фильтр запросов - это функция, которая имеет доступ к объектам req и res из файла контракта и может изменять их перед передачей на проверку. Это именно то, что нам нужно для решения этой задачи. Это гораздо более чистое решение, которое решает другие аналогичные проблемы, которые могут возникнуть в будущем, когда перехват запроса / ответа может быть полезен. Вы можете увидеть их пример на их Github.

Вот как теперь будет выглядеть наш предыдущий файл provider.spec.js:

Наша функция generateNewHeaders теперь будет заботиться о создании необходимых заголовков AWS и добавлении их к нашим существующим.

Также стоит отметить, что в этом выпуске команда Pact также добавила новую функцию, позволяющую указывать объект stateHandlers в параметрах. Этот объект состоит из пар "ключ-значение", где ключ - это providerState, который вы указали в своем контракте, а значение - это функция, которая выполняет действия, необходимые для достижения этого состояния. Это большое улучшение по сравнению с предыдущим способом, так как вам нужно было иметь доступную конечную точку, которая выполняла действие за вас. Вы можете увидеть, как это реализовано в том же примере, который я опубликовал выше.

Все это теперь доступно в PactJS версии 8.x.x.

Заключительные мысли

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

Но помните: хотя это действительно полезные дополнения, вы должны быть осторожны при их использовании. Как советует команда Pact, вы должны утомиться, если слишком много возитесь с потребительскими контрактами на уровне проверки - вы по-прежнему хотите, чтобы ваш контракт отражал то, чего ожидала ваша команда потребителей!