Skip to content

Commit

Permalink
ovirt-img: command testing
Browse files Browse the repository at this point in the history
Add the required testing infrastructure to test
ovirt-img command with a local setup.

Engine configuration needs to be set in a configuration
file, and then the tests will read this configuration
and run normally through tox.

The test are run through a new tox environment, namely
client (as it tests commands contained in the client
folder):
tox -e client

It will read the configuration in the default location
run the tests in the test/client folder.
Configuration location can be set through an env
variable:
CLIENT_TEST_CONF=/path/to/test.conf tox -e client

Currently, it only tests upload and download commands,
with different formats and comparing resulting images.
Example:

$ CLIENT_TEST_CONF=~/.config/ovirt-img.conf tox -e client --
--log-cli-level=debug

collected 2 items

test/client/upload_download_test.py::test_upload_download[raw] Formatting '/var/tmp/imageio-tests/test_upload_download_raw_0/image.raw', fmt=raw size=10737418240

12:26:37,374 INFO    (MainThread) [test] Upload raw image to SD nfs-01
[ 100% ] 10.00 GiB, 19.08 s, 536.59 MiB/s | upload completed
12:26:56,595 INFO    (MainThread) [test] Download image d27c0e2f-35d1-4106-96e6-215022e022bf
[ 100% ] 10.00 GiB, 2.47 s, 4.05 GiB/s | download completed
12:26:59,202 INFO    (MainThread) [test] Comparing images
12:26:59,539 INFO    (MainThread) [test] Upload raw image to SD iscsi-01
[ 100% ] 10.00 GiB, 24.73 s, 414.15 MiB/s | upload completed
12:27:24,405 INFO    (MainThread) [test] Download image a3b48896-33bc-4f62-b3af-159b56686a29
[ 100% ] 10.00 GiB, 4.73 s, 2.11 GiB/s | download completed
12:27:29,277 INFO    (MainThread) [test] Comparing images
PASSED
test/client/upload_download_test.py::test_upload_download[qcow2] Formatting '/var/tmp/imageio-tests/test_upload_download_qcow2_0/image.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=10737418240 lazy_refcounts=off refcount_bits=16

12:27:30,103 INFO    (MainThread) [test] Upload qcow2 image to SD nfs-01
[ 100% ] 10.00 GiB, 11.92 s, 858.81 MiB/s | upload completed
12:27:42,175 INFO    (MainThread) [test] Download image 9cb8da7a-6169-4020-8233-9f20aeeef56e
[ 100% ] 10.00 GiB, 2.44 s, 4.09 GiB/s | download completed
12:27:44,765 INFO    (MainThread) [test] Comparing images
12:27:45,956 INFO    (MainThread) [test] Upload qcow2 image to SD iscsi-01
[ 100% ] 10.00 GiB, 29.13 s, 351.49 MiB/s | upload completed
12:28:15,236 INFO    (MainThread) [test] Download image ae41f54d-0345-40ac-bf40-197430c671f5
[ 100% ] 10.00 GiB, 2.92 s, 3.43 GiB/s | download completed
12:28:18,290 INFO    (MainThread) [test] Comparing images
PASSED

Fixes: oVirt#124
Signed-off-by: Albert Esteve <[email protected]>
  • Loading branch information
aesteve-rh committed Oct 6, 2022
1 parent ffa7337 commit b05c430
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 3 deletions.
22 changes: 22 additions & 0 deletions test/client/client_tests.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Example configuration for client tests.
# Adapt these settings to your local engine setup and then run:
# tox -e client
# This configuration can be copied to a different location and used as
# CLIENT_TEST_CONF=/path/to/test.conf tox -e client

# Common parameters must be all kept, and are used by all tests
common:
engine_url: https://engine.com
username: admin@internal
password: password
cafile: /path/to/cert.pem

tests:
# Image upload and download test. Different formats are tested.
# Image and disk contents are compared.
upload-download:
# Set local storage domain names to test.
# At least one block and one file storage domain shall be tested.
storage-domains:
- nfs1
- scsi1
35 changes: 35 additions & 0 deletions test/client/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# ovirt-imageio
# Copyright (C) 2022 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

import logging
import os
import yaml

import pytest


log = logging.getLogger("test")


@pytest.fixture
def config(tmpdir):
with open(os.environ['CLIENT_TEST_CONF'], encoding='utf-8') as fstream:
try:
conf = yaml.safe_load(fstream)
except yaml.YAMLError as exc:
log.error("Invalid YAML format: %s", exc)
raise

conf_file = os.path.join(tmpdir, 'ovirt-img.conf')
os.environ['XDG_CONFIG_HOME'] = str(tmpdir)
with open(conf_file, "w+", encoding="utf-8") as fstream:
fstream.write("[test]\n")
for k, v in conf["common"].items():
fstream.write(f"{k} = {v}\n")

