[Тестирование IT-систем, Виртуализация, Разработка под Linux] Автоматизация системных тестов на базе QEMU (Часть 1/2)

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
23-Сен-2020 14:30

Эта статья посвящена автоматизации системного (end-to-end) тестирования с использованием виртуальных машин. В статье рассматриваются такие вопросы, как автоматизация развертывания и настройки виртуальных стендов, а также автоматизация запуска процессов внутри виртуальных машин с последующим контролем полученных результатов. В конце статьи мы получим пусть неидеальный (к этому мы ещё вернемся), но простой и понятный скрипт, с помощью которого вы сможете запускать системные тесты одной кнопкой, даже не имея у себя на компьютере ни одной виртуальной машины.
Статья предполагает наличие следующих навыков у читателя:
  • Уверенное пользование ОС семейства Linux;
  • Базовое понимание принципов виртуализации;
  • Знакомство с гипервизором QEMU и графическим клиентом virt-manager

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

Дисклеймер

SPL
Эта статья носит исключительно ознакомительный характер. Выбор инструментария обусловлен исключительно простотой ознакомления и общей доступностью. Автор осведомлен о наличии большого количества коммерческих и открытых решений по автоматизации тестирования (в т.ч. системного). Эту статью стоит расценивать как небольшое введение в курс системных тестов, где Вы сможете познакомиться с основными принципами системных тестов, а также увидите пример того, как их можно автоматизировать даже с использованием простых, общеизвестных и доступных решений.
Эта статья НЕ ставит себе целью рассказать Вам о продакшн-системах прогона системных тестов, НЕ ставит целью никоим образом преуменьшить значимость существующих решений, и НЕ ставит целью разжечь какой-либо холивар.

Что такое системное тестирование
Системное тестирование (или, как его ещё иногда называют, end-to-end тестирование) — это тестирование программы (или даже целой системы) с учётом окружения, в которой программе придётся работать. Помимо системного тестирования также существует unit-тестирование (тестирование конкретных функций и модулей), интеграционное тестирование (тестирование больших самостоятельных компонент программы или программы целиком) и ещё много других видов тестирования. Но почему же нас может заинтересовать именно системное?
Наверное, у всех бывали ситуации, когда у разработчика всё работает, а у заказчика вечно что-то ломается. Так вот, системное тестирование хорошо тем, что программа проверяется именно в том виде, в котором её увидит конечный потребитель. Системные тесты позволяют воспроизвести некоторое окружение и проверить, как программа с этим окружение справляется. Вот некоторые примеры настраиваемого окружения:
  • Вид и версия ОС;
  • Разные настройки ОС (например, в области разграничения прав доступа);
  • Наличие или отсутствие определенных программ в ОС (в т.ч. драйверов);
  • Наличие сети и других компьютеров в ней;
  • Количество оперативной памяти или определённая архитектура процессора.

Довольно часто разработчики и тестировщики просто не знают, как подступиться к задаче автоматизации системных тестов, либо им кажется, что затраты на автоматизацию не окупят себя. Этой статьёй я хотел бы продемонстрировать, что автоматизация системных тестов не настолько сложна, как это может показаться, и я надеюсь, что она послужит для кого-то хорошей отправной точкой.
Почему именно виртуалки?
Может возникнуть вопрос, а зачем использовать именно виртуалки? Ведь для воспроизведения окружения для программы можно использовать и контейнеры (например, если Вас интересует поведение программы в связке с другими программами). И действительно, для контейнеров существует несколько решений по автоматизации тестов. Однако, существуют классы сценариев, которые нельзя протестировать с помощью контейнеров:
  • Нельзя протестировать приложения не под Linux, а также гетерогенные стенды из нескольких машин;
  • Нельзя протестировать GUI (или даже псевдо-GUI);
  • Нельзя протестировать драйвера и работу с оборудованием.

