Общие сведения

ВступлениеПодготовка к запускуАрхитектура платформы TestoПорядок запускаПолитика запуска тестов

Обучающие материалы по Testo для Hyper-V

Часть 1. Самый первый тестЧасть 2. Устанавливаем Ubuntu ServerЧасть 3. Доступ в Интернет из виртуальной машиныЧасть 4. Гостевые дополненияЧасть 5. ПараметрыЧасть 6. КешированиеЧасть 7. Связываем две машины по сетиЧасть 8. ФлешкиЧасть 9. МакросыЧасть 10. Конструкция ifЧасть 11. No snapshotsЧасть 12. Управление мышкойЧасть 13. Импортирование жёстких дисковЧасть 14. JS-селекторыЧасть 15. Циклы

Обучающие материалы по Testo для QEMU

Часть 1. Самый первый тестЧасть 2. Устанавливаем Ubuntu ServerЧасть 3. Гостевые дополненияЧасть 4. ПараметрыЧасть 5. КешированиеЧасть 6. Доступ в Интернет из виртуальной машиныЧасть 7. Связываем две машины по сетиЧасть 8. ФлешкиЧасть 9. МакросыЧасть 10. Конструкция ifЧасть 11. No snapshotsЧасть 12. Управление мышкойЧасть 13. Импортирование жёстких дисковЧасть 14. JS-селекторыЧасть 15. ЦиклыЧасть 16. Макросы с объявлениями

Спецификация языка

Общая структура скриптовых файловБазовые конструкции языкаOбъявление виртуальной машиныОбъявление виртуального флеш-накопителяОбъявление виртуальной сетиПараметрыОбъявление тестовМакросыДействия с виртуальными машинамиДействия с мышкойПоиск изображений на экранеДействия с виртуальными флеш-накопителямиУсловияЦиклыСписок идентификаторов клавиш

Запросы на языке Javascript

Общая концепция построения JS-селекторовВстроенные глобальные функции JavascriptИсключенияКласс TextTensorКласс ImgTensorКласс Point

Часть 11. No snapshots

С чем Вы познакомитесь

В этой части вы познакомитесь с тестами без снепшотов гипервизора в платформе Testo, которые могут позволить сэкономить вам очень много места на диске.

Начальные условия

  1. Платформа Testo установлена.
  2. Гипервизор Hyper-V установлен.
  3. Имеется установочный образ Ubuntu server 16.04 с расположением C:\iso\ubuntu_server.iso. Местоположение и название установочного файла может быть другим, в этом случае нужно будет соответствующим образом поправить параметр ISO_DIR, передаваемый через командную строку во время запуска тестов.
  4. Имеется образ с гостевыми дополнениями Testo для Hyper-V в одной папке с установочным образом Ubuntu.
  5. Хост имеет доступ в Интернет.
  6. (Рекомендовано) Настроена подсветка синтаксиса Testo-lang в Sublime Text 3.
  7. (Рекомендовано) Проделаны шаги из десятой части.

Вступление

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

Но такое поведение рано или поздно может привести к проблемам: каждый снепшот (как машин, так и флешек) занимает немало места на диске, и это самое место может очень быстро закончиться. Ситуация усугубляется тем, что в конце успешного теста создаются снепшоты всех сущностей, участвующих в тесте. Если, например, тест включает в себя пять виртуальных машин и две виртуальных флешки, то в конце теста вы получите пять снепшотов виртуальных машин и два снепшота для флешек.

Поэтому в языке Testo-lang существует механизм, который позволяет не создавать снепшоты гипервизора для виртуальных сущностей, а ограничиваться фиксацией тестов в виде метаданных. Грамотное использование этого механизма позволит вам сэкономить очень много места на диске без особого ущерба, и именно с этим механизмом мы познакомимся в этом уроке.

С чего начать?

Для лучшей демонстрации мы разделим тест test_ping из предыдущих гайдов на два теста: test_ping_1 и test_ping_2.