yield conf
103 changes: 103 additions & 0 deletions test/client/upload_download_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# ovirt-imageio
# Copyright (C) 2022 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

import contextlib
import logging
import os
import uuid
import subprocess
import sys

import pytest
import ovirtsdk4 as sdk

from ovirt_imageio._internal import qemu_img


OS_VERSION = 'fedora-36'

log = logging.getLogger("test")


class ClientError(Exception):
pass


def create_disk(path, fmt, os_version=OS_VERSION):
env = os.environ.copy()
env['LIBGUESTFS_BACKEND'] = 'direct'
cmd = ['virt-builder', os_version, '--format', fmt, '-o', path]
subprocess.check_call(cmd, env=env)


def run_upload_disk(storage_domain, image, disk_id=None, log_level=None):
# Make sure it runs with the same tox environment executable
cmd = [sys.executable, './ovirt-img', 'upload-disk', '-c', 'test']
cmd.extend(['-s', storage_domain])
if log_level:
cmd.extend(['--log-level', log_level])
if disk_id:
cmd.extend(['--disk-id', disk_id])
cmd.append(image)
try:
subprocess.run(cmd, check=True)
except subprocess.CalledProcessError as exc:
raise ClientError(f'Client Error: {exc}') from exc


def run_download_disk(disk_id, image, log_level=None):
# Make sure it runs with the same tox environment executable
cmd = [sys.executable, './ovirt-img', 'download-disk', '-c', 'test']
if log_level:
cmd.extend(['--log-level', log_level])
cmd.extend([disk_id, image])
try:
subprocess.run(cmd, check=True)
except subprocess.CalledProcessError as exc:
raise ClientError(f'Client Error: {exc}') from exc


def remove_disk(conf, sd_name, disk_id):
connection = sdk.Connection(
url=f'{conf["engine_url"]}/ovirt-engine/api',
username=conf["username"],
password=conf["password"],
ca_file=conf["cafile"]
)
with contextlib.closing(connection):
sd_service = connection.system_service().storage_domains_service()
found_sd = sd_service.list(search=f'name={sd_name}')
if not found_sd:
raise RuntimeError(f"Couldn't find storage domain {sd_name}")

sd = found_sd[0]
sd_service = sd_service.storage_domain_service(sd.id)
sd_service.disks_service().disk_service(disk_id).remove()


@pytest.mark.parametrize("fmt", ["raw", "qcow2"])
def test_upload_download(config, tmpdir, fmt):
image = os.path.join(tmpdir, f'image.{fmt}')
create_disk(image, fmt)
test_config = config["tests"]["upload-download"]
for sd_name in test_config.get("storage-domains", []):
disk_id = str(uuid.uuid4())
try:
log.info("Upload %s image to SD %s", fmt, sd_name)
run_upload_disk(sd_name, image, disk_id)
down_img = os.path.join(tmpdir, f'downloaded.{fmt}')
log.info("Download image %s", disk_id)
run_download_disk(disk_id, down_img)
log.info("Comparing images")
qemu_img.compare(image, down_img)
except ClientError as exc:
log.error("%s", exc)
# Skip disk cleanup if client failed
return
finally:
remove_disk(config["common"], sd_name, disk_id)
17 changes: 14 additions & 3 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# and then run "tox" from this directory.

[tox]
envlist = flake8,test-{py36,py38,py39,py310},bench-{py36,py38,py39,py310}
envlist = flake8,test-{py36,py38,py39,py310},bench-{py36,py38,py39,py310},client
skip_missing_interpreters = True
whitelist_externals =
ip
Expand All @@ -25,8 +25,19 @@ commands_pre =
/usr/bin/python3 setup.py build_ext --build-lib .
python -c 'from test import testutil; print("ipv6 supported: %s" % testutil.ipv6_enabled())'
commands =
test: pytest -m 'not benchmark' --cov=ovirt_imageio --durations=10 {posargs}
bench: pytest -m 'benchmark' -vs {posargs}
test: pytest -m 'not benchmark' --ignore=test/client --cov=ovirt_imageio --durations=10 {posargs}
bench: pytest -m 'benchmark' -vs --ignore=test/client {posargs}

[testenv:client]
setenv =
CLIENT_TEST_CONF = {env:CLIENT_TEST_CONF:{toxinidir}/test/client/client_tests.conf}
deps =
pytest
pytest-timeout
pyyaml
ovirt-engine-sdk-python
commands =
pytest -vs --timeout 200 {posargs} test/client

[testenv:flake8]
sitepackages = False
Expand Down

0 comments on commit b05c430

Please sign in to comment.