Автоматизация пунктов 1 и 2 потребует от нас существенной подготовки, поэтому оставим их для одной из следующих статей. А вот для пункта 3 вполне хватит той информации, которую Вы узнаете из этой статьи. В этой статье (во второй её части) мы как раз продемонстрируем автоматизацию тестирования приложения, которое взаимодействует с оборудованием напрямую, в обход операционной системы.
Какой выбрать гипервизор?
В целом, схема, которую мы предложим в этой статье, применима к любому гипервизору. Но мы воспользуемся QEMU, потому что он позволит нам получить работающий прототип затратив при этом минимальные усилия и время. Основные принципы и идеи из этой статьи, при желании, можно реализовать и на других гипервизорах (например, на VirtualBox).
Какие действия мы хотим автоматизировать?
Для того, чтобы автоматизировать системные тесты, нам нужно решить как минимум следующие вопросы:
  • Как автоматически создать виртуалку;
  • Как "раскатать" и настроить ОС;
  • Как научиться управлять виртуалкой после её установки. В частности, нас интересует, как запускать процессы внутри виртуалки и копировать на неё файлы.

Заметка про тестирование методом чёрного ящика

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

Что ж, погнали!
Создаем виртуалку
Конечно, я думаю все пробовали создавать виртуальные машины вручную. Для этого в графическом интерфейсе рисуются всякие диалоговые окна, где надо выбрать конфигурацию, диски, сетевые адаптеры и прочее прочее. Так вот, для гипервизора QEMU всё это можно сделать и в консольном режиме с помощью утилиты virt-install. Давайте посмотрим как будет выглядеть простейшее создание виртуальной машины с помощью этой утилиты:
virt-install \
    --name my_super_vm \
    --ram 1024 \
    --disk my_super_vm.qcow2,size=8 \
    --cdrom /path/to/ubuntu_server.iso

Вот такой простой командой мы можем создать виртуальную машину с именем my_super_vm, 1024 Мегабайтами оперативной памяти, новым диском my_super_vm.qcow2 размером 8 Гигабайт. В виртуальном CD-приводе такой машины будет смонтирован установочный образ ubuntu_server.iso (конечно, этот образ надо предварительно скачать), который, как обычно, нужен для установки ОС на свежесозданную виртуалку.
Впрочем, если Вы выполните такую команду, то увидите как у вас запустилось графическое окно с VNC-клиентом, который подключается к виртуальной консоли виртуальной машины. В этом окне Вы увидите начало установки Ubuntu Server 18.04. Конечно, реальный человек бы смог протыкать несколько клавиш на клавиатуре и установить Ubuntu Server, но мы лишены такой роскоши, ведь мы работаем исключительно консольными командами.
Но наше положение не такое уж и безвыходное, ведь установить ОС на виртуальную машину можно и по-другому.
Создаём диск из шаблона
Тут следует сделать небольшую ремарку и обозначить (на всякий случай) разницу между виртуальной машиной и виртуальным диском. Виртуальная машина (как и настоящая физическая) может иметь один диск, или несколько дисков, или вообще не иметь дисков. Виртуальные диски можно подключать и отключать от виртуальных машин. Это совершенно разные, независимые сущности. Поэтому, например, в гипервизоре VirtualBox за создание виртуального диска отвечает отдельный мастер.
Вызов команды virt-install, приведённый выше, выполняет сразу два действия: он создаёт одновременно и машину и диск. Из-за может сложиться неверное впечатление, что эти сущности неотделимы друг от друга.
Но на самом деле никто не мешает нам отдельно создать виртуальный диск, а затем подключить его к виртуальной машине. Вы можете подготовить свой образ диска, но в этой статье мы для простоты воспользуемся уже готовым. Проект libguestfs поддерживает в свободном доступе целый репозиторий таких образов. Кроме того, в рамках этого же проекта существует утилита virt-builder, которая позволяет легко скачать нужный образ диска и доработать его "напильником" под наши нужды.

Несколько слов про проект libguestfs и почему стоит обратить на него внимание

SPL
В первую очередь Libguestfs — это программная библиотека, которая позволяет легко манипулировать содержимым образом виртуальных дисков. Под манипуляцией подразумеваются такие операции как форматирование дисков, копирование файлов на диск и из него и так далее. Кроме того, в рамках проекта реализован целый набор утилит на все случаи жизни, которые используют различные возможности библиотеки. Среди них есть очень простые утилиты (в стиле Unix-way), которые выполняют всего одно действие, например virt-copy-in. С другой стороны есть команды-комбайны, которые умеют много всего и сразу, такие как virt-builder.