test test_ping_1: client_setup_nic, server_setup_nic {
    client exec bash "ping 192.168.1.2 -c5"
}

test test_ping_2: client_setup_nic, server_setup_nic {
    server exec bash "ping 192.168.1.1 -c5"
}

После этого прогоним все тесты ещё раз и добьёмся чтобы они были закешированы:

C:\Users\Testo> testo run tests.testo --stop_on_fail --param ISO_DIR C:\iso --assume_yes
UP-TO-DATE TESTS:
server_install_ubuntu
server_prepare
server_install_guest_additions
server_setup_nic
client_install_ubuntu
client_prepare
client_install_guest_additions
client_setup_nic
TESTS TO RUN:
test_ping_1
test_ping_2
[ 80%] Preparing the environment for test test_ping_1
[ 80%] Restoring snapshot server_setup_nic for virtual machine server
[ 80%] Restoring snapshot client_setup_nic for virtual machine client
[ 80%] Running test test_ping_1
[ 80%] Executing bash command in virtual machine client with timeout 10m
+ ping 192.168.1.2 -c5
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.016 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.035 ms
64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=0.030 ms
64
bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=0.033 ms
64 bytes from 192.168.1.2: icmp_seq=5 ttl=64 time=0.087 ms

--- 192.168.1.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4075ms
rtt min/avg/max/mdev = 0.016/0.040/0.087/
0.024 ms
[ 80%] Taking snapshot test_ping_1 for virtual machine client
[ 80%] Taking snapshot test_ping_1 for virtual machine server
[ 90%] Test test_ping_1 PASSED in 0h:0m:14s
[ 90%] Preparing the environment for test test_ping_2
[ 90%] Restoring snapshot server_setup_nic for virtual machine server
[ 90%] Restoring snapshot client_setup_nic for virtual machine client
[ 90%] Running test test_ping_2
[ 90%] Executing bash command in virtual machine server with timeout 10m
+ ping 192.168.1.1 -c5
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.017 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.033 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.033 ms
64
bytes from 192.168.1.1: icmp_seq=4 ttl=64 time=0.033 ms
64 bytes from 192.168.1.1: icmp_seq=5 ttl=64 time=0.035 ms

--- 192.168.1.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4095ms
rtt min/avg/max/mdev = 0.017/0.030/0.035/
0.007 ms
[ 90%] Taking snapshot test_ping_2 for virtual machine client
[ 90%] Taking snapshot test_ping_2 for virtual machine server
[100%] Test test_ping_2 PASSED in 0h:0m:14s
PROCESSED TOTAL 10 TESTS IN 0h:0m:28s
UP-TO-DATE: 8
RUN SUCCESSFULLY: 2
FAILED: 0
C:\Users\Testo>

Конечно, это достаточно условное разделение, но оно нам пригодится для лучшего понимания механизма тестов без снепшотов.

Теперь посмотрим на наше дерево тестов, которое у нас накопилось на текущий момент.

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

Давайте подумаем, а зачем вообще нужны снепшоты в конце каждого успешного теста? В первую очередь это необходимо для того, чтобы платформа Testo могла бы вернуться к сохранённым снепшотам в случае, если нужно прогнать тесты-потоки закешированного теста. Например, если бы в нашем дереве тестов тест test_ping_1 потерял бы целостность, то нам нужно было бы восстановить виртуальные машины в состояния server_setup_nic (для машины server) и client_setup_nic (для машины client) для того, чтобы заново прогнать этот тест.

Но зачем нужны снепшоты в конце тестов test_ping_1 и test_ping_2? Ведь эти тесты являются конечными в нашей иерархии, и возвращаться к состоянию виртуальных машин на момент их успешного окончания просто бесмыссленно. Поэтому давайте попробуем убрать в этих двух тестах снепшоты (пожалуйста, убедитесь что все тесты проведены успешно и закешированы прежде чем изменять тестовые сценарии):

