Francesco Romani has uploaded a new change for review.
Change subject: tests: containers: add testsuite
......................................................................
tests: containers: add testsuite
Change-Id: I27ba3cecbd71b7bbba94992d6bc63ca29333e313
WIP: more tests are being ported
Signed-off-by: Francesco Romani <fromani(a)redhat.com>
---
M configure.ac
M tests/Makefile.am
A tests/containers/Makefile.am
A tests/containers/__init__.py
A tests/containers/cgroups_test.py
A tests/containers/conttestlib.py
A tests/containers/data/bridge_down.xml
A tests/containers/data/bridge_no_source.xml
A tests/containers/data/disk_dev.xml
A tests/containers/data/disk_file_malformed.xml
A tests/containers/data/full_dom.xml
A tests/containers/data/metadata_drive_map.xml
A tests/containers/data/minimal_dom.xml
A tests/containers/data/only_disk.xml
A tests/containers/data/only_mem.xml
A tests/containers/errors_test.py
A tests/containers/fake/bin/docker
A tests/containers/fake/bin/rkt
A tests/containers/fake/bin/systemctl
A tests/containers/fake/bin/systemd-run
A tests/containers/fake/cgroups.tgz
A tests/containers/fs_test.py
A tests/containers/monkey.py
A tests/containers/xmlfile_test.py
24 files changed, 1,083 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/78/60678/1
diff --git a/configure.ac b/configure.ac
index c1dbba5..1087766 100644
--- a/configure.ac
+++ b/configure.ac
@@ -428,6 +428,7 @@
lib/vdsm/virt/containers/runtimes/Makefile
tests/Makefile
tests/common/Makefile
+ tests/containers/Makefile
tests/cpuinfo/Makefile
tests/functional/Makefile
tests/devices/Makefile
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 96c66b7..64e768d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -22,6 +22,7 @@
SUBDIRS = \
common \
+ containers \
cpuinfo \
functional \
devices \
@@ -30,6 +31,8 @@
$(NULL)
common_modules = common/*_test.py
+
+containers_modules = containers/*_test.py
device_modules = \
devices/parsing/complex_vm_tests.py \
@@ -360,6 +363,7 @@
./makecert.sh
run_modules = $(test_modules)
+run_modules += $(containers_modules)
run_modules += $(network_modules)
run_modules += $(device_modules)
run_modules += $(common_modules)
diff --git a/tests/containers/Makefile.am b/tests/containers/Makefile.am
new file mode 100644
index 0000000..afeca74
--- /dev/null
+++ b/tests/containers/Makefile.am
@@ -0,0 +1,31 @@
+#
+# Copyright 2016 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.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+vdsmcontainerstestsdir = ${vdsmtestsdir}/containers
+
+dist_vdsmcontainerstests_PYTHON = \
+ __init__.py \
+ *_test.py \
+ conttestlib.py \
+ $(NULL)
+
+dist_vdsmcontainerstests_DATA = \
+ $(NULL)
+
diff --git a/tests/containers/__init__.py b/tests/containers/__init__.py
new file mode 100644
index 0000000..44b8a6b
--- /dev/null
+++ b/tests/containers/__init__.py
@@ -0,0 +1,19 @@
+#
+# Copyright 2015-2016 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
diff --git a/tests/containers/cgroups_test.py b/tests/containers/cgroups_test.py
new file mode 100644
index 0000000..49835d0
--- /dev/null
+++ b/tests/containers/cgroups_test.py
@@ -0,0 +1,69 @@
+#
+# Copyright 2015-2016 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+from __future__ import absolute_import
+
+import vdsm.virt.containers.metrics.cgroups
+
+from . import conttestlib
+
+
+class CgroupTests(conttestlib.CgroupTestCase):
+
+ def test_empty_cgroups(self):
+ mon = vdsm.virt.containers.metrics.cgroups.Monitorable(self.pid)
+ self.assertEquals(mon.cgroups, ())
+
+ def test_empty_cpuacct(self):
+ mon = vdsm.virt.containers.metrics.cgroups.Monitorable(self.pid)
+ self.assertIs(mon.cpuacct, None)
+
+ def test_empty_memory(self):
+ mon = vdsm.virt.containers.metrics.cgroups.Monitorable(self.pid)
+ self.assertIs(mon.memory, None)
+
+ def test_empty_blkio(self):
+ mon = vdsm.virt.containers.metrics.cgroups.Monitorable(self.pid)
+ self.assertIs(mon.blkio, None)
+
+ def test_from_pid(self):
+ mon = vdsm.virt.containers.metrics.cgroups.Monitorable.from_pid(
+ self.pid
+ )
+ self.assertTrue(mon.cgroups)
+
+ def test_pid_matches(self):
+ mon = vdsm.virt.containers.metrics.cgroups.Monitorable(self.pid)
+ self.assertEquals(mon.pid, self.pid)
+
+ def test_setup(self):
+ mon = vdsm.virt.containers.metrics.cgroups.Monitorable(self.pid)
+ mon.setup()
+ self.assertTrue(mon.cgroups)
+
+ def test_cgroups_found(self):
+ mon = vdsm.virt.containers.metrics.cgroups.Monitorable(self.pid)
+ mon.setup()
+ for cg in ('memory', 'cpuacct', 'blkio'):
+ self.assertIn(cg, mon.cgroups)
+
+ def test_update_without_setup(self):
+ mon = vdsm.virt.containers.metrics.cgroups.Monitorable(self.pid)
+ mon.update()
+ self.assertEquals(mon.cgroups, ())
diff --git a/tests/containers/conttestlib.py b/tests/containers/conttestlib.py
new file mode 100644
index 0000000..5ad3c4f
--- /dev/null
+++ b/tests/containers/conttestlib.py
@@ -0,0 +1,290 @@
+from __future__ import absolute_import
+#
+# Copyright 2015-2016 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+from contextlib import contextmanager
+import collections
+import gzip
+import os
+import os.path
+import shutil
+import tarfile
+import tempfile
+import uuid
+import unittest
+
+import vdsm.virt.containers.command
+import vdsm.virt.containers.config
+import vdsm.virt.containers.config.environ
+import vdsm.virt.containers.metrics.cgroups
+import vdsm.virt.containers.runtime
+import vdsm.virt.containers.runtimes
+
+from . import monkey
+
+
+class TestCase(unittest.TestCase):
+
+ def assertNotRaises(self, callableObj=None, *args, **kwargs):
+ # This is required when any exception raised during the call should be
+ # considered as a test failure.
+ context = not_raises(self)
+ if callableObj is None:
+ return context
+ with context:
+ callableObj(*args, **kwargs)
+
+
+@contextmanager
+def not_raises(test_case):
+ try:
+ yield
+ except Exception as e:
+ raise test_case.failureException("Exception raised: %s" % e)
+
+
+class TruePath(object):
+ def cmd(self):
+ return True
+
+
+class NonePath(object):
+ def __init__(self):
+ self.cmd = None
+
+
+TEMPDIR = '/tmp'
+
+
+@contextmanager
+def named_temp_dir(base=TEMPDIR):
+ tmp_dir = tempfile.mkdtemp(dir=base)
+ try:
+ yield tmp_dir
+ finally:
+ shutil.rmtree(tmp_dir)
+
+
+def make_conf(**kwargs):
+ conf = vdsm.virt.containers.config.environ.current()
+ for k, v in list(kwargs.items()):
+ setattr(conf, k, v)
+ return conf
+
+
+@contextmanager
+def global_conf(**kwargs):
+ saved_conf = vdsm.virt.containers.config.environ.current()
+
+ conf = make_conf(**kwargs)
+ vdsm.virt.containers.config.environ.setup(conf)
+ try:
+ yield conf
+ finally:
+ vdsm.virt.containers.config.environ.setup(saved_conf)
+
+
+def fake_executables():
+ paths = ['.', './tests', './fake/bin',
'./tests/fake/bin']
+ return {
+ 'machinectl': vdsm.virt.containers.command.Path(
+ 'true'
+ ),
+ 'systemctl': vdsm.virt.containers.command.Path(
+ 'systemctl', paths=paths
+ ),
+ 'rkt': vdsm.virt.containers.command.Path(
+ 'rkt', paths=paths
+ ),
+ 'systemd-run': vdsm.virt.containers.command.Path(
+ 'systemd-run', paths=paths
+ ),
+ }
+
+
+class RunnableTestCase(TestCase):
+
+ def setUp(self):
+ self.guid = uuid.uuid4()
+ self.run_dir = tempfile.mkdtemp()
+ self.patch = monkey.Patch([
+ (vdsm.virt.containers.runtimes.rkt.Network, 'DIR', self.run_dir),
+ (vdsm.virt.containers.command, 'executables', fake_executables()),
+ ])
+ self.patch.apply()
+ vdsm.virt.containers.runtime.clear()
+ vdsm.virt.containers.runtime.configure()
+
+ def tearDown(self):
+ self.patch.revert()
+ shutil.rmtree(self.run_dir)
+
+
+@contextmanager
+def move_into(path):
+ oldpath = os.getcwd()
+ try:
+ os.chdir(path)
+ yield
+ finally:
+ os.chdir(oldpath)
+
+
+class CgroupTestCase(TestCase):
+
+ def setUp(self):
+ self.pid = 0
+ testdir = os.path.dirname(os.path.abspath(__file__))
+ self.root = os.path.join(testdir, 'fake')
+
+ self.procfsroot = os.path.join(
+ self.root, vdsm.virt.containers.metrics.cgroups.PROCFS
+ )
+ self.cgroupfsroot = os.path.join(
+ self.root, vdsm.virt.containers.metrics.cgroups.CGROUPFS
+ )
+
+ with move_into(self.root):
+ cgroupsdata = os.path.join(self.root, 'cgroups.tgz')
+ with gzip.GzipFile(cgroupsdata) as gz:
+ tar = tarfile.TarFile(fileobj=gz)
+ tar.extractall()
+
+ self.patch = monkey.Patch([
+ (vdsm.virt.containers.metrics.cgroups,
+ '_PROCBASE', self.procfsroot),
+ (vdsm.virt.containers.metrics.cgroups,
+ '_CGROUPBASE', self.cgroupfsroot),
+ ])
+ self.patch.apply()
+
+ def tearDown(self):
+ self.patch.revert()
+ shutil.rmtree(self.procfsroot)
+ shutil.rmtree(self.cgroupfsroot)
+
+
+class FakeRunnableTestCase(TestCase):
+
+ def setUp(self):
+ def _fake_create(rt, conf, repo, **kwargs):
+ return vdsm.virt.containers.runtimes.fake.Fake(
+ conf,
+ repo,
+ **kwargs
+ )
+
+ self.patch = monkey.Patch([
+ (vdsm.virt.containers.runtime, 'create', _fake_create),
+ ])
+ self.patch.apply()
+ self.dom = vdsm.virt.containers.domain.Domain(
+ minimal_dom_xml(),
+ vdsm.virt.containers.config.environ.current(),
+ FakeRepo()
+ )
+
+ def tearDown(self):
+ self.patch.revert()
+
+
+class FakeRunner(object):
+ def __init__(self):
+ self.stopped = False
+ self.started = False
+ self.setup_done = False
+ self.teardown_done = False
+ self.configured = False
+ self.resynced = False
+ self.uuid = '00000000-0000-0000-0000-000000000000'
+
+ def setup(self, *args, **kwargs):
+ self.setup_done = True
+
+ def teardown(self, *args, **kwargs):
+ self.teardown_done = True
+
+ def start(self, *args, **kwargs):
+ self.started = True
+
+ def resync(self):
+ self.resynced = True
+
+ def stop(self):
+ self.stopped = True
+
+ def configure(self, *args, **kwargs):
+ self.configured = True
+
+
+def minimal_dom_xml(vm_uuid=None):
+ data = _read_dom_xml('minimal_dom.xml')
+ vm_uuid = str(uuid.uuid4()) if vm_uuid is None else vm_uuid
+ return data.format(vm_uuid=vm_uuid)
+
+
+def full_dom_xml(vm_uuid=None):
+ data = _read_dom_xml('full_dom.xml')
+ vm_uuid = str(uuid.uuid4()) if vm_uuid is None else vm_uuid
+ return data.format(vm_uuid=vm_uuid)
+
+
+def only_disk_dom_xml():
+ return _read_dom_xml('only_disk.xml')
+
+
+def only_mem_dom_xml():
+ return _read_dom_xml('only_mem.xml')
+
+
+def disk_dev_dom_xml():
+ return _read_dom_xml('disk_dev.xml')
+
+
+def disk_file_malformed_dom_xml():
+ return _read_dom_xml('disk_file_malformed.xml')
+
+
+def bridge_down_dom_xml():
+ return _read_dom_xml('bridge_down.xml')
+
+
+def bridge_no_source_dom_xml():
+ return _read_dom_xml('bridge_no_source.xml')
+
+
+def metadata_drive_map_dom_xml():
+ return _read_dom_xml('metadata_drive_map.xml')
+
+
+def _read_dom_xml(name):
+ testdir = os.path.dirname(os.path.abspath(__file__))
+ tmpl = os.path.join(testdir, 'data', name)
+ with open(tmpl, 'rt') as src:
+ return src.read()
+
+
+class FakeRepo(vdsm.virt.containers.command.Repo):
+
+ def __init__(self):
+ super(FakeRepo, self).__init__(execs=fake_executables())
+ self._cmds = collections.defaultdict(
+ lambda: vdsm.virt.containers.command.FakeCommand
+ )
diff --git a/tests/containers/data/bridge_down.xml
b/tests/containers/data/bridge_down.xml
new file mode 100644
index 0000000..2ef73c7
--- /dev/null
+++ b/tests/containers/data/bridge_down.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<domain type="kvm"
xmlns:ovirt="http://ovirt.org/vm/tune/1.0">
+ <name>testVm</name>
+ <uuid>35ef4734-4ed5-4f95-abf8-928e23a76619</uuid>
+ <maxMemory>16384</maxMemory>
+ <metadata>
+ <convirt:container
xmlns:convirt="http://github.com/ovirt/containers/1.0">rkt&l...
+ </metadata>
+ <devices>
+ <emulator>kvm</emulator>
+ <disk type='file' device='disk' snapshot='no'>
+ <driver name='qemu' type='raw' cache='none'
error_policy='stop' io='threads'/>
+ <source
file='/rhev/data-center/00000001-0001-0001-0001-00000000027f/43db3789-bb16-40bd-a9fc-3cced1b23ea6/images/90bece76-2df6-4a88-bfc8-f6f7461b7b8b/844e5378-6700-45ba-a846-67eba730e24b'>
+ <seclabel model='selinux' labelskip='yes'/>
+ </source>
+ <backingStore/>
+ <target dev='vda' bus='virtio'/>
+ <serial>90bece76-2df6-4a88-bfc8-f6f7461b7b8b</serial>
+ <alias name='virtio-disk0'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x06' function='0x0'/>
+ </disk>
+ <interface type="bridge">
+ <mac address="00:1a:4a:16:01:5a"/>
+ <model type="virtio"/>
+ <source bridge="ovirtmgmt"/>
+ <filterref filter="vdsm-no-mac-spoofing"/>
+ <link state="down"/>
+ <bandwidth/>
+ </interface>
+ </devices>
+</domain>
diff --git a/tests/containers/data/bridge_no_source.xml
b/tests/containers/data/bridge_no_source.xml
new file mode 100644
index 0000000..ed99cae
--- /dev/null
+++ b/tests/containers/data/bridge_no_source.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<domain type="kvm"
xmlns:ovirt="http://ovirt.org/vm/tune/1.0">
+ <name>testVm</name>
+ <uuid>35ef4734-4ed5-4f95-abf8-928e23a76619</uuid>
+ <maxMemory>16384</maxMemory>
+ <metadata>
+ <convirt:container
xmlns:convirt="http://github.com/ovirt/containers/1.0">rkt&l...
+ </metadata>
+ <devices>
+ <emulator>kvm</emulator>
+ <disk type='file' device='disk' snapshot='no'>
+ <driver name='qemu' type='raw' cache='none'
error_policy='stop' io='threads'/>
+ <source
file='/rhev/data-center/00000001-0001-0001-0001-00000000027f/43db3789-bb16-40bd-a9fc-3cced1b23ea6/images/90bece76-2df6-4a88-bfc8-f6f7461b7b8b/844e5378-6700-45ba-a846-67eba730e24b'>
+ <seclabel model='selinux' labelskip='yes'/>
+ </source>
+ <backingStore/>
+ <target dev='vda' bus='virtio'/>
+ <serial>90bece76-2df6-4a88-bfc8-f6f7461b7b8b</serial>
+ <alias name='virtio-disk0'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x06' function='0x0'/>
+ </disk>
+ <interface type="bridge">
+ <mac address="00:1a:4a:16:01:5a"/>
+ <model type="virtio"/>
+ <filterref filter="vdsm-no-mac-spoofing"/>
+ <link state="up"/>
+ <bandwidth/>
+ </interface>
+ </devices>
+</domain>
diff --git a/tests/containers/data/disk_dev.xml b/tests/containers/data/disk_dev.xml
new file mode 100644
index 0000000..cec0cbc
--- /dev/null
+++ b/tests/containers/data/disk_dev.xml
@@ -0,0 +1,15 @@
+<domain type='kvm' id='2'>
+ <metadata>
+ <convirt:container
xmlns:convirt="http://github.com/ovirt/containers/1.0">rkt&l...
+ </metadata>
+ <devices>
+ <emulator>kvm</emulator>
+ <disk device="disk" snapshot="no" type="block">
+ <source
dev="/rhev/data-center/00000001-0001-0001-0001-00000000027f/38fa52fc-f62f-4d83-b89d-956f3d75c518/images/e0482091-853c-4e97-b80f-87f174730688/c36bb9f1-976a-414b-abd5-d72f5d2a94d2"/>
+ <target bus="virtio" dev="vda"/>
+
<serial>e0482091-853c-4e97-b80f-87f174730688</serial>
+ <boot order="1"/>
+ <driver cache="none" error_policy="stop"
io="native" name="qemu" type="qcow2"/>
+ </disk>
+ </devices>
+ </domain>
diff --git a/tests/containers/data/disk_file_malformed.xml
b/tests/containers/data/disk_file_malformed.xml
new file mode 100644
index 0000000..e15aebf
--- /dev/null
+++ b/tests/containers/data/disk_file_malformed.xml
@@ -0,0 +1,16 @@
+<domain type='kvm' id='2'>
+ <maxMemory slots='16' unit='KiB'>4294967296</maxMemory>
+ <metadata>
+ <convirt:container
xmlns:convirt="http://github.com/ovirt/containers/1.0">rkt&l...
+ </metadata>
+ <devices>
+ <emulator>kvm</emulator>
+ <disk device="disk" snapshot="no" type="file">
+ <source
dev="/rhev/data-center/00000001-0001-0001-0001-00000000027f/38fa52fc-f62f-4d83-b89d-956f3d75c518/images/e0482091-853c-4e97-b80f-87f174730688/c36bb9f1-976a-414b-abd5-d72f5d2a94d2"/>
+ <target bus="virtio" dev="vda"/>
+
<serial>e0482091-853c-4e97-b80f-87f174730688</serial>
+ <boot order="1"/>
+ <driver cache="none" error_policy="stop"
io="native" name="qemu" type="qcow2"/>
+ </disk>
+ </devices>
+ </domain>
diff --git a/tests/containers/data/full_dom.xml b/tests/containers/data/full_dom.xml
new file mode 100644
index 0000000..901e3ca
--- /dev/null
+++ b/tests/containers/data/full_dom.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<domain type="kvm"
xmlns:ovirt="http://ovirt.org/vm/tune/1.0">
+ <name>a_c7_2</name>
+ <uuid>{vm_uuid}</uuid>
+ <memory>4194304</memory>
+ <currentMemory>4194304</currentMemory>
+ <maxMemory slots="16">4294967296</maxMemory>
+ <vcpu current="2">16</vcpu>
+ <metadata>
+ <convirt:container
xmlns:convirt="http://github.com/ovirt/containers/1.0">rkt&l...
+ <ovirt:qos/>
+ </metadata>
+ <devices>
+ <emulator>kvm</emulator>
+ <channel type="unix">
+ <target name="com.redhat.rhevm.vdsm"
type="virtio"/>
+ <source mode="bind"
path="/var/lib/libvirt/qemu/channels/338175a6-44e7-45d0-8321-2c6f2d5b3d6b.com.redhat.rhevm.vdsm"/>
+ </channel>
+ <channel type="unix">
+ <target name="org.qemu.guest_agent.0"
type="virtio"/>
+ <source mode="bind"
path="/var/lib/libvirt/qemu/channels/338175a6-44e7-45d0-8321-2c6f2d5b3d6b.org.qemu.guest_agent.0"/>
+ </channel>
+ <input bus="ps2" type="mouse"/>
+ <memballoon model="none"/>
+ <video>
+ <model heads="1" ram="65536"
type="qxl" vgamem="16384" vram="32768"/>
+ </video>
+ <graphics autoport="yes" passwd="*****"
passwdValidTo="1970-01-01T00:00:01" port="-1" tlsPort="-1"
type="spice">
+ <listen network="vdsm-ovirtmgmt"
type="network"/>
+ </graphics>
+ <interface type="bridge">
+ <mac address="00:1a:4a:16:01:57"/>
+ <model type="virtio"/>
+ <source bridge="ovirtmgmt"/>
+ <filterref filter="vdsm-no-mac-spoofing"/>
+ <link state="up"/>
+ <bandwidth/>
+ </interface>
+ <disk device="cdrom" snapshot="no"
type="file">
+ <source
file="/rhev/data-center/00000001-0001-0001-0001-00000000027f/43db3789-bb16-40bd-a9fc-3cced1b23ea6/images/27101aac-10ec-468a-aaf5-694c663b2c33/373d166e-d21a-4ad0-8166-571f49c22d64"
startupPolicy="optional"/>
+ <target bus="ide" dev="hdc"/>
+ <readonly/>
+
<serial>522169df-603d-4229-8451-69a4e860554a</serial>
+ <boot order="1"/>
+ </disk>
+ <disk device="disk" snapshot="no"
type="file">
+ <source
file="/rhev/data-center/00000001-0001-0001-0001-00000000027f/43db3789-bb16-40bd-a9fc-3cced1b23ea6/images/27101aac-10ec-468a-aaf5-694c663b2c33/19bb423f-7db0-4cd1-9fe9-5aa3d4d8c1af"/>
+ <target bus="virtio" dev="vda"/>
+
<serial>27101aac-10ec-468a-aaf5-694c663b2c33</serial>
+ <boot order="2"/>
+ <driver cache="none" error_policy="stop"
io="threads" name="qemu" type="raw"/>
+ </disk>
+ <channel type="spicevmc">
+ <target name="com.redhat.spice.0"
type="virtio"/>
+ </channel>
+ </devices>
+ <os>
+ <type arch="x86_64"
machine="pc-i440fx-rhel7.2.0">hvm</type>
+ <smbios mode="sysinfo"/>
+ </os>
+ <sysinfo type="smbios">
+ <system>
+ <entry name="manufacturer">oVirt</entry>
+ <entry name="product">oVirt Node</entry>
+ <entry
name="version">7-2.1511.el7.centos.2.10</entry>
+ <entry
name="serial">0A9C980E-6B95-3D34-C5AC-40167EB07D87</entry>
+ <entry
name="uuid">338175a6-44e7-45d0-8321-2c6f2d5b3d6b</entry>
+ </system>
+ </sysinfo>
+ <clock adjustment="0" offset="variable">
+ <timer name="rtc" tickpolicy="catchup"/>
+ <timer name="pit" tickpolicy="delay"/>
+ <timer name="hpet" present="no"/>
+ </clock>
+ <features>
+ <acpi/>
+ </features>
+ <cpu match="exact">
+ <model>Opteron_G2</model>
+ <topology cores="1" sockets="16"
threads="1"/>
+ <numa>
+ <cell cpus="0,1" memory="4194304"/>
+ </numa>
+ </cpu>
+ <numatune>
+ <memory mode="interleave" nodeset="0"/>
+ </numatune>
+</domain>
diff --git a/tests/containers/data/metadata_drive_map.xml
b/tests/containers/data/metadata_drive_map.xml
new file mode 100644
index 0000000..daf194c
--- /dev/null
+++ b/tests/containers/data/metadata_drive_map.xml
@@ -0,0 +1,35 @@
+<domain type='kvm' id='2'>
+ <metadata>
+ <convirt:drivemap
xmlns:convirt="http://github.com/ovirt/containers/drivemap/1.0"...
+ <volume name="data" drive="vda"/>
+ </convirt:drivemap>
+ <convirt:container
xmlns:convirt="http://github.com/ovirt/containers/1.0">rkt&l...
+ </metadata>
+ <memory>4194304</memory>
+ <currentMemory>4194304</currentMemory>
+ <maxMemory slots="16">4294967296</maxMemory>
+ <vcpu current="2">16</vcpu>
+ <devices>
+ <emulator>kvm</emulator>
+ <disk device="cdrom" snapshot="no" type="file">
+ <source
file="/rhev/data-center/00000001-0001-0001-0001-00000000027f/43db3789-bb16-40bd-a9fc-3cced1b23ea6/images/27101aac-10ec-468a-aaf5-694c663b2c33/373d166e-d21a-4ad0-8166-571f49c22d64"
startupPolicy="optional"/>
+ <target bus="ide" dev="hdc"/>
+ <readonly/>
+ <serial>522169df-603d-4229-8451-69a4e860554a</serial>
+ <boot order="1"/>
+ </disk>
+ <disk device="disk" snapshot="no" type="block">
+ <source
dev="/rhev/data-center/00000001-0001-0001-0001-00000000027f/38fa52fc-f62f-4d83-b89d-956f3d75c518/images/e0482091-853c-4e97-b80f-87f174730688/c36bb9f1-976a-414b-abd5-d72f5d2a94d2"/>
+ <target bus="virtio" dev="vda"/>
+ <serial>e0482091-853c-4e97-b80f-87f174730688</serial>
+ <boot order="2"/>
+ <driver cache="none" error_policy="stop"
io="native" name="qemu" type="qcow2"/>
+ </disk>
+ <interface type="bridge">
+ <mac address="00:1a:4a:16:01:57"/>
+ <model type="virtio"/>
+ <source bridge="ovirtmgmt"/>
+ <link state="up"/>
+ </interface>
+ </devices>
+</domain>
diff --git a/tests/containers/data/minimal_dom.xml
b/tests/containers/data/minimal_dom.xml
new file mode 100644
index 0000000..cfcb6fa
--- /dev/null
+++ b/tests/containers/data/minimal_dom.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<domain type="kvm"
xmlns:ovirt="http://ovirt.org/vm/tune/1.0">
+ <name>testVm</name>
+ <uuid>{vm_uuid}</uuid>
+ <maxMemory>16384</maxMemory>
+ <metadata>
+ <convirt:container
xmlns:convirt="http://github.com/ovirt/containers/1.0">rkt&l...
+ </metadata>
+ <devices>
+ <emulator>rkt</emulator>
+ <disk type='file' device='cdrom' snapshot='no'>
+ <driver name='qemu' type='raw' cache='none'
error_policy='stop' io='threads'/>
+ <source
file='/rhev/data-center/00000001-0001-0001-0001-00000000027f/43db3789-bb16-40bd-a9fc-3cced1b23ea6/images/90bece76-2df6-4a88-bfc8-f6f7461b7b8b/844e5378-6700-45ba-a846-67eba730e24b'>
+ <seclabel model='selinux' labelskip='yes'/>
+ </source>
+ <backingStore/>
+ <target dev='vda' bus='virtio'/>
+ <serial>90bece76-2df6-4a88-bfc8-f6f7461b7b8b</serial>
+ <alias name='virtio-disk0'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x06' function='0x0'/>
+ </disk>
+ <interface type="bridge">
+ <mac address="00:1a:4a:16:01:57"/>
+ <model type="virtio"/>
+ <source bridge="ovirtmgmt"/>
+ <link state="up"/>
+ </interface>
+ </devices>
+</domain>
diff --git a/tests/containers/data/only_disk.xml b/tests/containers/data/only_disk.xml
new file mode 100644
index 0000000..dc00f51
--- /dev/null
+++ b/tests/containers/data/only_disk.xml
@@ -0,0 +1,19 @@
+<domain type='kvm' id='2'>
+ <metadata>
+ <convirt:container
xmlns:convirt="http://github.com/ovirt/containers/1.0">rkt&l...
+ </metadata>
+ <devices>
+ <emulator>kvm</emulator>
+ <disk type='file' device='disk' snapshot='no'>
+ <driver name='qemu' type='raw' cache='none'
error_policy='stop' io='threads'/>
+ <source file='/random/path/to/disk/image'>
+ <seclabel model='selinux' labelskip='yes'/>
+ </source>
+ <backingStore/>
+ <target dev='vdb' bus='virtio'/>
+ <serial>90bece76-2df6-4a88-bfc8-f6f7461b7b8b</serial>
+ <alias name='virtio-disk1'/>
+ <address type='pci' domain='0x0000' bus='0x00'
slot='0x06' function='0x0'/>
+ </disk>
+ </devices>
+ </domain>
diff --git a/tests/containers/data/only_mem.xml b/tests/containers/data/only_mem.xml
new file mode 100644
index 0000000..ff4190b
--- /dev/null
+++ b/tests/containers/data/only_mem.xml
@@ -0,0 +1,9 @@
+<domain type='kvm' id='2'>
+ <maxMemory slots='16' unit='KiB'>4294967296</maxMemory>
+ <metadata>
+ <convirt:container
xmlns:convirt="http://github.com/ovirt/containers/1.0">rkt&l...
+ </metadata>
+ <devices>
+ <emulator>kvm</emulator>
+ </devices>
+</domain>
diff --git a/tests/containers/errors_test.py b/tests/containers/errors_test.py
new file mode 100644
index 0000000..9b5b159
--- /dev/null
+++ b/tests/containers/errors_test.py
@@ -0,0 +1,34 @@
+from __future__ import absolute_import
+#
+# Copyright 2015-2016 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+
+import unittest
+
+import libvirt
+
+import vdsm.virt.containers.errors
+
+
+class ErrorsTests(unittest.TestCase):
+
+ def test_throw(self):
+ self.assertRaises(libvirt.libvirtError,
+ vdsm.virt.containers.errors.throw)
diff --git a/tests/containers/fake/bin/docker b/tests/containers/fake/bin/docker
new file mode 100755
index 0000000..6ef02d1
--- /dev/null
+++ b/tests/containers/fake/bin/docker
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+
+import os
+import os.path
+import sys
+
+
+def _main(args):
+ sys.exit(0)
+
+
+if __name__ == "__main__":
+ _main(sys.argv[1:])
diff --git a/tests/containers/fake/bin/rkt b/tests/containers/fake/bin/rkt
new file mode 100755
index 0000000..bc8f566
--- /dev/null
+++ b/tests/containers/fake/bin/rkt
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+
+import os
+import os.path
+import random
+import sys
+import uuid
+
+_ARG = '--uuid-file-save'
+
+def find_path(args):
+ for arg in args:
+ if arg.startswith(_ARG):
+ opt, val = arg.split('=', 1)
+ return val
+ return None
+
+
+def _gc(args):
+ sys.exit(0)
+
+
+def _run(args):
+ try:
+ path = find_path(args)
+ except ValueError:
+ sys.exit(1)
+
+ try:
+ path = path.strip('"')
+ with open(path, 'wt') as fp:
+ fp.write(str(uuid.uuid4()))
+ except IOError as e:
+ sys.exit(2)
+
+
+def _status(rkt_uuid):
+ print(
+"""state=running
+created=2016-06-29 10:10:07.441 +0200 CEST
+started=2016-06-29 10:10:08.548 +0200 CEST
+networks=default:ip4=172.16.28.5
+pid=%i
+exited=false""" % (random.randint(10, 65535)))
+
+
+
+def _main(args):
+ if not args:
+ sys.exit(1)
+
+ if 'gc' in args:
+ _gc(args)
+ elif 'run' in args:
+ _run(args)
+ elif 'status' == args[0]:
+ if len(args) != 2:
+ sys.exit(1)
+ _status(args[1])
+
+
+if __name__ == "__main__":
+ _main(sys.argv[1:])
diff --git a/tests/containers/fake/bin/systemctl b/tests/containers/fake/bin/systemctl
new file mode 100755
index 0000000..f1dee5d
--- /dev/null
+++ b/tests/containers/fake/bin/systemctl
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+import sys
+
+sys.exit(0)
diff --git a/tests/containers/fake/bin/systemd-run
b/tests/containers/fake/bin/systemd-run
new file mode 100755
index 0000000..5454dd7
--- /dev/null
+++ b/tests/containers/fake/bin/systemd-run
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+
+import subprocess
+import sys
+
+for idx, arg in enumerate(sys.argv[1:]):
+ if not arg.startswith('--'):
+ break
+
+torun = sys.argv[idx+1:]
+
+subprocess.check_call(torun)
diff --git a/tests/containers/fake/cgroups.tgz b/tests/containers/fake/cgroups.tgz
new file mode 100644
index 0000000..fe3f58f
--- /dev/null
+++ b/tests/containers/fake/cgroups.tgz
Binary files differ
diff --git a/tests/containers/fs_test.py b/tests/containers/fs_test.py
new file mode 100644
index 0000000..e58df27
--- /dev/null
+++ b/tests/containers/fs_test.py
@@ -0,0 +1,75 @@
+#
+# Copyright 2015-2016 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+from __future__ import absolute_import
+
+import os
+import tempfile
+import uuid
+
+import vdsm.virt.containers
+import vdsm.virt.containers.fs
+
+from . import conttestlib
+
+
+class ReadFileTests(conttestlib.TestCase):
+
+ def test_read_existing_file(self):
+ content = str(uuid.uuid4())
+ with tempfile.NamedTemporaryFile() as f:
+ f.write(content.encode('ascii'))
+ f.flush()
+ self.assertEqual(content,
+ vdsm.virt.containers.fs.read_file(f.name))
+
+ def test_read_unexisting_file(self):
+ path = '/most/likely/does/not/exist'
+ self.assertRaises(IOError,
+ vdsm.virt.containers.fs.read_file,
+ path)
+
+
+class RMFileTests(conttestlib.TestCase):
+
+ def test_rm_file_once(self):
+ with conttestlib.named_temp_dir() as tmp_dir:
+ path = os.path.join(tmp_dir, "foobar")
+ with open(path, 'wt') as f:
+ f.write('%s\n' % str(uuid.uuid4()))
+ self.assertEquals(os.listdir(tmp_dir), ['foobar'])
+ vdsm.virt.containers.fs.rm_file(path)
+ self.assertEquals(os.listdir(tmp_dir), [])
+
+ def test_rm_file_twice(self):
+ with conttestlib.named_temp_dir() as tmp_dir:
+ path = os.path.join(tmp_dir, "foobar")
+ with open(path, 'wt') as f:
+ f.write('%s\n' % str(uuid.uuid4()))
+ self.assertEquals(os.listdir(tmp_dir), ['foobar'])
+ vdsm.virt.containers.fs.rm_file(path)
+ self.assertEquals(os.listdir(tmp_dir), [])
+ self.assertNotRaises(vdsm.virt.containers.fs.rm_file, path)
+ self.assertEquals(os.listdir(tmp_dir), [])
+
+ def test_rm_file_fails(self):
+ self.assertNotEqual(os.geteuid(), 0)
+ self.assertRaises(OSError,
+ vdsm.virt.containers.fs.rm_file,
+ '/var/log/lastlog')
diff --git a/tests/containers/monkey.py b/tests/containers/monkey.py
new file mode 100644
index 0000000..b71e0825
--- /dev/null
+++ b/tests/containers/monkey.py
@@ -0,0 +1,108 @@
+from __future__ import absolute_import
+#
+# Copyright 2012-2016 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+from contextlib import contextmanager
+from functools import wraps
+import inspect
+
+
+class Patch(object):
+
+ def __init__(self, what):
+ self.what = what
+ self.old = []
+
+ def apply(self):
+ for module, name, that in self.what:
+ old = getattr(module, name)
+ self.old.append((module, name, old))
+ # The following block is done so that if it is a method we are
+ # patching in, that it will have the same type as the method it
+ # replaced.
+ if inspect.isclass(module):
+ if inspect.isfunction(old):
+ that = staticmethod(that)
+ elif (inspect.ismethod(old) and
+ getattr(old, 'im_self', None) is not None):
+ that = classmethod(that)
+ setattr(module, name, that)
+
+ def revert(self):
+ assert self.old != []
+ while self.old:
+ module, name, that = self.old.pop()
+ # The following block is only necessary for Python2 as it wrongly
+ # sets the function as instancemethod instead of keeping it as
+ # staticmethod.
+ if inspect.isclass(module):
+ if inspect.isfunction(that):
+ that = staticmethod(that)
+
+ setattr(module, name, that)
+
+
+@contextmanager
+def patch_scope(what):
+ patch = Patch(what)
+ patch.apply()
+ try:
+ yield
+ finally:
+ patch.revert()
+
+
+def patch_function(module, name, that):
+ def decorator(f):
+ @wraps(f)
+ def wrapper(*args, **kw):
+ with patch_scope([(module, name, that)]):
+ return f(*args, **kw)
+ return wrapper
+ return decorator
+
+
+def patch_class(module, name, that):
+
+ def setup_decorator(func):
+ @wraps(func)
+ def setup(self, *a, **kw):
+ if not hasattr(self, '__monkeystack__'):
+ self.__monkeystack__ = []
+ patch = Patch([(module, name, that)])
+ self.__monkeystack__.append(patch)
+ patch.apply()
+ return func(self, *a, **kw)
+ return setup
+
+ def teardown_decorator(func):
+ @wraps(func)
+ def teardown(self, *a, **kw):
+ patch = self.__monkeystack__.pop()
+ patch.revert()
+ return func(self, *a, **kw)
+ return teardown
+
+ def wrapper(cls):
+ cls.setUp = setup_decorator(cls.setUp)
+ cls.tearDown = teardown_decorator(cls.tearDown)
+ return cls
+
+ return wrapper
diff --git a/tests/containers/xmlfile_test.py b/tests/containers/xmlfile_test.py
new file mode 100644
index 0000000..8b50652
--- /dev/null
+++ b/tests/containers/xmlfile_test.py
@@ -0,0 +1,87 @@
+#
+# Copyright 2015-2016 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+from __future__ import absolute_import
+
+import contextlib
+import os
+import uuid
+import xml.etree.ElementTree as ET
+
+import vdsm.virt.containers
+import vdsm.virt.containers.config
+import vdsm.virt.containers.config.environ
+import vdsm.virt.containers.xmlfile
+
+from . import conttestlib
+
+
+class XMLFileTests(conttestlib.TestCase):
+
+ def setUp(self):
+ self.vm_uuid = str(uuid.uuid4())
+
+ @contextlib.contextmanager
+ def test_env(self):
+ with conttestlib.named_temp_dir() as tmp_dir:
+ with conttestlib.global_conf(run_dir=tmp_dir):
+ yield vdsm.virt.containers.xmlfile.XMLFile(
+ self.vm_uuid,
+ vdsm.virt.containers.config.environ.current()
+ )
+
+ def test_fails_without_conf(self):
+ self.assertRaises(vdsm.virt.containers.xmlfile.UnconfiguredXML,
+ vdsm.virt.containers.xmlfile.XMLFile,
+ self.vm_uuid,
+ None)
+
+ def test_path(self):
+ with self.test_env() as xf:
+ self.assertTrue(xf.path.endswith('xml'))
+ self.assertIn(self.vm_uuid, xf.path)
+
+ def test_save(self):
+ root = ET.fromstring(conttestlib.minimal_dom_xml())
+ with self.test_env() as xf:
+ conf = vdsm.virt.containers.config.environ.current()
+ self.assertEquals(os.listdir(conf.run_dir), [])
+ self.assertNotRaises(xf.save, root)
+ self.assertTrue(len(os.listdir(conf.run_dir)), 1)
+
+ def test_load(self):
+ xml_data = conttestlib.minimal_dom_xml()
+ root = ET.fromstring(xml_data)
+ with self.test_env() as xf:
+ xf.save(root)
+ new_root = xf.load()
+ xml_copy = vdsm.virt.containers.xmlfile.XMLFile.encode(new_root)
+ # FIXME: nasty trick to tidy up the XML
+ xml_ref = vdsm.virt.containers.xmlfile.XMLFile.encode(root)
+ self.assertEquals(xml_ref, xml_copy)
+
+ def test_clear(self):
+ xml_data = conttestlib.minimal_dom_xml()
+ root = ET.fromstring(xml_data)
+ with self.test_env() as xf:
+ xf.save(root)
+ conf = vdsm.virt.containers.config.environ.current()
+ self.assertTrue(len(os.listdir(conf.run_dir)), 1)
+ self.assertNotRaises(xf.clear)
+ self.assertEquals(os.listdir(conf.run_dir), [])
--
To view, visit
https://gerrit.ovirt.org/60678
To unsubscribe, visit
https://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I27ba3cecbd71b7bbba94992d6bc63ca29333e313
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Francesco Romani <fromani(a)redhat.com>