Введение
Конфигурация может быть отформатирована и структурно корректна, но при этом неверно обозначать среду отчётов. Вашей команде нужны исполняемые проверки входных значений, выходных значений и запланированных тегов небольшого модуля хранилища, прежде чем доверять плану доставки.
Вы напишете контракт модуля, проверите две поддерживаемые среды и неподдерживаемое входное значение и заставите настоящий бизнес-дефект останавливать задание. Вы должны понимать переменные и выходные значения модулей, а также контрольные этапы форматирования и валидации из предыдущей лабораторной работы. Существующее эталонное хранилище должно остаться без изменений.
Связь с сертификацией
| Сертификация | Задача экзамена | Практика |
|---|---|---|
| DevOps Engineer – Professional (DOP-C02) | Задача 1.2 | Базовая практика включения исполняемых утверждений модуля в автоматизированный контроль качества. |

Определение входного контракта
На этом шаге вы определите, какие входные значения среды принимает модуль хранилища. Проверка входных данных отклоняет неподдерживаемый запрос до создания плана ресурсов.
Перейдите в предоставленный модуль и загрузите подготовленные инструменты.
cd /home/labex/project/report-module
source environment.sh
Прочитайте его интерфейс и реализацию ресурсов.
cat variables.tf main.tf outputs.tf pipeline.json
environment выбирает preview или review; bucket_prefix различает имена хранилищ вызывающей стороны. Имя бакета объединяет оба входных значения, а тег Environment и выходное значение должны определять запрошенную среду. Предоставленные main.tf, outputs.tf, provider.tf и run-job.py необходимо сохранить: оставьте их итоговое содержимое без изменений. Ваша работа относится к variables.tf, tests/ и pipeline.json.
Добавьте блок validation к environment. contains проверяет принадлежность поддерживаемому списку; ложное condition выдаёт указанное сообщение об ошибке. Here-document с разделителем в кавычках записывает HCL буквально.
cat > variables.tf <<'EOF'
variable "environment" {
type = string
default = "preview"
validation {
condition = contains(["preview", "review"], var.environment)
error_message = "Choose preview or review."
}
}
variable "bucket_prefix" {
type = string
default = "delivery-contract"
}
EOF
Отформатируйте изменение.
terraform fmt
Попробуйте неподдерживаемый запрос. -var передаёт значение для этого вызова. Эта команда намеренно возвращает собственный код завершения 1; она должна сообщить Choose preview or review., а не предложить бакет production.
terraform plan -input=false -var=environment=production
Валидация определяет допустимый интерфейс. На следующем шаге тесты проверят оба допустимых значения и этот ожидаемый отказ.
Написание утверждений и наблюдение за реальной ошибкой
На этом шаге вы используете собственную команду Terraform terraform test для проверки запланированного поведения модуля. Форматирование и валидация могут принять жёстко заданное, но неверное выходное значение; утверждение сравнивает вычисленный результат с запрошенным входным значением.
Terraform читает файлы .tftest.hcl в tests/. Каждый run — независимый тестовый сценарий. Явное command = plan оценивает план без его применения. Храните файлы тестов в tests/ в формате .tftest.hcl. В этой лабораторной работе каждый запуск должен использовать режим plan и предоставленные провайдер и модуль; альтернативные модули, моки провайдеров и переопределения выходят за рамки задачи. Сохраните наследование bucket_prefix от входных данных набора тестов: не присваивайте ему значение в тестовых переменных уровня файла или запуска, чтобы вызывающая сторона могла выбрать другой допустимый префикс. Эти тесты проверяют известные значения плана, а не фактическое создание, разрешения во время выполнения или развёрнутое приложение.
Создайте каталог тестов. mkdir -p создаёт его при необходимости и допускает существующий каталог.
mkdir -p tests
Напишите утверждения для среды по умолчанию и альтернативной среды. var ссылается на входные данные запуска, ссылки на ресурсы проверяют запланированные значения, а output ссылается на выходные значения модуля. expect_failures требует ошибки валидации указанной переменной; он не превращает произвольные ошибки провайдера или сети в успешные тесты.
cat > tests/contract.tftest.hcl <<'EOF'
run "preview_contract" {
command = plan
assert {
condition = output.environment == var.environment
error_message = "The output must identify the requested environment."
}
assert {
condition = aws_s3_bucket.reports.bucket == "${var.bucket_prefix}-${var.environment}"
error_message = "The bucket name must use the requested prefix and environment."
}
assert {
condition = aws_s3_bucket.reports.tags.Environment == var.environment
error_message = "The planned tag must identify the requested environment."
}
}
run "review_contract" {
command = plan
variables { environment = "review" }
assert {
condition = output.environment == var.environment
error_message = "The alternate environment must not use the default label."
}
assert {
condition = aws_s3_bucket.reports.bucket == "${var.bucket_prefix}-${var.environment}"
error_message = "The alternate bucket must use its requested inputs."
}
assert {
condition = aws_s3_bucket.reports.tags.Environment == var.environment
error_message = "The alternate environment tag must match its input."
}
}
run "unsupported_environment" {
command = plan
variables { environment = "production" }
expect_failures = [var.environment]
}
EOF
Рекурсивно отформатируйте тесты и файлы модуля.
terraform fmt -recursive
Запустите набор тестов.
terraform test
Ожидайте три успешных запуска и сводку об успехе. Тестовый бакет не развёртывается. Входные и выходные значения поступают из реального плана Terraform с настроенным провайдером.
Докажите, что ваши утверждения обнаруживают правдоподобный дефект. Временно замените только выходное значение среды фиксированной меткой по умолчанию; сохраните выходное значение имени бакета.
cat > outputs.tf <<'EOF'
output "environment" {
value = "preview"
}
output "bucket_name" {
value = aws_s3_bucket.reports.bucket
}
EOF
Запустите набор ещё раз. Эта команда намеренно возвращает собственный код завершения 1. Утверждение для альтернативной среды должно завершиться ошибкой, показывая, что корректный HCL всё ещё может нарушать контракт модуля.
terraform test
Восстановите предоставленную реализацию выходных значений из Git. Это удаляет временный дефект, сохраняя написанные вами валидацию и тесты.
git restore -- outputs.tf
Проверьте исправленную реализацию теми же утверждениями.
terraform test
Все запуски должны снова пройти. Тесты должны принимать допустимые входные данные, а не просто распознавать одно выходное значение по умолчанию.
Остановка задания доставки с помощью тестов
На этом шаге вы разместите тесты модуля между статическими контрольными этапами и планированием. Предоставленный исполнитель — часть подготовки; редактируйте конфигурацию этапов, а не run-job.py.
Добавьте test после fmt/validate и перед plan.
cat > pipeline.json <<'EOF'
{"stages":["fmt","validate","test","plan"]}
EOF
Запустите полное задание.
python3 run-job.py
Все четыре этапа должны пройти. Итоговый план может вернуть собственный код 2, потому что этот модуль не был применён; исполнитель считает это успешным предварительным просмотром. Неудачный тест, напротив, должен остановить задание до этапа plan. Этапа apply нет.
Запустите набор с другим допустимым префиксом бакета. Этот -var меняет входные данные набора без редактирования модуля или его тестов.
terraform test -var=bucket_prefix=audit-contract
Те же три запуска должны пройти. В этом упражнении сохраните наследование bucket_prefix от вызывающей стороны в каждом запуске: не присваивайте ему значение в блоках variables уровня файла тестов или запуска. Такие присваивания переопределяют входные данные тестов из CLI и не дадут этой команде проверить запрошенный префикс. Переопределения среды по-прежнему необходимы для проверки обеих поддерживаемых сред. Утверждения, построенные на запрошенных входных данных, продолжают работать, когда вызывающая сторона выбирает другое допустимое имя.
Прочитайте существующий эталонный отчёт непосредственно из хранилища. Эти подготовленные бакеты принадлежат другой среде; не удаляйте и не изменяйте их.
aws s3 cp s3://delivery-reference-reports/report.txt -
В нём по-прежнему должно быть reference report v1. Проверьте и соседние данные.
aws s3 cp s3://delivery-reference-neighbor/keep.txt -
Ожидайте preserve contract neighbor. Ваши тесты не создавали ресурсов хранилища, поэтому тестового стека для удаления нет. Сохраните входной контракт, тесты и конфигурацию конвейера для заключительной проверки; временный дефект выходного значения уже удалён.
Резюме
Вы определили поддерживаемый входной контракт, использовали собственные тесты Terraform в режиме plan для сравнения запланированных выходных значений и тегов с входными данными и увидели реальную ошибку утверждения. Затем вы включили тесты в контроль качества доставки, сохранив существующие данные и бизнес-состояние.
Тесты в режиме plan не подтверждают поведение развёрнутой системы. Последующие этапы доставки объединяют эти проверки с проверенным конкретным планом и реальным контролируемым применением. О механизмах, изученных здесь, читайте в официальном справочнике Terraform test и документации по конфигурации тестов.