[no_snapshots: true]
test test_ping_1: client_setup_nic, server_setup_nic {
    client exec bash "ping 192.168.1.2 -c5"
}

[no_snapshots: true]
test test_ping_2: client_setup_nic, server_setup_nic {
    server exec bash "ping 192.168.1.1 -c5"
}

Здесь мы воспользовались ещё одной новой для нас языковой конструкцией - атрибутами тестов. Всего существует два возможных атрибута тестов: no_snapshots и description. Атрибут description не такой интересный и позволяет лишь добавить текстоое описание теста, которое затем будет сохранено в отчете (если конечно проинструктировать Testo создать такой отчет с помощью аргумента командной строки --report_folder). Атрибут no_snapshots гораздо более значимый и нам необходимо задать ему значение true.

Попробуем запустить тесты:

C:\Users\Testo> testo run tests.testo --stop_on_fail --param ISO_DIR C:\iso --assume_yes
UP-TO-DATE TESTS:
server_install_ubuntu
server_prepare
server_install_guest_additions
server_setup_nic
client_install_ubuntu
client_prepare
client_install_guest_additions
client_setup_nic
TESTS TO RUN:
test_ping_1
test_ping_2
[ 80%] Preparing the environment for test test_ping_1
[ 80%] Restoring snapshot server_setup_nic for virtual machine server
[ 80%] Restoring snapshot client_setup_nic for virtual machine client
[ 80%] Running test test_ping_1
[ 80%] Executing bash command in virtual machine client with timeout 10m
+ ping 192.168.1.2 -c5
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.016 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.035 ms
64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=0.030 ms
64
bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=0.033 ms
64 bytes from 192.168.1.2: icmp_seq=5 ttl=64 time=0.087 ms

--- 192.168.1.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4075ms
rtt min/avg/max/mdev = 0.016/0.040/0.087/
0.024 ms
[ 80%] Taking snapshot test_ping_1 for virtual machine client
[ 80%] Taking snapshot test_ping_1 for virtual machine server
[ 90%] Test test_ping_1 PASSED in 0h:0m:14s
[ 90%] Preparing the environment for test test_ping_2
[ 90%] Restoring snapshot server_setup_nic for virtual machine server
[ 90%] Restoring snapshot client_setup_nic for virtual machine client
[ 90%] Running test test_ping_2
[ 90%] Executing bash command in virtual machine server with timeout 10m
+ ping 192.168.1.1 -c5
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.017 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.033 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.033 ms
64
bytes from 192.168.1.1: icmp_seq=4 ttl=64 time=0.033 ms
64 bytes from 192.168.1.1: icmp_seq=5 ttl=64 time=0.035 ms

--- 192.168.1.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4095ms
rtt min/avg/max/mdev = 0.017/0.030/0.035/
0.007 ms
[ 90%] Taking snapshot test_ping_2 for virtual machine client
[ 90%] Taking snapshot test_ping_2 for virtual machine server
[100%] Test test_ping_2 PASSED in 0h:0m:14s
PROCESSED TOTAL 10 TESTS IN 0h:0m:28s
UP-TO-DATE: 8
RUN SUCCESSFULLY: 2
FAILED: 0
C:\Users\Testo>

Мы видим, что оба наших изменённых теста потеряли целостность, и их пришлось прогонять заново. Это произошло потому, что атрибуты теста также входят в подсчёт целостности кеша.

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

C:\Users\Testo> testo run tests.testo --stop_on_fail --param ISO_DIR C:\iso --assume_yes
UP-TO-DATE TESTS:
server_install_ubuntu
server_prepare
server_install_guest_additions
server_setup_nic
client_install_ubuntu
client_prepare
client_install_guest_additions
client_setup_nic
test_ping_1
test_ping_2
PROCESSED TOTAL 10 TESTS IN 0h:0m:0s
UP-TO-DATE: 10
RUN SUCCESSFULLY: 0
FAILED: 0
C:\Users\Testo>

