版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 (作者:张华 发表于:2018-03-15)

  1. 沿用tox调用virtualenv自动创建的虚拟环境(virtualenv -p python3.5 .tox/py35)
source .tox/py35/bin/activate
sudo pip install --upgrade -r requirements.txt
sudo pip install --upgrade -r test-requirements.txt
  1. 使用unittest和nose运行测试。nose是对unittest的扩展,使得python的测试更加简单,nose自动发现测试代码并执行,nose提供了大量的插件,比如覆盖报表等。
python -m unittest -v unit_tests.test_neutron_utils.TestNeutronUtils.test_get_packages_ovs_newton
.tox/py35/bin/python nosetests -v unit_tests/test_neutron_utils.py:TestNeutronUtils.test_get_packages_ovs_newton

注意:上面采用nosetests运行时会报错,因为我们的测试采用了python3, 所以需要在安装了python3-nose之后(sudo apt-get install python3-nose python3-mock)再采用下列三种方式之一运行:

nosetests3 -v unit_tests/test_neutron_utils.py:TestNeutronUtils.test_restart_map_ovs_odl
/bak/work/charms/neutron-gateway/.tox/py35/bin/python /usr/local/bin/nosetests -v unit_tests/test_neutron_utils.py:TestNeutronUtils.test_get_packages_ovs_newton
python -m nose unit_tests/test_neutron_utils.py:TestNeutronUtils.test_restart_map_ovs_odl