Итак, что же нам позволяет сделать virt-builder? С помощью этой утилиты мы можем на лету сформировать уже "подготовленный" диск с уже установленной Ubuntu Server. Сделать это можно так:
virt-builder ubuntu-18.04 \
    --format qcow2 \
    --output my_super_disk.qcow2

Что же здесь происходит? Мы говорим, что хотели бы создать диск в формате qcow2 (можно выбрать другой) и использовать в качестве основы шаблон ubuntu-18.04, который хранится в репозитории шаблонов в проекте libguestfs. Команда virt-builder скачает этот шаблон из Интернета и затем на его основе сгенерирует итоговый диск, в котором теперь будет установлен Ubuntu Server!

Кешируемость шаблонов

SPL
Приятной особенностью утилиты virt-builder является то, что шаблон диска кешируется после первого скачивания, поэтому последующие создания дисков будут проходить гораздо быстрее

Ну а теперь нам остаётся создать виртуальную машину, и указать в качестве диска (импортировать) подготовленный образ my_super_disk.qcow2:
virt-install \
    --import \
    --name my_super_vm \
    --ram 1024 \
    --disk my_super_vm.qcow2

Обратите внимание, что исчез параметр --cdrom, он нам больше не нужен. Также добавился параметр --import. Этот параметр указывает, что виртуалка будет загружаться не с cdrom, а с виртуального диска (то есть это влияет на Bios Boot Options виртуальной машины). Ну а т.к. диск у нас теперь содержит установленный Ubuntu Server, такая загрузка пройдёт успешно.
Попробуйте выполнить эти команды и создать таким образом виртуальную машину my_super_vm. Вы сможете убедиться, что Ubuntu Server 18.04 действительно уже установлен и успешно загружается.
Соединяем сетью виртуалку и хост
Вот так вот мы практически незаметно научились автоматически устанавливать виртуалки и даже раскатывать на них готовую ОС. Теперь настало время поговорить о канале управления виртуалкой после её установки и настройки.
Ещё раз хотелось бы отметить, что эталоном автоматизации системных тестов должна выступать автоматизация действий человека: как он нажимает на клавиши, кликает мышкой и совершает другие действия. И ещё раз напомним, что это очень сложный (хоть и правильный) путь. Мы же воспользуемся тем фактом, что нам не требуется взаимодействовать с GUI, нам пока вполне хватит возможности выполнения произвольных bash-команд на гостевой системе.
Для этого существуют разные подходы, но мы с Вами в этой статье рассмотрим только самый простой и, в некоторой степени, топорный вариант: установка SSH-соединения между хостом и виртуалкой.

Альтернативные подходы

SPL
Не всегда канал управления виртуалкой через ssh является приемлемым вариантом. Такое бывает, если Вы тестируете приложение, которое каким-то образом завязано на сетевую подсистему. Например, в случае если вы как раз таки и разрабатываете ssh-сервер. Вы же не хотите, чтобы Ваши тесты полагались на работоспособность ещё неготовой программы? Либо Вы хотите проверить, как поведёт себя Ваша программа на виртуалке, где вообще нет сетевых интерфейсов.
В качестве альтернативы можно управлять гостевой системой через последовательный порт. При этом последовательный порт образует как бы трубу (pipe), проложенную между хостом и виртуалкой. Со стороны Linux-хоста эта труба видна как unix-socket, а со стороны гостевой системы — как последовательное устройство. Всё, что отправляется в один конец трубы, тут же появляется из другого. Соответственно, как и в случае с ssh, на гостевой системе должен работать некий сервер, ожидающий получения данных из последовательного порта. Примером такого сервера может служить qemu-guest-agent.
В случае, если Вы работаете с гипервизором Hyper-V, то помимо последовательного порта можно попробовать воспользоваться механизмом KVP (Key-Value Pairs) или Hyper-V Sockets.

Для этого нам потребуется сделать несколько манипуляций:
  • Создать виртуальную сеть между хостом и виртуалкой;
  • Настроить сетевой интерфейс на виртуалке;
  • Задать пароль от пользователя root на виртуалке;
  • Подредактировать SSH-настройке на виртуалке, чтобы можно было соединяться по SSH от имени рута с помощью пароля.