Что же мы видим? Все тесты закешированы, и ничего не пришлось прогонять. И при этом два последних теста имеют атрибут no_snapshots, то есть у виртуальных машин и флешек не создаются снепшоты гипервизора (в этом кстати можно легко убедиться, посмотрев свойства виртуальных машин).

Почему же так происходит? Давайте разбираться.

Дело в том, что в платформе Testo существуют два типа снепшотов, которые работают одновременно никак не мешают друг другу:

  1. Снепшоты на уровне метаданных. Это различные служебные данные в виде небольших текстовых файликов, которые создаёт Testo для своих целей, и которые участвуют, в том числе, в контроли целостности кеша тестов. Эти снепшоты создаются всегда, и вы не можете на них повлиять. Если вы приглядитесь на вывод последнего прогона тестов, вы можете увидеть, что в выводе всё-равно присутствют надписи Taking snapshot... - это как раз и отражает создание новых метаданных.
  2. Снепшоты гипервизора. Это и есть снепшоты в привычном нам понимании. Эти снепшоты создаются только в том случае, если у теста нет атрибута no_snapshots. Т.к. сейчас мы включили этот атрибут, то снепшоты гипервизора не были созданы.

Если кратко просуммировать вышесказанное, то получится очень важное заключение:

Атрибут no_snapshots не влияет на кешируемость тестов, и к таким тестам применяются точно такие же законы целостности кеша, как и к обычным тестам. Наличие такого атрибута не означает, что тест не будет кешироваться и будет всегда запускаться.

Получается, что мы сэкономили немного места на диске и при этом совершенно ничего не потеряли - ведь снепшоты тестов test_ping_1 и test_ping_2 нам и так никогда бы не пригодились. Отсюда следует ещё одно важное заключение:

Для "листовых" тестов (тестов, не имеющих потомков) можно и даже рекомендуется указывать атрибут no_snapshots, т.к. особой пользы от наличия снепшотов в таких тестах всё равно практически нет.

no_snapshots в промежуточных тестах

Может возникнуть ощущение, что если атрибут no_snapshots экономит место на диске и не влияет на кешируемость тестов, то, может быть, имеет смысл вообще указывать этот атрибут во всех тестах подряд? Такое ощущение будет не совсем верным.

Да, с одной стороны такой атрибут не влияет на кешируемость тестов, но это не значит, что его наличие не будет иметь никаких отрицательных эффектов. Давайте продемонстрируем это на примере и добавим этот атрибут в тест client_install_guest_additions:

[no_snapshots: true]
test client_install_guest_additions: client_prepare {
    client install_guest_additions()
}

Давайте прогоним именно этот тест и ничего больше:

C:\Users\Testo> testo run tests.testo --stop_on_fail --param ISO_DIR C:\iso --assume_yes --test_spec client_install_guest_additions
UP-TO-DATE TESTS:
client_install_ubuntu
client_prepare
TESTS TO RUN:
client_install_guest_additions
[ 67%] Preparing the environment for test client_install_guest_additions
[ 67%] Restoring snapshot client_prepare for virtual machine client
[ 67%] Running test client_install_guest_additions
[ 67%] Calling macro install_guest_additions() in virtual machine client
[ 67%] Plugging dvd C:/iso/testo-guest-additions-hyperv.iso into virtual machine client
[ 67%] Typing "mount /dev/cdrom /media" with interval 30ms in virtual machine client
[ 67%] Pressing key ENTER in virtual machine client
[ 67%] Waiting "mounting read-only" for 1m with interval 1s in virtual machine client
[ 67%] Calling macro exec_bash_command(command="dpkg -i /media/testo-guest-additions.deb", time_to_wait="1m") in virtual machine client
[ 67%] Typing "clear && dpkg -i /media/testo-guest-additions.deb && echo Result is $?" with interval 30ms in virtual machine client
[ 67%] Pressing key ENTER in virtual machine client
[ 67%] Waiting "Result is 0" for 1m with interval 1s in virtual machine client
[ 67%] Calling macro exec_bash_command(command="umount /media", time_to_wait="1m") in virtual machine client
[ 67%] Typing "clear && umount /media && echo Result is $?" with interval 30ms in virtual machine client
[ 67%] Pressing key ENTER in virtual machine client
[ 67%] Waiting "Result is 0" for 1m with interval 1s in virtual machine client
[ 67%] Sleeping in virtual machine client for 2s
[ 67%] Unplugging dvd from virtual machine client
[ 67%] Taking snapshot client_install_guest_additions for virtual machine client
[100%] Test client_install_guest_additions PASSED in 0h:0m:19s
PROCESSED TOTAL 3 TESTS IN 0h:0m:19s
UP-TO-DATE: 2
RUN SUCCESSFULLY: 1
FAILED: 0
C:\Users\Testo>