但实际上仍然找不找nose模块,那是因为nose与virtualenv结合地不大好,在这个网页找着了答案(https://stackoverflow.com/questions/864956/problems-using-nose-in-a-virtualenv) - You need to have a copy of nose installed in the virtual environment. In order to force installation of nose into the virtualenv, even though it is already installed in the global site-packages, run pip install with the -I flag: pip install nose -I

  1. 上面使用unittest与nose运行测试的方式只是将结果输出到stdout,不便于分析。所以可以使用python-subunit模块来运行测试,并将测试结果通过subunit协议输出到文件中便于日后分析。因为subunit是基于二进制的不便于人眼看,所以可使用subunit2pyunit工具将其人类可读化。
python -m subunit.run discover |subunit2pyunit
python -m subunit.run discover -t ./ ./unit_tests |subunit2pyunit
python -m subunit.run unit_tests.test_neutron_utils.TestNeutronUtils. |subunit2pyunit
  1. 在大型应用中分析测试结果很重要,testrepository可以调用subunit来用python-subunit模块来运行测试,并将测试结果通过subunit协议输出到文件中,然后testrepository在些基础上有更多的分析,如分析哪些用例运行的时间最长,如显示失败的用例,如仅运行上次运行失败的用例。
testr init
testr run
testr run --parallel
$ cat .testr.conf
[DEFAULT]
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \${PYTHON:-python} -m subunit.run discover -t ./ ./unit_tests $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list
  1. tox用于创建虚拟python环境,也可以集成上面的testrepository(commands = ostestr {posargs})
$ cat tox.ini
[tox]
envlist = pep8,py27,py35
skipsdist = True[testenv]
setenv = VIRTUAL_ENV={envdir}PYTHONHASHSEED=0CHARM_DIR={envdir}AMULET_SETUP_TIMEOUT=5400
install_command =pip install --allow-unverified python-apt {opts} {packages}
commands = ostestr {posargs}
whitelist_externals = juju
passenv = HOME TERM AMULET_* CS_API_*[testenv:py27]
basepython = python2.7
deps = -r{toxinidir}/requirements.txt-r{toxinidir}/test-requirements.txt
commands = /bin/true[testenv:py35]
basepython = python3.5
deps = -r{toxinidir}/requirements.txt-r{toxinidir}/test-requirements.txt[testenv:pep8]
basepython = python2.7
deps = -r{toxinidir}/requirements.txt-r{toxinidir}/test-requirements.txt
commands = flake8 {posargs} hooks unit_tests tests actions libcharm-proof[flake8]
ignore = E402,E226
exclude = */helpers
  1. pydev使用virtualenv中的py35

    在eclipse的"Preferences -> Pydev -> Interpreters -> Python Interpreters"菜单中定义python35=/bak/work/charms/neutron-gateway/.tox/py35/bin/python,然后在工程上点右键从"Properties -> Pydev - Interpreter/Grammar"定义使用python35。注意,需要将/bak/work/charms/neutron-gateway/.tox/py35/lib/python3.5/site-packages也选到环境变量中,否则后面会报ImportError: No module named 'mock。
    为一个测试类定义"Python unitest"类型的"Debug Configurations", 也在其Interpreter选项卡中定义使用python35 (结果:eclipse似乎有bug,此处选择了python35后无法保存)
    所以无法成功,似乎是pydev与python3协作不大好。最后还是pudb好使(sudo pip install pudb, import pudb; pdb.set_trace())

  2. py27下的测试运行方法(如openstack), charm似乎只能用py36 (tox -r -epy36 && tox -e py36).

cat tox.ini
tox -r -epy27
tox -e py27,pep8
tox -e py27 neutron.tests.unit.agent.linux.test_keepalived
tox -e py27 neutron.tests.unit.agent.linux.test_keepalived.KeepalivedInstanceTestCase.test_remove_addresses_by_interface
mkdir /opt/stack && sudo chown -R hua /opt/stack
tox -e functional neutron.tests.functional.agent.l3.test_ha_router.L3HATestCase.test_keepalived_configuration
tox -e dsvm-fullstack
source .tox/functional/bin/activate
.tox/functional/bin/pip install -r requirements.txt
.tox/functional/bin/pip install -r test-requirements.txt
.tox/functional/bin/pip install -r neutron/tests/functional/requirements.txt
.tox/functional/bin/pip freeze |grep neutron
.tox/functional/bin/pip install 'neutron-lib==1.13.0'
OS_SUDO_TESTING=True .tox/functional/bin/python -m unittest -v neutron.tests.functional.agent.l3.test_ha_router.L3HATestCase.test_keepalived_configuration

有时如mitaka已经eol了, 例如它的origain-stable-mitaka这个分支都没有了, 这会导致运行’tox -r -epy27 '不成功, 那么可以手工执行:

virtualenv venv_mitaka
. venv_mitaka/bin/activate# pg_config executable not found
# Error: could not determine PostgreSQL version from '10.5'
sudo apt install python-setuptools python-dev libpython-dev libssl-dev python-pip libmysqlclient-dev libxml2-dev libxslt-dev libxslt1-dev libpq-dev git git-review libffi-dev gettext graphviz libjpeg-dev zlib1g-dev build-essential python-nose python-mock libssl1.0
sudo apt install python3.6 python3.6-dev python3-pip python3-dev python3-nose python3-mock
#sudo pip install --upgrade setuptools
#sudo pip3 install --upgrade setuptools
#sudo pip install --upgrade --force-reinstall pip virtualenv# Failed to install Cryptography - sudo apt install libssl1.0
# No module named dulwich - ./venv/bin/pip install dulwich
# unittest has no attribute 'virt' -
# ./venv_ocata/bin/pip install -c https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/ocata .
./venv_mitaka/bin/pip install -c https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=mitaka-eol .
./venv_mitaka/bin/pip install -r requirements.txt
./venv_mitaka/bin/pip install -r test-requirements.txtfind . -name "*.pyc" -exec rm -rf {} \;git clone https://github.com/openstack/oslo.cache.git
cd oslo.cache && git checkout -b mitaka mitaka-eol
../nova/venv/bin/pip install -r requirements.txt
../nova/venv/bin/pip install -r test-requirements.txt# dogpile can't cannot import name threading - venv/bin/pip uninstall dogpile.cache dogpile && venv/bin/pip install dogpile.cache
venv_mitaka/bin/python -m subunit.run discover ./nova/tests/unit/compute |subunit2pyunit
venv_mitaka/bin/python -m subunit.run nova.tests.unit.compute.test_compute |subunit2pyunit
venv_mitaka/bin/python -m subunit.run nova.tests.unit.compute.test_compute.ComputeAPITestCase.test_attach_volume |subunit2pyunit
venv_mitaka/bin/python -m unittest -v nova.tests.unit.compute.test_compute  #make sure the package nova.tests.virt existsvenv_mitaka/bin/python -m unittest -v nova.tests.unit.virt.libvirt.test_driver.LibvirtConnTestCase.test_check_can_live_migrate_dest_all_pass_with_over_commit#venv/bin/pep8
venv/bin/flake8

对于horizion的测试:

https://docs.openstack.org/horizon/latest/contributor/testing.html
tox
tox -e py27 -- openstack_dashboard.test.views:DashboardViewsTest.test_urls_ngdetails

charm的unit test:

# charm unit test
sudo pip install virtualenv
sudo pip install --upgrade pip
proxychains tox -r -epy36
source .tox/py36/bin/activate
python -m subunit.run discover -t ./ ./unit_tests |subunit2pyunit
python -m subunit.run unit_tests.test_neutron_ovs_context.L3AgentContextTest |subunit2pyunit
python -m subunit.run unit_tests.test_neutron_ovs_context.L3AgentContextTest.test_dvr_enabled |subunit2pyunit
OS_SUDO_TESTING=True .tox/py36/bin/python -m unittest -v unit_tests.test_neutron_ovs_context.L3AgentContextTest.test_dvr_enabled

20200714更新

今天,发现上面的subunit的方法不work了, 例如运行下面三行报这个错"TypeError: test_data_port_name() missing 1 required positional argument: ‘config’"

tox -r -epy38
source .tox/py38/bin/activate
python -m subunit.run unit_tests.test_neutron_ovs_context.OVSPluginContextTest.test_data_port_name

估计是现在全面移到python3了,subunit和python3搭配不大好吧, 试了一下, 下面两种方法还可以用:

OS_SUDO_TESTING=True .tox/py3/bin/python -m unittest -v subunit.run unit_tests.test_neutron_ovs_context.OVSPluginContextTest.test_data_port_name
nosetests3 unit_tests/test_neutron_ovs_context.py:OVSPluginContextTest.test_data_port_name

20201026更新

#https://review.opendev.org/#/c/749175/
cd nova
tox
#tox -r -epy38
#source .tox/py38/bin/activate
tox -epy38 nova.tests.unit.pci.test_stats.PciDeviceStatsWithTagsTestCase.test_update_device
.tox/py38/bin/python -m unittest nova.tests.unit.pci.test_stats.PciDeviceStatsWithTagsTestCase.test_update_devicetox -e functional nova.tests.functional.libvirt.test_pci_sriov_servers.SRIOVServersTest.test_create_server_after_change_in_nonsriov_pf_to_sriov_pf
.tox/functional/bin/python -m unittest -v nova.tests.functional.libvirt.test_pci_sriov_servers.SRIOVServersTest.test_create_server_after_change_in_nonsriov_pf_to_sriov_pf#NOTE: can use rpdb to debug nova/tests/functional/libvirt/test_pci_sriov_servers.py
.tox/functional/bin/pip3 install rpdb
import rpdb;rpdb.set_trace()
nc 127.0.0.1 4444python3 -m flake8

unit test怎么写

下列代码是初始为https://bugs.launchpad.net/charm-octavia/+bug/1915512 写的,它是错的因为在删除一个unit时,leader马上会运行下列代码仍然会将正在删除但还未删除的unit弄进去所以是错的。

+        running_units.append(ch_core.hookenv.local_unit().replace('/', '-'))
+        for u in ch_core.hookenv.iter_units_for_relation_name('cluster'):
+            running_units.append(u.unit.replace('/', '-'))

但是这个代码刚好可以演示unit test怎么写。

From 02d8c5185afc6aebfa03d58aa1fe90be4b0d200f Mon Sep 17 00:00:00 2001
From: xxxx
Date: Fri, 23 Apr 2021 18:10:32 +0800
Subject: [PATCH] Delete hm prt on unit removalJuju has no pre hook to clean up hm port resources first before removing
one octavia unit. This patch will do it in another way, the leader unit finds
all running units by querying 'cluster' relations, then finds all mapping
between IPv6 management address and unit name by querying DB, finally
deletes hm ports for missing units.Closes-Bug: 1915512
Change-Id: I88c61b8d2d0b573df7df071ed7978e83b6803c5c
---src/lib/charm/openstack/api_crud.py           | 26 ++++++++++++++++++-src/reactive/octavia_handlers.py              | 26 ++++++++++++++++++-.../test_lib_charm_openstack_api_crud.py      | 25 +++++++++++++++---unit_tests/test_octavia_handlers.py           | 16 +++++++-----4 files changed, 81 insertions(+), 12 deletions(-)diff --git a/src/lib/charm/openstack/api_crud.py b/src/lib/charm/openstack/api_crud.py
index 81c8b31..a0209b8 100644
--- a/src/lib/charm/openstack/api_crud.py
+++ b/src/lib/charm/openstack/api_crud.py
@@ -251,6 +251,26 @@ def lookup_hm_port(nc, local_unit_name):return+def delete_hm_port(identity_service, local_unit_name):
+    """Delete port object for Octavia hm port for local unit.
+
+    :param nc: Neutron Client object
+    :type nc: neutron_client.Client
+    :param local_unit_name: Name of juju unit, used to build tag name for port
+    :type local_unit_name: str
+    :returns: None
+    :raises: DuplicateResource or any exceptions raised by Keystone and Neutron
+             clients.
+    """
+    session = session_from_identity_service(identity_service)
+    try:
+        nc = init_neutron_client(session)
+        port = lookup_hm_port(nc, local_unit_name)
+        nc.delete_port(port['id'])
+    except NEUTRON_TEMP_EXCS as e:
+        raise APIUnavailable('neutron', 'ports', e)
+
+def get_hm_port(identity_service, local_unit_name, local_unit_address,host_id=None):"""Get or create a per unit Neutron port for Octavia Health Manager.
@@ -507,12 +527,16 @@ def get_port_ips(identity_service):except NEUTRON_TEMP_EXCS as e:raise APIUnavailable('neutron', 'ports', e)+    neutron_ip_unit_map = dict()neutron_ip_list = []for port in resp['ports']:for ip_info in port['fixed_ips']:neutron_ip_list.append(ip_info['ip_address'])
+            unitname = port['name'].replace(
+                'octavia-health-manager-', '').replace('-listen-port', '')
+            neutron_ip_unit_map[unitname] = ip_info['ip_address']-    return neutron_ip_list
+    return neutron_ip_list, neutron_ip_unit_mapdef get_mgmt_network(identity_service, create=True):
diff --git a/src/reactive/octavia_handlers.py b/src/reactive/octavia_handlers.py
index c1f57d2..cbb7d67 100644
--- a/src/reactive/octavia_handlers.py
+++ b/src/reactive/octavia_handlers.py
@@ -179,7 +179,9 @@ def update_controller_ip_port_list():leader_ip_list = leadership.leader_get('controller-ip-port-list') or []try:
-        neutron_ip_list = sorted(api_crud.get_port_ips(identity_service))
+        neutron_ip_list, neutron_ip_unit_map = api_crud.get_port_ips(
+            identity_service)
+        neutron_ip_list = sorted(neutron_ip_list)except api_crud.APIUnavailable as e:ch_core.hookenv.log('Neutron API not available yet, deferring ''port discovery. ("{}")'
@@ -187,6 +189,28 @@ def update_controller_ip_port_list():level=ch_core.hookenv.DEBUG)returnif neutron_ip_list != sorted(leader_ip_list):
+        # delete hm port which may be caused by 'juju remove-unit <octavia>'
+        missing_units = []
+        running_units = []
+        db_units = neutron_ip_unit_map.keys()
+        running_units.append(ch_core.hookenv.local_unit().replace('/', '-'))
+        for u in ch_core.hookenv.iter_units_for_relation_name('cluster'):
+            running_units.append(u.unit.replace('/', '-'))
+        for unit_name in db_units:
+            if unit_name not in running_units:
+                missing_units.append(unit_name)
+        for unit_name in missing_units:
+            neutron_ip_list.remove(neutron_ip_unit_map.get(unit_name))
+            try:
+                ch_core.hookenv.log('deleting hm port for missing '
+                                    'unit {}'.format(unit_name))
+                api_crud.delete_hm_port(identity_service, unit_name)
+            except api_crud.APIUnavailable as e:
+                ch_core.hookenv.log('Neutron API not available yet, deferring '
+                                    'port discovery. ("{}")'
+                                    .format(e),
+                                    level=ch_core.hookenv.DEBUG)
+                returnleadership.leader_set({'controller-ip-port-list': json.dumps(neutron_ip_list)})diff --git a/unit_tests/test_lib_charm_openstack_api_crud.py b/unit_tests/test_lib_charm_openstack_api_crud.py
index cbc5776..5ca2628 100644
--- a/unit_tests/test_lib_charm_openstack_api_crud.py
+++ b/unit_tests/test_lib_charm_openstack_api_crud.py
@@ -247,6 +247,19 @@ class TestAPICrud(test_utils.PatchHelper):nc.update_port.assert_called_with('fake-port-uuid',{'port': {'admin_state_up': True}})+    def test_delete_hm_port(self):
+        self.patch_object(api_crud, 'session_from_identity_service')
+        self.patch_object(api_crud, 'init_neutron_client')
+        identity_service = mock.MagicMock()
+        nc = mock.MagicMock()
+        self.init_neutron_client.return_value = nc
+        nc.list_ports.return_value = {'ports': [{'id': 'fake-port-uuid'}]}
+        api_crud.delete_hm_port(identity_service, 'fake-unit-name')
+        self.init_neutron_client.assert_called_once_with(
+            self.session_from_identity_service())
+        nc.list_ports.asssert_called_with(tags='charm-octavia-fake-unit-name')
+        nc.delete_port.assert_called_with('fake-port-uuid')
+def test_setup_hm_port(self):self.patch('subprocess.check_output', 'check_output')self.patch('subprocess.check_call', 'check_call')
@@ -305,14 +318,18 @@ class TestAPICrud(test_utils.PatchHelper):self.init_neutron_client.return_value = ncnc.list_ports.return_value = {'ports': [
-                {'fixed_ips': [{'ip_address': '2001:db8:42::42'}]},
-                {'fixed_ips': [{'ip_address': '2001:db8:42::51'}]},
+                {'name': 'octavia-health-manager-lb-0-listen-port',
+                 'fixed_ips': [{'ip_address': '2001:db8:42::1'}]},
+                {'name': 'octavia-health-manager-lb-1-listen-port',
+                 'fixed_ips': [{'ip_address': '2001:db8:42::2'}]},],}identity_service = mock.MagicMock()
+        fake_ip_list = ['2001:db8:42::1', '2001:db8:42::2']
+        fake_ip_unit_map = {'lb-0': '2001:db8:42::1', 'lb-1': '2001:db8:42::2'}
+        fake_return_value = (fake_ip_list, fake_ip_unit_map)self.assertEquals(api_crud.get_port_ips(identity_service),
-                          ['2001:db8:42::42',
-                           '2001:db8:42::51'])
+                          fake_return_value)self.init_neutron_client.assert_called_once_with(self.session_from_identity_service())diff --git a/unit_tests/test_octavia_handlers.py b/unit_tests/test_octavia_handlers.py
index 4e3a3c5..8b2560d 100644
--- a/unit_tests/test_octavia_handlers.py
+++ b/unit_tests/test_octavia_handlers.py
@@ -171,16 +171,20 @@ class TestOctaviaHandlers(test_utils.PatchHelper):self.patch('charms.leadership.leader_set', 'leader_set')self.patch('charms.leadership.leader_get', 'leader_get')self.patch_object(handlers.api_crud, 'get_port_ips')
-        self.get_port_ips.return_value = [
-            '2001:db8:42::42',
-            '2001:db8:42::51',
-        ]
+        fake_ip_list = ['2001:db8:42::1', '2001:db8:42::2']
+        fake_ip_unit_map = {'lb-0': '2001:db8:42::1', 'lb-1': '2001:db8:42::2'}
+        self.get_port_ips.return_value = [fake_ip_list, fake_ip_unit_map]
+        self.patch_object(
+            handlers.ch_core.hookenv, 'iter_units_for_relation_name')
+        fake_relation_name = mock.MagicMock()
+        fake_relation_name.unit = 'lb/0'
+        self.iter_units_for_relation_name.return_value = [fake_relation_name]
+        self.patch_object(handlers.api_crud, 'delete_hm_port')handlers.update_controller_ip_port_list()self.leader_set.assert_called_once_with({'controller-ip-port-list': json.dumps([
-                    '2001:db8:42::42',
-                    '2001:db8:42::51',
+                    '2001:db8:42::1',])})def test_render(self):
--
2.25.1

Zaza functional test

functest-run-suite读tests.yaml运行测试,测试的每个象位可独立隔离运行。
https://zaza.readthedocs.io/en/latest/runningcharmtests.html

# octavia测试必须enable SG
juju bootstrap stsstack --no-gui --bootstrap-series focal --config use-default-secgroup=true --config network=zhhuabj_port_sec_enabled --config image-stream=daily --config image-metadata-url=http://10.230.19.58/swift/v1/simplestreams/data/ zhhuabj-sg
juju model-defaults use-default-secgroup=true network=zhhuabj_port_sec_enabled image-stream=daily image-metadata-url=http://10.230.19.58/swift/v1/simplestreams/data/
juju switch zhhuabj-sg# 必须运行在有juju环境的节点上如bastion,
# git clone https://github.com/openstack-charmers/zaza.git
cd ~/charms
# 不能用reactive源码,必须得使用完整的octavia charm
# 因为upload charm /home/ubuntu/charms/octavia for series focal
#git clone https://github.com/openstack/charm-octavia.git charm-octavia
charm pull octavia
cd octavia
tox -e func-noop
source .tox/func-noop/bin/activate
ls tests/bundles/focal-ussuri-ha.yaml
ls tests/bundles/overlays/focal-ussuri-ha.yaml.j2
ls tests/tests.yaml
export OS_VIP00=10.0.0.122         #because we are using zhhuabj-sg
functest-run-suite -b focal-ussuri-ha#下面是分步运行的步骤,但似乎不work
functest-prepare -m testmodel
juju switch testmodel
export OS_VIP00=10.0.0.122
#注意:也需要调整bundle中的mem大小,以免quota exceed
functest-deploy -m testmodel -b ./tests/bundles/focal-ussuri-ha.yaml
source ~/xxx/openstack/novarc
functest-configure -m testmodel
#run test
functest-test -m testmodel
functest-destroy -m testmodel或
juju bootstrap stsstack --no-gui --bootstrap-series focal --config use-default-secgroup=true --config network=zhhuabj_port_sec_enabled --config image-stream=daily --config image-metadata-url=http://10.230.19.58/swift/v1/simplestreams/data/ zhhuabj-sg
juju model-defaults use-default-secgroup=true network=zhhuabj_port_sec_enabled image-stream=daily image-metadata-url=http://10.230.19.58/swift/v1/simplestreams/data/

20220106

tox -e func-target ceph:focal-ussuri

20220520 - 调试pip依赖问题

实际上是这个lp bug : https://bugs.launchpad.net/aodh/+bug/1973116
aodh只有在focal yoga中才遇到这个运行’tox -epy39’ hang在那的问题.

sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
sudo apt install python3.9 python3.9-dev python3.9-distutils -y
alias python=python3.9
alias python3=python3.9
sudo apt install build-essential -y
sudo apt install python3-pip python3-dev python3-nose python3-mock -y
sudo apt install python3-setuptools libpython3-dev libssl-dev \libxml2-dev libxslt-dev libxslt1-dev libpq-dev git git-review \libffi-dev gettext graphviz libjpeg-dev zlib1g-dev psycopg2-binary -y
sudo apt install postgresql-server-dev-all libmysqlclient-dev -y
git clone https://opendev.org/openstack/aodh.git -b stable/yoga
cd aodh
tox -e py39#sudo dpkg -i --force-overwrite /var/cache/apt/archives/python3-distutils_3.10.4-0ubuntu1_all.deb
#sudo apt-get -f install

那是因为https://opendev.org/openstack/requirements/raw/branch/stable/yoga/upper-constraints.txt 中缺少了:

setuptools===60.9.3;python_version=='3.9'

所以focal master与focal yoga都使用了setuptools=62.1.0, 而这个62.1.0和testr一起工作没问题,但和non-testr一起工作则有问题.刚好master分支才开始使用testr (https://opendev.org/openstack/aodh/commit/63c3466f291996c3d5f99e307f8784abeeb1ef78).
所以这个focal master没这个问题,而focal yoga则有这个问题.
鉴于修改openstack requirement工程估计不可行,所以提了一个patch来修改aodh自己的requirement.txt (https://review.opendev.org/c/openstack/aodh/+/842697)

tox -e generate
.tox/generate/bin/generate-constraints -b blacklist.txt -r global-requirements.txt -p python3.6 -p python3.7 -p python3.8 -p python3.9 '>' upper-constraints.txt

其他测试手段:

wget https://releases.openstack.org/constraints/upper/yoga -O yoga.txt
.tox/py39/bin/pip install -r yoga.txt
.tox/py39/bin/pip install -r requirements.txt
.tox/py39/bin/pip install -r test-requirements.txt
sudo apt install subunit -y
.tox/py39/bin/python -m subunit.run discover -t ./ ./aodh/tests/unit |subunit2pyunit# run-tests.sh
sudo apt install python3-os-testr -y
export OS_TEST_PATH=aodh/tests/unit
.tox/py39/bin/python setup.py testr --slowest --testr-args="--subunit $*" | subunit-trace -f

也试过二分,这个问题与二分无关:

二分法:https://zhhuabj.blog.csdn.net/article/details/53676439
git log --tags --simplify-by-decoration --pretty="format:%ci %d"
git log --since=2015-01-27 --before=2015-05-04 --oneline src/qemu/qemu_migration.c |wc -l# 13.0.0 is xena, 14.0.0 is yoga
git bisect start
git bisect bad 14.0.0
$ git bisect good 13.0.0
Bisecting: 5 revisions left to test after this (roughly 3 steps)
[9fa5ad045b41f90a1f80aca5d8a46a5abbd848c9] Merge "Introduce Guru Meditation Reports into Aodh"$ git bisect bad
Bisecting: 2 revisions left to test after this (roughly 1 step)
[0d6c43811dc1b531c38bf1fd9c4d345f30ac16b5] Add Python3 yoga unit tests

温故OpenStack中的测试(by Joshua)相关推荐

  1. 基于OpenStack的云测试平台

    1.云测试平台技术架构 \\ (一)云测试平台搭建的背景 \\ 笔者目前处于一家国内核心金融机构的测试中心部门,随着公司新业务的开展以及大数据时代的到来,金融软件系统逐步趋向于分布式.高稳定性.高可用 ...

  2. 测试驱动开发与行为驱动开发中的测试先行方法

    Gil Zilberfeld将在 Agile Practitioners会议上举办小型研讨会,讨论测试先行(test first)方法,测试驱动开发(TDD)和行为驱动开发(BDD)的基础. \\ \ ...

  3. Python中的测试工具

    当我们在写程序的时候,我们需要通过测试来验证程序是否出错或者存在问题,但是,编写大量的测试来确保程序的每个细节都没问题会显得很繁琐.在Python中,我们可以借助一些标准模块来帮助我们自动完成测试过程 ...

  4. python代码测试工具模块_详解Python中的测试工具

    当我们在写程序的时候,我们需要通过测试来验证程序是否出错或者存在问题,但是,编写大量的测试来确保程序的每个细节都没问题会显得很繁琐.在Python中,我们可以借助一些标准模块来帮助我们自动完成测试过程 ...

  5. Spring Boot中的测试

    文章目录 简介 添加maven依赖 Repository测试 Service测试 测试Controller @SpringBootTest的集成测试 Spring Boot中的测试 简介 本篇文章我们 ...

  6. junit 测试执行顺序_JUnit 5中的测试执行顺序

    junit 测试执行顺序 一般实践认为,自动化测试应能够独立运行且无特定顺序,并且测试结果不应依赖于先前测试的结果. 但是在某些情况下,可以证明特定的测试执行顺序是正确的,尤其是在集成或端到端测试中. ...

  7. JUnit 5中的测试执行顺序

    一般实践认为,自动化测试应能够独立运行且无特定顺序,并且测试结果不应依赖于先前测试的结果. 但是在某些情况下,可以证明特定的测试执行顺序是正确的,尤其是在集成或端到端测试中. 默认情况下,在JUnit ...

  8. 中resource文件夹的作用_冲突与碰撞:OpenStack中的虚拟机和裸机

    冲突与碰撞:OpenStack中的虚拟机和裸机 要虚拟化还是非虚拟化? 如果您追求性能,那么就没有争议--裸机仍然胜过虚拟机:特别是对于I/O密集型应用程序.但是,除非您可以保证充分利用它,否则是有代 ...

  9. 简单的11步在Laravel中实现测试驱动开发

    测试驱动开发(英语:Test-driven development,缩写为TDD)是一种软件开发过程中的应用方法,由极限编程中倡导,以其倡导先写测试程序,然后编码实现其功能得名. 下文是我在Mediu ...

最新文章

  1. python manager与basemanager_使用Python多处理管理器(BaseManager/SyncManager)与远程计算机共享队列时出现管道中断...
  2. Azure 应用服务、虚拟机、Service Fabric 和云服务的比较
  3. spring加载application.xml异常
  4. 面包板如何接线电源 图解_互感器、电能表接线和原理讲解
  5. EasyUI Combobox 设置默认值
  6. python能做什么游戏-Python有做大型游戏的潜力吗?
  7. C#中水晶按钮的程序生成【转载】
  8. 如何批量识别二维码图片信息?
  9. Variable Declarations
  10. [zz] 导致你创业失败的18个错误 [2007-05-03]
  11. 磁盘管理器显示状态良好 计算机不显示,win7系统打开磁盘管理显示显示状态良好(有危险)的解决方法...
  12. 马尔代夫的华为“新4军”
  13. 抖音TikTok国际版可切换全球任意地区
  14. 什么是泊松分布?什么是泊松过程?
  15. BA-中央空调冰蓄冷(视频)
  16. yum安装telnet详解
  17. MUSIC算法-呼吸心跳信号检测方法(五)
  18. alex机器人 ser_机器人Alex
  19. 【傅老师DarkSouls第一季】05
  20. BZOJ 4244 邮戳拉力赛

热门文章

  1. HTML总结2(路径与超链接)
  2. 通信人的经典语录,第一条就扎心了……
  3. 小米6--安装Charles证书
  4. 小米笔记本pro macOS Mojave使用体验
  5. 当瑞幸“咖啡的小世界”遇上星巴克“全世界的咖啡”
  6. spring事务注解@Transactional参数详解
  7. 手机如何裁剪视频?分享三个裁剪方法给你
  8. 飞机可以连wifi 互联网+航空机会来了
  9. transform函数转换大小写
  10. 《神经质人格》摘录(第十章)