По поводу ssh без пароля

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

Для начала займемся созданием виртальной сети между хостом и виртуалкой. Для этого нам надо сделать две простых операции:
  • Создать виртуальную сеть;
  • Подключить виртуалку к этой сети (хост уже будет подключен к сети по-умолчанию).

Итак, поехали.
Для создания виртуальной сети мы воспользуемся ещё одной утилитой virsh, которая работает поверх ещё одной замечательной библиотеки libvirt.

Несколько слов про libvirt

SPL
Libvirt — это, опять же, программная библиотека, предназначенная для управления гипервизорами. Проект libvirt ставит перед собой задачу объять необъятное — сделать интерфейс управления, подходящий сразу для всех гипервизоров. Задача благая, но уж слишком амбициозная. На данный момент гипервизоры, отличные от QEMU, поддерживаются довольно слабо. Однако, если Вам требуется сделать что-то именно с QEMU, то проект libvirt и утилита virsh, входящая в его состав, являются самым быстрым и удобным вариантом.

В libvirt для создания различных виртуальных объектов (дисков, сетей, виртуалок) используются XML-схемы. XML-схема для создания сети выглядит примерно так:
<network>
    <name>net_for_ssh</name>
    <bridge name='net_for_ssh'/>
    <ip address='192.168.100.1' netmask='255.255.255.0'/>
</network>

Где 192.168.100.1 — это адрес, присваиваемый сетевому интерфейсу, который будет автоматически создан на хосте и ассоциирован с новой виртуальной сетью.
Для того, чтобы создать сеть — необходимо передать путь к файлу с xml схемой сети в следующую команду:
virsh net-define net_for_ssh.xml

После создания сеть создаётся в выключенном состоянии, поэтому её ещё надо включить:
virsh net-start net_for_ssh

Теперь надо подключить виртуалку к свежесозданной сети. Для этого при создании виртуалки необходимо добавить параметр --network:
virt-install \
    --import \
    --name my_super_vm \
    --ram 1024 \
    --disk my_super_vm.qcow2 \
    --network network=net_for_ssh \
    --noautoconsole

Обратите также внимание на аргумент --noautoconsole, который отключает автоматическое подключение к консоли виртуалки через VNC-клиент (впрочем, если Вам всё-равно хочется зайти посмотреть на виртуалку, Вы можете воспользоваться virt-manager).
Соединение готово, но пропинговать с хоста нашу виртуалку мы всё ещё не можем: сетевой интерфейс пока не настроен.
Настройка сетевого интерфейса на виртуалке
Как же мы будем настраивать интерфейс внутри виртуалки, если мы пока не можем выполнять на ней никаких команд (SSH-канал ведь ещё не настроен)? В этом нам снова поможет библиотека libguestfs и утилита virt-builder.
Дело в том, эта библиотека позволяет, в числе прочего, копировать файлы на виртуальный диск. Как мы знаем, в Ubuntu Server 18.04 за сетевые настройки отвечает netplan, и для того, чтобы сконфигурировать сетевой интерфейс, нам достаточно подложить специальный .yaml файлик в каталог /etc/netplan. И сделать это можно с помощью той же утилиты virt-builder с помощью параметра --copy-in:

Файл с настройками сетевого интерфейса netcfg_ssh.yaml

SPL
network:
  version: 2
  renderer: networkd
  ethernets:
    ens3:
      addresses:
        - 192.168.100.2/24

virt-builder ubuntu-18.04 \
    --format qcow2 \
    --output my_super_disk.qcow2 \
    --copy-in netcfg_ssh.yaml:/etc/netplan/

И теперь при создании виртуального диска после раскатывания Ubuntu Server 18.04 из шаблона virt-builder дополнительно скопирует файл netcfg_ssh.yaml и подложит его в директорию /etc/netplan/ на файловой системе виртуального диска.
Теперь виртуальная машина должна пинговаться, проверим:
ping 192.168.100.2 -c5