Убедимся также, что этот тест закеширован, несмотря на no_snapshots: true:

C:\Users\Testo> testo run tests.testo --stop_on_fail --param ISO_DIR C:\iso --assume_yes --test_spec client_install_guest_additions
UP-TO-DATE TESTS:
client_install_ubuntu
client_prepare
client_install_guest_additions
PROCESSED TOTAL 3 TESTS IN 0h:0m:0s
UP-TO-DATE: 3
RUN SUCCESSFULLY: 0
FAILED: 0
C:\Users\Testo>

А теперь попытаемся прогнать тест client_setup_nic, который зависит от client_install_guest_additions:

C:\Users\Testo> testo run tests.testo --stop_on_fail --param ISO_DIR C:\iso --assume_yes --test_spec client_setup_nic
UP-TO-DATE TESTS:
UP-TO-DATE TESTS:
client_install_ubuntu
client_prepare
client_install_guest_additions
TESTS TO RUN:
client_install_guest_additions
client_setup_nic
[ 60%] Preparing the environment for test client_install_guest_additions
[ 60%] Restoring snapshot client_prepare for virtual machine client
[ 60%] Running test client_install_guest_additions
[ 60%] Calling macro install_guest_additions() in virtual machine client
[ 60%] Plugging dvd C:/iso/testo-guest-additions-hyperv.iso into virtual machine client
[ 60%] Typing "mount /dev/cdrom /media" with interval 30ms in virtual machine client
[ 60%] Pressing key ENTER in virtual machine client
[ 60%] Waiting "mounting read-only" for 1m with interval 1s in virtual machine client
[ 60%] Calling macro exec_bash_command(command="dpkg -i /media/testo-guest-additions.deb", time_to_wait="1m") in virtual machine client
[ 60%] Typing "clear && dpkg -i /media/testo-guest-additions.deb && echo Result is $?" with interval 30ms in virtual machine client
[ 60%] Pressing key ENTER in virtual machine client
[ 60%] Waiting "Result is 0" for 1m with interval 1s in virtual machine client
[ 60%] Calling macro exec_bash_command(command="umount /media", time_to_wait="1m") in virtual machine client
[ 60%] Typing "clear && umount /media && echo Result is $?" with interval 30ms in virtual machine client
[ 60%] Pressing key ENTER in virtual machine client
[ 60%] Waiting "Result is 0" for 1m with interval 1s in virtual machine client
[ 60%] Sleeping in virtual machine client for 2s
[ 60%] Unplugging dvd from virtual machine client
[ 80%] Test client_install_guest_additions PASSED in 0h:0m:18s
[ 80%] Preparing the environment for test client_setup_nic
[ 80%] Running test client_setup_nic
[ 80%] Copying C:/Users/Alex/testo-tutorials/hyperv/11 - no_snapshots/./rename_net.sh to virtual machine client to destination /opt/rename_net.sh with timeout 10m
[ 80%] Executing bash command in virtual machine client with timeout 10m
+ chmod +x /opt/rename_net.sh
+ /opt/rename_net.sh 52:54:00:00:00:aa server_side
Renaming success
+ ip a a 192.168.1.2/24 dev server_side
+ ip l s server_side up
+ ip ad
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen
1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,
LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:15:5d:01:25:1f brd ff:ff:ff:ff:ff:ff
inet 192.168.154.93/28 brd 192.168.154.95 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::215:5dff:fe01
:251f/64 scope link
valid_lft forever preferred_lft forever
3: server_side: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 52:54:00:00:00:aa brd ff:ff:ff:ff:ff:ff
inet 192.168.1.2/24 scope gl
obal server_side
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe00:aa/64 scope link tentative
valid_lft forever preferred_lft forever
[ 80%] Taking snapshot client_setup_nic for virtual machine client
[100%] Test client_setup_nic PASSED in 0h:0m:2s
PROCESSED TOTAL 4 TESTS IN 0h:0m:20s
UP-TO-DATE: 3
RUN SUCCESSFULLY: 1
FAILED: 0
C:\Users\Testo>

