Posted on 2022-07-19

Спочатку тут була одна велика стаття про тестування терраформу з теоретичними викладками, схибленою логікою та прикладами що включали у себе біготню без штанів. Я вирішив поділити її на шматочки, щоб вам, мої любі, було зручніше їх їсти.

Ця стаття про те як не треба тестувати терраформ. Якщо ви хочете взнати як треба, то вам сюди.

Далі я буду наводити приклади з мого складного життя і розбирати чому саме так робити не треба.

Антіпаттерн 1: тестування інфраструктури

Якщо одразу не розборонити інфраструктуру та код, то замість тестів у вас можуть вилупитися дуже цікаві цуцикопівні - ні лають, ні квохчуть, тільки дивляться грусними оченятами.

Не треба тeстувати чи є в інфраструктурі якісь ресурси, чи конфіги. Треба тестувати лише код, який ви написали.

Антіпаттерн 2: тестування лише позитивних сценаріїв

Якщо в вас є якась логіка яку ви хочете перевірити, то треба тестувати не лише успішні кейси, але й неуспішні.

Падіння программи у випадку якщо данні на вході не правильні — то добра поведінка. І ви маєте точно знати коли ваша функція працює, а коли — ні і що з цим робити.

Інакше ви можете опинитись у ситуації, коли невалідний інпут робить вам бо-бо і розвалює стейт частковим аплаєм.

Антіпаттерн 3: тестування ресурсів

Інша проблема — недовіра. Хороший девопс накопичує психотравми як бєлочка горішки. І згодом, як розвідник, не довіряє нікому. Навіть собі.

Ось є в тебе терраформ код котрий підіймає один інстанс.

data "aws_ami" "ubuntu" {
	...
}

resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t3.micro"

  tags = {
    Name = "HelloWorld"
  }
}

Можна зробити тераформ ап і подивитись чи з’явився інстанс. Але шо то дасе?

Нічого! Отже майже завжди то тестити не треба.

Ресурси — декларативні, тобто повинні вже бути протестовані і їх тести повинні бути у репках з провайдером.

А якщо ресурси не працюють? Ну кидай ішью, чи піди поплач в шкарпетки, не знаю. Ну чи тестуй, але виключно те, що потребує тестування.

Тестування датасорців

Тести датасорців також досить дивні. Наприклад, ось кейс з моєї практики:

data "aws_ami" "ubuntu" {
	...
}

Що воно хоче зрозуміти? Просто так заради фану ну можна шукати напевно, але... навіщо?

Якщо ресурс який ти шукаєш у датасорці створений не тобою за кілька хвилин до тесту, то то вже не тестування, а моніторинг. Я читав що справжні козаки моніторять інфру дженкінсом, але це не дуже зручно. До того ж тести будуть довгі і ще будуть падати без зв’язку з змінами кода.

Антіпаттерн 4: Тестування інпуту

Ще одна популярна місконцепція — валідація інпуту як тестування.

variable "listener_rule_priority" {
 type        = number
 default     = 1
 description = "Priority of listener rule between 1 to 50000"
 validation {
   condition     = var.listener_rule_priority > 0 && var.listener_rule_priority < 50000
   error_message = "The priority of listener_rule must be between 1 to 50000."
 }
}

Валідація інпуту то не є тестуванная. То є частина вашої программи яку ви пишете мовою терраформ.

Те саме стосується precondition і postcondition блоків в ресурсах.

Увесь код, написанний в модулі є кодом, котрий потребує додаткового тестування — чи працює валідація так як хотілося? Ось що важливо.

Тому кожен блок з валідацією — ціль для тестів, а не тести.

Антіпаттерн 5: тестування великих модулів

Мабуть найбільш поширена місконцепція.

Як приклад — модуль який створює кубернетіс кластер і в ньому VPC, якісь хелм ресурси і так далєє. Можна ж просто його подняти і подивитись чи все створене, ну чому ні?

Проблема в тому, що у великих модулях нам треба тестувати усі можливі комбінації успішних і невдалих сценаріїв.

Ось наприклад кількість змінних у terraform-aws-eks модулі.

І на кожну комбінацію треба робити окремий аплай і створювати окремий кластер.

Це дуже дорого. Це дуже повільно, бо може бути 100-200 різних комбінацій і кожен аплай може тривати хвилин по 20-30.

Тому майже ніколи не потрібно тестувати великі модулі одним махом, краще розбивати їх на частини і тестувати вже частини.

Тестування комьюніті модулів

Комьюніті модулі зазвичай не протестовані і створені з велетеньским різномаїттям можливостей. І там ті ж самі проблеми, що в будь-яких великих модулях, помножені на різномаїття фантазії авторів модуля.

Якщо ви використовуєте модулі, то звісно треба тестувати сценарії, але не усі сценарії які покриває модуль, але лише ваші. Бо то довго і складно, чи думаєте чого автори модулів їх не тестують?

Для успішного тестування — комьюніті модулі треба ізолювати по можливостям, створивши навколо них враппер в котрому зафіксувати лише ті можливості модуля які потрібні вам.

Але зазвичай простіше написати код самостійно — так щоб він а) не потребував тестування (чисті ресурси без логіки) б) тестування було зробити просто (логіка ізольована у сабмодулях)

Антіпаттерн 6: тестування лише підняття з чистого листа

Інша велика проблема — тестування створення.

Якщо ви тестуєте лише створення, то ви ніяк не відреагуєте на те що терраформ може щось зламати у процесі оновлення.

Наприклад, у вас є тест що рахує кількість створенних інстансів. Ви тестуєте щоб їх було 10.

А потім заміняєте count на for_each і терраформ при оновленні видале ресурси замість оновлення референсу.

Тестування змін складне, сумне та невеселе. Простіше всього тестити на різних оточеннях — staging → preprod → prod.

Але якщо такої змоги нема — можна підняти попередню версію і потім накатити нову зверху і дивитись у віконечко як проходить міграція.

Висновки

Не треба робити роботу, котра нікому не потрібна і нічого не дає. Краще почитайте як треба тестувати терраформу і витрачайте мінімум часу, бо життя одне. А зарплатню вам і так будуть платити.