aboutsummaryrefslogtreecommitdiffstats
path: root/tests/unit/benchmark/scenarios
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/benchmark/scenarios')
-rw-r--r--tests/unit/benchmark/scenarios/compute/test_qemumigrate.py166
-rw-r--r--tests/unit/benchmark/scenarios/lib/__init__.py0
-rw-r--r--tests/unit/benchmark/scenarios/lib/test_add_memory_load.py65
-rw-r--r--tests/unit/benchmark/scenarios/lib/test_check_numa_info.py84
-rw-r--r--tests/unit/benchmark/scenarios/lib/test_check_value.py46
-rw-r--r--tests/unit/benchmark/scenarios/lib/test_get_migrate_target_host.py51
-rw-r--r--tests/unit/benchmark/scenarios/lib/test_get_numa_info.py106
-rw-r--r--tests/unit/benchmark/scenarios/lib/test_get_server.py50
-rw-r--r--tests/unit/benchmark/scenarios/lib/test_get_server_ip.py41
9 files changed, 609 insertions, 0 deletions
diff --git a/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py b/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py
new file mode 100644
index 000000000..9514729ba
--- /dev/null
+++ b/tests/unit/benchmark/scenarios/compute/test_qemumigrate.py
@@ -0,0 +1,166 @@
+#!/usr/bin/env python
+
+##############################################################################
+# Copyright (c) 2015 Huawei Technologies Co.,Ltd and other.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+# Unittest for yardstick.benchmark.scenarios.compute.qemu_migrate.QemuMigrate
+
+from __future__ import absolute_import
+
+import unittest
+
+import mock
+from oslo_serialization import jsonutils
+
+from yardstick.benchmark.scenarios.compute import qemu_migrate
+
+
+@mock.patch('yardstick.benchmark.scenarios.compute.qemu_migrate.ssh')
+class QemuMigrateTestCase(unittest.TestCase):
+
+ def setUp(self):
+ self.scenario_cfg = {
+ "host": "kvm.LF",
+ "setup_options": {
+ "rpm_dir": "/opt/rpm",
+ "script_dir": "/opt/scripts",
+ "image_dir": "/opt/image",
+ "host_setup_seqs": [
+ "host-setup0.sh",
+ "host-setup1.sh",
+ "setup-ovsdpdk.sh",
+ "host-install-qemu.sh",
+ "host-run-qemu4lm.sh"
+ ]
+ },
+ "sla": {
+ "action": "monitor",
+ "max_totaltime": 10,
+ "max_downtime": 0.10,
+ "max_setuptime": 0.50
+ },
+ "options": {
+ "smp": 99,
+ "migrate_to_port": 4444,
+ "incoming_ip": 0,
+ "qmp_src_path": "/tmp/qmp-sock-src",
+ "qmp_dst_path": "/tmp/qmp-sock-dst",
+ "max_down_time": "0.10"
+ }
+ }
+ self.context_cfg = {
+ "host": {
+ "ip": "10.229.43.154",
+ "key_filename": "/yardstick/resources/files/yardstick_key",
+ "role": "BareMetal",
+ "name": "kvm.LF",
+ "user": "root"
+ }
+ }
+
+ def test_qemu_migrate_successful_setup(self, mock_ssh):
+
+ q = qemu_migrate.QemuMigrate(self.scenario_cfg, self.context_cfg)
+ mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
+
+ q.setup()
+ self.assertIsNotNone(q.host)
+ self.assertEqual(q.setup_done, True)
+
+ def test_qemu_migrate_successful_no_sla(self, mock_ssh):
+ result = {}
+ self.scenario_cfg.pop("sla", None)
+ q = qemu_migrate.QemuMigrate(self.scenario_cfg, self.context_cfg)
+ mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
+ q.setup()
+
+ sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}'
+ mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
+
+ q.run(result)
+ expected_result = jsonutils.loads(sample_output)
+ self.assertEqual(result, expected_result)
+
+ def test_qemu_migrate_successful_sla(self, mock_ssh):
+ result = {}
+ self.scenario_cfg.update({"sla": {
+ "action": "monitor",
+ "max_totaltime": 15,
+ "max_downtime": 2,
+ "max_setuptime": 1
+ }
+ })
+ q = qemu_migrate.QemuMigrate(self.scenario_cfg, self.context_cfg)
+ mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
+ q.setup()
+
+ sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}'
+ mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
+
+ q.run(result)
+ expected_result = jsonutils.loads(sample_output)
+ self.assertEqual(result, expected_result)
+
+ def test_qemu_migrate_unsuccessful_sla_totaltime(self, mock_ssh):
+
+ result = {}
+ self.scenario_cfg.update({"sla": {"max_totaltime": 10}})
+ q = qemu_migrate.QemuMigrate(self.scenario_cfg, self.context_cfg)
+ mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
+ q.setup()
+
+ sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}'
+
+ mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
+ self.assertRaises(AssertionError, q.run, result)
+
+ def test_qemu_migrate_unsuccessful_sla_downtime(self, mock_ssh):
+
+ result = {}
+ self.scenario_cfg.update({"sla": {"max_downtime": 0.10}})
+ q = qemu_migrate.QemuMigrate(self.scenario_cfg, self.context_cfg)
+ mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
+ q.setup()
+
+ sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}'
+
+ mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
+ self.assertRaises(AssertionError, q.run, result)
+
+ def test_qemu_migrate_unsuccessful_sla_setuptime(self, mock_ssh):
+
+ result = {}
+ self.scenario_cfg.update({"sla": {"max_setuptime": 0.50}})
+ q = qemu_migrate.QemuMigrate(self.scenario_cfg, self.context_cfg)
+ mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
+ q.setup()
+
+ sample_output = '{"totaltime": 15, "downtime": 2, "setuptime": 1}'
+
+ mock_ssh.SSH.from_node().execute.return_value = (0, sample_output, '')
+ self.assertRaises(AssertionError, q.run, result)
+
+ def test_qemu_migrate_unsuccessful_script_error(self, mock_ssh):
+
+ result = {}
+ self.scenario_cfg.update({"sla": {"max_totaltime": 10}})
+ q = qemu_migrate.QemuMigrate(self.scenario_cfg, self.context_cfg)
+ mock_ssh.SSH.from_node().execute.return_value = (0, '', '')
+ q.setup()
+
+
+ mock_ssh.SSH.from_node().execute.return_value = (1, '', 'FOOBAR')
+ self.assertRaises(RuntimeError, q.run, result)
+
+
+def main():
+ unittest.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/unit/benchmark/scenarios/lib/__init__.py b/tests/unit/benchmark/scenarios/lib/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/unit/benchmark/scenarios/lib/__init__.py
diff --git a/tests/unit/benchmark/scenarios/lib/test_add_memory_load.py b/tests/unit/benchmark/scenarios/lib/test_add_memory_load.py
new file mode 100644
index 000000000..bda07f723
--- /dev/null
+++ b/tests/unit/benchmark/scenarios/lib/test_add_memory_load.py
@@ -0,0 +1,65 @@
+##############################################################################
+# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+import unittest
+import mock
+
+from yardstick.benchmark.scenarios.lib.add_memory_load import AddMemoryLoad
+
+
+class AddMemoryLoadTestCase(unittest.TestCase):
+
+ @mock.patch('yardstick.ssh.SSH.from_node')
+ def test_add_memory_load_with_load(self, mock_from_node):
+ scenario_cfg = {
+ 'options': {
+ 'memory_load': 0.5
+ }
+ }
+ context_cfg = {
+ 'host': {}
+ }
+ mock_from_node().execute.return_value = (0, '0 2048 512', '')
+ obj = AddMemoryLoad(scenario_cfg, context_cfg)
+ obj.run({})
+ self.assertTrue(mock_from_node.called)
+
+ @mock.patch('yardstick.ssh.SSH.from_node')
+ def test_add_memory_load_without_load(self, mock_from_node):
+ scenario_cfg = {
+ 'options': {
+ 'memory_load': 0
+ }
+ }
+ context_cfg = {
+ 'host': {}
+ }
+ obj = AddMemoryLoad(scenario_cfg, context_cfg)
+ obj.run({})
+ self.assertTrue(mock_from_node.called)
+
+ @mock.patch('yardstick.ssh.SSH.from_node')
+ def test_add_memory_load_without_args(self, mock_from_node):
+ scenario_cfg = {
+ 'options': {
+ }
+ }
+ context_cfg = {
+ 'host': {}
+ }
+ obj = AddMemoryLoad(scenario_cfg, context_cfg)
+ obj.run({})
+ self.assertTrue(mock_from_node.called)
+
+
+def main():
+ unittest.main()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/unit/benchmark/scenarios/lib/test_check_numa_info.py b/tests/unit/benchmark/scenarios/lib/test_check_numa_info.py
new file mode 100644
index 000000000..bdf1e66e5
--- /dev/null
+++ b/tests/unit/benchmark/scenarios/lib/test_check_numa_info.py
@@ -0,0 +1,84 @@
+##############################################################################
+# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+import unittest
+import mock
+
+from yardstick.benchmark.scenarios.lib.check_numa_info import CheckNumaInfo
+
+
+class CheckNumaInfoTestCase(unittest.TestCase):
+
+ @mock.patch('yardstick.benchmark.scenarios.lib.check_numa_info.CheckNumaInfo._check_vm2_status')
+ def test_check_numa_info(self, mock_check_vm2):
+ scenario_cfg = {'info1': {}, 'info2': {}}
+ obj = CheckNumaInfo(scenario_cfg, {})
+ obj.run({})
+ self.assertTrue(mock_check_vm2.called)
+
+ def test_check_vm2_status_length_eq_1(self):
+ info1 = {
+ 'pinning': [0],
+ 'vcpupin': [{
+ 'cpuset': '1,2'
+ }]
+ }
+ info2 = {
+ 'pinning': [0],
+ 'vcpupin': [{
+ 'cpuset': '1,2'
+ }]
+ }
+ scenario_cfg = {'info1': info1, 'info2': info2}
+ obj = CheckNumaInfo(scenario_cfg, {})
+ status = obj._check_vm2_status(info1, info2)
+ self.assertEqual(status, True)
+
+ def test_check_vm2_status_length_gt_1(self):
+ info1 = {
+ 'pinning': [0, 1],
+ 'vcpupin': [{
+ 'cpuset': '1,2'
+ }]
+ }
+ info2 = {
+ 'pinning': [0, 1],
+ 'vcpupin': [{
+ 'cpuset': '1,2'
+ }]
+ }
+ scenario_cfg = {'info1': info1, 'info2': info2}
+ obj = CheckNumaInfo(scenario_cfg, {})
+ status = obj._check_vm2_status(info1, info2)
+ self.assertEqual(status, False)
+
+ def test_check_vm2_status_length_not_in_set(self):
+ info1 = {
+ 'pinning': [0],
+ 'vcpupin': [{
+ 'cpuset': '1,7'
+ }]
+ }
+ info2 = {
+ 'pinning': [0],
+ 'vcpupin': [{
+ 'cpuset': '1,7'
+ }]
+ }
+ scenario_cfg = {'info1': info1, 'info2': info2}
+ obj = CheckNumaInfo(scenario_cfg, {})
+ status = obj._check_vm2_status(info1, info2)
+ self.assertEqual(status, False)
+
+
+def main():
+ unittest.main()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/unit/benchmark/scenarios/lib/test_check_value.py b/tests/unit/benchmark/scenarios/lib/test_check_value.py
new file mode 100644
index 000000000..21e83f830
--- /dev/null
+++ b/tests/unit/benchmark/scenarios/lib/test_check_value.py
@@ -0,0 +1,46 @@
+##############################################################################
+# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+import unittest
+
+from yardstick.benchmark.scenarios.lib.check_value import CheckValue
+
+
+class CheckValueTestCase(unittest.TestCase):
+
+ def test_check_value_eq(self):
+ scenario_cfg = {'options': {'operator': 'eq', 'value1': 1, 'value2': 2}}
+ obj = CheckValue(scenario_cfg, {})
+ try:
+ obj.run({})
+ except Exception as e:
+ self.assertIsInstance(e, AssertionError)
+
+ def test_check_value_eq_pass(self):
+ scenario_cfg = {'options': {'operator': 'eq', 'value1': 1, 'value2': 1}}
+ obj = CheckValue(scenario_cfg, {})
+ try:
+ obj.run({})
+ except Exception as e:
+ self.assertIsInstance(e, AssertionError)
+
+ def test_check_value_ne(self):
+ scenario_cfg = {'options': {'operator': 'ne', 'value1': 1, 'value2': 1}}
+ obj = CheckValue(scenario_cfg, {})
+ try:
+ obj.run({})
+ except Exception as e:
+ self.assertIsInstance(e, AssertionError)
+
+
+def main():
+ unittest.main()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/unit/benchmark/scenarios/lib/test_get_migrate_target_host.py b/tests/unit/benchmark/scenarios/lib/test_get_migrate_target_host.py
new file mode 100644
index 000000000..f046c92ea
--- /dev/null
+++ b/tests/unit/benchmark/scenarios/lib/test_get_migrate_target_host.py
@@ -0,0 +1,51 @@
+##############################################################################
+# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+import unittest
+import mock
+
+from yardstick.benchmark.scenarios.lib.get_migrate_target_host import GetMigrateTargetHost
+
+BASE = 'yardstick.benchmark.scenarios.lib.get_migrate_target_host'
+
+
+class GetMigrateTargetHostTestCase(unittest.TestCase):
+
+ @mock.patch('{}.openstack_utils.get_nova_client'.format(BASE))
+ @mock.patch('{}.GetMigrateTargetHost._get_migrate_host'.format(BASE))
+ @mock.patch('{}.GetMigrateTargetHost._get_current_host_name'.format(BASE))
+ def test_get_migrate_target_host(self,
+ mock_get_current_host_name,
+ mock_get_migrate_host,
+ mock_get_nova_client):
+ obj = GetMigrateTargetHost({}, {})
+ obj.run({})
+ self.assertTrue(mock_get_nova_client.called)
+ self.assertTrue(mock_get_current_host_name.called)
+ self.assertTrue(mock_get_migrate_host.called)
+
+ @mock.patch('{}.openstack_utils.get_nova_client'.format(BASE))
+ def test_get_migrate_host(self, mock_get_nova_client):
+ class A(object):
+ def __init__(self, service):
+ self.service = service
+ self.host = 'host4'
+
+ mock_get_nova_client().hosts.list_all.return_value = [A('compute')]
+ obj = GetMigrateTargetHost({}, {})
+ host = obj._get_migrate_host('host5')
+ self.assertTrue(mock_get_nova_client.called)
+ self.assertEqual(host, 'host4')
+
+
+def main():
+ unittest.main()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py b/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py
new file mode 100644
index 000000000..e7ba3ca73
--- /dev/null
+++ b/tests/unit/benchmark/scenarios/lib/test_get_numa_info.py
@@ -0,0 +1,106 @@
+##############################################################################
+# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+import unittest
+import mock
+
+from yardstick.benchmark.scenarios.lib.get_numa_info import GetNumaInfo
+
+BASE = 'yardstick.benchmark.scenarios.lib.get_numa_info'
+
+
+class GetNumaInfoTestCase(unittest.TestCase):
+
+ @mock.patch('{}.GetNumaInfo._check_numa_node'.format(BASE))
+ @mock.patch('{}.GetNumaInfo._get_current_host_name'.format(BASE))
+ @mock.patch('yaml.safe_load')
+ @mock.patch('yardstick.common.task_template.TaskTemplate.render')
+ def test_get_numa_info(self,
+ mock_render,
+ mock_safe_load,
+ mock_get_current_host_name,
+ mock_check_numa_node):
+ scenario_cfg = {
+ 'options': {
+ 'server': {
+ 'id': '1'
+ },
+ 'file': 'yardstick/ssh.py'
+ },
+ 'output': 'numa_info'
+ }
+ mock_safe_load.return_value = {
+ 'nodes': []
+ }
+ obj = GetNumaInfo(scenario_cfg, {})
+ obj.run({})
+ self.assertTrue(mock_get_current_host_name.called)
+ self.assertTrue(mock_check_numa_node.called)
+
+ @mock.patch('yardstick.ssh.SSH.from_node')
+ @mock.patch('{}.GetNumaInfo._get_current_host_name'.format(BASE))
+ @mock.patch('yaml.safe_load')
+ @mock.patch('yardstick.common.task_template.TaskTemplate.render')
+ def test_check_numa_node(self,
+ mock_render,
+ mock_safe_load,
+ mock_get_current_host_name,
+ mock_from_node):
+ scenario_cfg = {
+ 'options': {
+ 'server': {
+ 'id': '1'
+ },
+ 'file': 'yardstick/ssh.py'
+ },
+ 'output': 'numa_info'
+ }
+ mock_safe_load.return_value = {
+ 'nodes': []
+ }
+ data = """
+ <data>
+ </data>
+ """
+ mock_from_node().execute.return_value = (0, data, '')
+ obj = GetNumaInfo(scenario_cfg, {})
+ result = obj._check_numa_node('1', 'host4')
+ self.assertEqual(result, {'pinning': [], 'vcpupin': []})
+
+ @mock.patch('{}.change_obj_to_dict'.format(BASE))
+ @mock.patch('{}.get_nova_client'.format(BASE))
+ @mock.patch('yaml.safe_load')
+ @mock.patch('yardstick.common.task_template.TaskTemplate.render')
+ def test_get_current_host_name(self,
+ mock_render,
+ mock_safe_load,
+ mock_get_nova_client,
+ mock_change_obj_to_dict):
+ scenario_cfg = {
+ 'options': {
+ 'server': {
+ 'id': '1'
+ },
+ 'file': 'yardstick/ssh.py'
+ },
+ 'output': 'numa_info'
+ }
+ mock_get_nova_client().servers.get.return_value = ''
+ mock_change_obj_to_dict.return_value = {'OS-EXT-SRV-ATTR:host': 'host5'}
+
+ obj = GetNumaInfo(scenario_cfg, {})
+ result = obj._get_current_host_name('1')
+ self.assertEqual(result, 'host5')
+
+
+def main():
+ unittest.main()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/unit/benchmark/scenarios/lib/test_get_server.py b/tests/unit/benchmark/scenarios/lib/test_get_server.py
new file mode 100644
index 000000000..aebbf5416
--- /dev/null
+++ b/tests/unit/benchmark/scenarios/lib/test_get_server.py
@@ -0,0 +1,50 @@
+##############################################################################
+# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+import unittest
+import mock
+
+from yardstick.benchmark.scenarios.lib.get_server import GetServer
+
+
+class GetServerTestCase(unittest.TestCase):
+
+ @mock.patch('yardstick.common.openstack_utils.get_server_by_name')
+ @mock.patch('yardstick.common.openstack_utils.get_nova_client')
+ def test_get_server_with_name(self, mock_get_nova_client, mock_get_server_by_name):
+ scenario_cfg = {
+ 'options': {
+ 'server_name': 'yardstick_server'
+ },
+ 'output': 'status server'
+ }
+ obj = GetServer(scenario_cfg, {})
+ obj.run({})
+ self.assertTrue(mock_get_nova_client.called)
+ self.assertTrue(mock_get_server_by_name.called)
+
+ @mock.patch('yardstick.common.openstack_utils.get_nova_client')
+ def test_get_server_with_id(self, mock_get_nova_client):
+ scenario_cfg = {
+ 'options': {
+ 'server_id': '1'
+ },
+ 'output': 'status server'
+ }
+ mock_get_nova_client().servers.get.return_value = None
+ obj = GetServer(scenario_cfg, {})
+ obj.run({})
+ self.assertTrue(mock_get_nova_client.called)
+
+
+def main():
+ unittest.main()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/unit/benchmark/scenarios/lib/test_get_server_ip.py b/tests/unit/benchmark/scenarios/lib/test_get_server_ip.py
new file mode 100644
index 000000000..3d20d5439
--- /dev/null
+++ b/tests/unit/benchmark/scenarios/lib/test_get_server_ip.py
@@ -0,0 +1,41 @@
+##############################################################################
+# Copyright (c) 2017 Huawei Technologies Co.,Ltd and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+import unittest
+
+from yardstick.benchmark.scenarios.lib.get_server_ip import GetServerIp
+
+
+class GetServerIpTestCase(unittest.TestCase):
+ def test_get_server_ip(self):
+ scenario_cfg = {
+ 'options': {
+ 'server': {
+ 'addresses': {
+ 'net1': [
+ {
+ 'OS-EXT-IPS:type': 'floating',
+ 'addr': '127.0.0.1'
+ }
+ ]
+ }
+ }
+ },
+ 'output': 'ip'
+ }
+ obj = GetServerIp(scenario_cfg, {})
+ result = obj.run({})
+ self.assertEqual(result, {'ip': '127.0.0.1'})
+
+
+def main():
+ unittest.main()
+
+
+if __name__ == '__main__':
+ main()