И мы с вами увидим очень интересную картину: тест client_install_guest_additions одновременно помечен и как UP-TO-DATE и как TEST TO RUN. Давайте разберёмся, почему так происходит.

Когда Testo сканирует дерево тестов чтобы определить, какие тесты необходимо выполнить, каждый тест анализируется отдельно. Т.к. мы хотим запустить тест client_setup_nic, то предварительно анализируются на предмет закешированности все его предки: client_install_ubuntu, client_prepare и client_install_guest_additions. Все эти тесты имеют валидный кеш, поэтому они и помечаются как UP-TO-DATE, что мы и видим.

Затем приходит черед проанализировать закешированность самого теста client_setup_nic. Кеш этого теста недействителен (потому что мы ранее меняли в предыдущем шаге client_install_guest_additions), а значит его необходимо выполнить. Остаётся вопрос - а как его выполнить?

Если бы тест client_install_guest_additions не был бы помечен, как no_snapshots, то мы могли бы откатиться к снепшотам виртуальных машин на момент окончания client_install_guest_additions. Но у этого теста нет снепшотов гипервизора, поэтому и откатиться нам некуда. Возникает вопрос - а как вернуть виртуальную машину client в состояние на момент окончания client_install_guest_additions? В этом случае платформа Testo начинает идти вверх по иерархии тестов в попытке найти хоть один снепшот со снепшотами гипервизора, за который можно было бы "зацепиться". В нашем случае - это тест client_prepare.

В итоге мы откатываемся к снепшоту client_prepare и начинаем заново прогонять тест client_install_guest_additions чтобы вернуть виртуальную машину client в нужное состояние (в состояние на момент окончания теста client_install_guest_additions). Именно поэтому мы видим client_install_guest_additions в списке TESTS TO RUN.

После того, как мы вернули машину в нужное состояние, мы можем, наконец, запустить сам тест client_setup_nic. Этот процесс можно визуализировать примерно так:

Если бы тест client_setup_nic был бы тоже помечен как no_snapshots, то итоговый план выполнения тестов выглядел бы так: client_setup_nic->client_install_guest_additions->client_setup_nic

После этого давайте попробуем запустить все тесты целиком:

C:\Users\Testo> testo run tests.testo --stop_on_fail --param ISO_DIR C:\iso --assume_yes
UP-TO-DATE TESTS:
server_install_ubuntu
server_prepare
server_install_guest_additions
server_setup_nic
client_install_ubuntu
client_prepare
client_install_guest_additions
client_setup_nic
TESTS TO RUN:
test_ping_1
test_ping_2
[ 80%] Preparing the environment for test test_ping_1
[ 80%] Restoring snapshot client_setup_nic for virtual machine client
[ 80%] Restoring snapshot server_setup_nic for virtual machine server
[ 80%] Running test test_ping_1
[ 80%] Executing bash command in virtual machine client with timeout 10m
+ ping 192.168.1.2 -c5
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.017 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.030 ms
64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=0.031 ms
64
bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=0.031 ms
64 bytes from 192.168.1.2: icmp_seq=5 ttl=64 time=0.030 ms