Почти всё сделали, осталось лишь настроить SSH.
Настраиваем SSH на виртуалке
Для создания канала управления виртуалкой осталось сделать совсем чуть чуть:
  • Прописать пароль для root-пользователя в виртуалке;
  • Создать ключи на виртуалке для SSH-сервера чтобы он стартовал без ругани;
  • Прописать в конфиг SSH-сервера возможность подключаться от имени рута с использованием пароля.

Начнём с пароля для root. Здесь нас снова выручает virt-builder, который, на самом деле, позволяет Вам делать с виртуальным диском поистине удивительные вещи, одна из которых — прописать пароль для root-пользоавтеля:
virt-builder ubuntu-18.04 \
    --format qcow2 \
    --output my_super_disk.qcow2 \
    --root-password password:1111 \
    --copy-in netcfg_ssh.yaml:/etc/netplan/

Теперь осталось сгенерировать ключи для SSH и подправить конфиг. Для этого нам надо всего-то надо выполнить пару команд:
ssh-keygen -A
sed -i "s/.*PermitRootLogin.*/PermitRootLogin yes/g" /etc/ssh/sshd_config

Вот только вопрос, а как же нам выполнить эти команды? Ведь virt-builder работает только с образами дисков, никаких виртуальных машин на этом этапе не создаётся. Однако, уvirt-builder есть ещё пара козырей в рукаве. Он позволяет запускать программы гостевой системы без запуска собственно гостевой системы с помощью параметра --run-command:
virt-builder ubuntu-18.04 \
    --format qcow2 \
    --output my_super_disk.qcow2 \
    --root-password password:1111 \
    --run-command "ssh-keygen -A" \
    --run-command "sed -i "s/.*PermitRootLogin.*/PermitRootLogin yes/g" /etc/ssh/sshd_config" \
    --copy-in netcfg_ssh.yaml:/etc/netplan/

А как это работает?

SPL
Хороший вопрос. Документация libguestfs ничего не говорит нам о деталях реализации этого механизма, а исходники довольно запутаны. Но похоже, что здесь используется User Space Linux Kernel. Это не контейнеры, но очень на них похоже. В любом случае можно сделать следующие выводы:
  • в параметре --run-command можно смело вызвать любой бинарник, который есть на диске гостевой системы
  • при этом можно смело пользоваться сетью, например — устанавливать пакеты с помощью apt install

И теперь… всё! Канал настроен! Можно было бы даже попробовать подключиться, если бы не одно "но". После выполнения команды virt-install виртуалка только только начинает включаться. Между моментом включения виртуалки и запуском на ней ssh сервера может пройти несколько секунд. Поэтому нам потребуется организовать незатейливый механизм ожидания ssh сервера:
#!/bin/bash
SSH_CMD="sshpass -p 1111 ssh -o StrictHostKeyChecking=no"
while ! $SSH_CMD root@192.168.100.2 echo Hello world from my super vm!
do
    echo "Waiting for client VM ..."
    sleep 1
done

Также, мне пришлось добавить параметр -o StrictHostKeyChecking=no к команде ssh для того, чтобы запрос на добавление сервера в список доверенных серверов не блокировал выполнение скрипта. Так же мне пришлось воспользоваться утилитой sshpass для того, чтобы автоматизировать ввод пароля.
Итоги
В первой части статьи мы пока не написали ни одного реального системного теста, зато познакомились с серьёзным арсеналом утилит по работе с виртуальными машинами, научились автоматически создавать виртуалки, раскатывать на них ОС, настраивать их, а также налаживать канал управления по SSH. С этим запасом знаний мы теперь можем смело переходить к самому главному и интересному: как же, всё-таки, автоматизировать системные тесты на виртуалках.
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_testirovanie_itsistem (Тестирование IT-систем), #_virtualizatsija (Виртуализация), #_razrabotka_pod_linux (Разработка под Linux), #_avtomatizatsija_testirovanija (автоматизация тестирования), #_qa_automation, #_qemukvm, #_libvirt, #_libguestfs, #_ssh, #_testirovanie_itsistem (
Тестирование IT-систем
)
, #_virtualizatsija (
Виртуализация
)
, #_razrabotka_pod_linux (
Разработка под Linux
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 08:00
Часовой пояс: UTC + 5