--- 192.168.1.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4081ms
rtt min/avg/max/mdev = 0.017/0.027/0.031/
0.008 ms
[ 80%] Taking snapshot test_ping_1 for virtual machine client
[ 80%] Taking snapshot test_ping_1 for virtual machine server
[ 90%] Test test_ping_1 PASSED in 0h:0m:8s
[ 90%] Preparing the environment for test test_ping_2
[ 90%] Restoring snapshot client_setup_nic for virtual machine client
[ 90%] Restoring snapshot server_setup_nic for virtual machine server
[ 90%] Running test test_ping_2
[ 90%] Executing bash command in virtual machine server with timeout 10m
+ ping 192.168.1.1 -c5
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.018 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.029 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.033 ms
64
bytes from 192.168.1.1: icmp_seq=4 ttl=64 time=0.026 ms
64 bytes from 192.168.1.1: icmp_seq=5 ttl=64 time=0.032 ms

--- 192.168.1.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4091ms
rtt min/avg/max/mdev = 0.018/0.027/0.033/
0.007 ms
[ 90%] Taking snapshot test_ping_2 for virtual machine client
[ 90%] Taking snapshot test_ping_2 for virtual machine server
[100%] Test test_ping_2 PASSED in 0h:0m:8s
PROCESSED TOTAL 10 TESTS IN 0h:0m:17s
UP-TO-DATE: 8
RUN SUCCESSFULLY: 2
FAILED: 0
C:\Users\Testo>

Что же мы видим? Мы видим, что несмотря на то, что наш тест client_install_guest_additions получил атрибут no_snapshots, наше время прогона ЛИСТОВЫХ тестов не пострадало: ведь мы всё еще можем использовать снепшоты от теста client_setup_nic.

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

Попробуйте самостоятельно добавить атрибут no_snapshots в тест server_install_guest_additions и внимательно поизучайте какие тесты в каких случаях будут запускаться.

Теперь давайте рассмотрим ещё один момент, после которого мы сформулируем несколько правил относительно того, где стоит применять no_snapshots, а где не стоит.

no_snapshots в опорных тестах - плохая идея

Перед дальнейшим шагом убедитесь, что тесты client_install_guest_additions, server_install_guest_additions, test_ping_1 и test_ping_2 имеют атрибут no_snapshots, все тесты должны быть прогнаны и закешированы.

При таком раскладе получается, что мы сэкономили довольно много места, и при условии, что мы не будем трогать тесты client_setup_nic и server_setup_nic тесты test_ping_1 и test_ping_2 прогоняются так же быстро, как если бы все тесты имели полноценные снепшоты. Мы достигли определённого баланса - места гораздо меньше, и неудобства от увеличенного времени прогона тестов пока не сильно ощущаются.

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

Давайте добавим no_snapshots в тесты client_setup_nic и server_setup_nic и попробуем прогнать все тесты:

C:\Users\Testo> testo run tests.testo --stop_on_fail --param ISO_DIR C:\iso --assume_yes
UP-TO-DATE TESTS:
server_install_ubuntu
server_prepare
server_install_guest_additions
client_install_ubuntu
client_prepare
client_install_guest_additions
TESTS TO RUN:
server_install_guest_additions
server_setup_nic
client_install_guest_additions
client_setup_nic
test_ping_1
server_setup_nic
client_install_guest_additions
client_setup_nic
test_ping_2
...
C:\Users\Testo>

Посмотрите насколько выросла очередь TESTS TO RUN. Мы видим, что тесты server_install_guest_additions, client_install_guest_additions, server_setup_nic и client_setup_nic планируются к выполнению аж два раза! Давайте проанализируем, почему так происходит:

  1. Нам необходимо выполнить два листовых теста: test_ping_1 и test_ping_2, которые оба полагаются на опорные тесты client_setup_nic и server_setup_nic;
  2. Т.к. тесты client_setup_nic и server_setup_nic теперь не имеют снепшотов гипервизора, платформе Testo ничего не остаётся, кроме как выполнить поиск ближайших тестов, к результатам которых можно откатиться;
  3. Сначала такой поиск происходит для теста test_ping_1, в результате появляется путь выполнения server_install_guest_additions->server_setup_nic->client_install_guest_additions->client_setup_nic, который берет свое начало с момента успешного окончания тестов client_prepare и server_prepare;
  4. Такой же поиск приходится проделать и для теста test_ping_2! Ведь отсутствие снепшотов никто не отменял. В итоге некоторые тесты запланированы к выполнению аж два раза!

В данном случае мы, конечно, ещё сэкономили место на диске, но с другой стороны явно перегнули палку с точки зрения времени выполнения тестов. Наше решение никак нельзя назвать эффективным: неудобства значительно превысили пользу.

В связи с этим возникает вопрос, а какое же распредение атрибутов no_snapshots в тестах можно назвать оптимальным (в большинстве случаев)? Мы предлагаем такой алгоритм:

  1. Все листовые (не имеющие потомков) тесты можно безболезненно помечать атрибутом no_snapshots, поэтому следует это сделать;
  2. Промежуточные тесты следует помечать атрибутом no_snapshots, если эти тесты не являются опорными, то есть если к результатам их выполнения не будет происходить откатов (по крайней мере часто);
  3. Тесты, имеющие несколько потомков, не следует помечать атрибутом no_snapshots.

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

  1. Тесты test_ping_1 и test_ping_2 являются листовыми, поэтому им следует назначить атрибут no_snapshots;
  2. Тесты client_setup_nic и server_setup_nic явно не должны иметь атрибут no_snapshots, т.к. от этих тестов зависит более одного теста;
  3. Тесты client_install_guest_additions и server_install_guest_additions следует пометить атрибутом no_snapshots в том случае, если тесты client_setup_nic и server_setup_nic будут закешированы большую часть времени. Если эти тесты будут постоянно терять целостность кеша, то лучше оставить тесты client_install_guest_additions и server_install_guest_additions в первоначальном виде;
  4. Тесты install_ubuntu достаточно трудоемкие и выполняются долго. Их можно оставить в изначальном виде, даже с учётом, что к ним редко будет происходить откат, просто чтобы сэкономить себе время на лишней установке ОС в том случае в случае непредвиденных обстоятельств;
  5. Тесты prepare можно пометить атрибутом no_snapshots без особых проблем и рисков.

Проведя такую оптимизацию, мы достигнем неплохого баланса между экономией места на диске и скоростью прогона тестов. Многие подготовительные тесты имеют атрибут no_snapshots, потому что мы предполагаем, что подготовка будет происходить редко (в идеале - ровно один раз), после чего мы фиксируем итоги подготовки в тестах client_setup_nic и server_setup_nic. Производные сложные тесты, котрые предположительно будут прогоняться часто, всегда смогут положиться на результат тестов prepare, поэтому время их прогона не пострадает.

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

Итоги

Механизм no_snapshots в языке Testo-lang позволяет экономить место на диске, потенциально в ущерб времени прогона тестов. Впрочем, если грамотно распоряжаться этим механизмом, то потеря времени на прогонах тестов может оказаться очень несущественной или вовсе отсутствовать. Поэтому при достижении определенного количества тестов определенно следует остановиться и подумать, какие тесты будут выполняться часто, а какие редко - и в каких тестах можно безболезненно поставить атрибут no_snapshots.

Готовые скрипты можно найти здесь