OpenStack 單元測試

OpenStack 單元測試

OpenStack開發——單元測試

      本文將介紹OpenStack單元測試的部分。本文將重點講述Python和OpenStack中的單元測試的生態環境。

      openstack社區推崇的是使用tox進行單元測試,tox只須要配置好tox.ini就能夠了,比較靈活也比較簡單。在opensatck的項目代碼中也有包含tox配置,安裝好tox以後就能夠對項目代碼進行單元測試

經過demo學習OpenStack開發——單元測試
  單元測試的重要性
  單元測試工具
     unittest
     mock
     testtools
     fixtures
     testscenarios
     subunit
     testrepository
     coverage
     tox
     單元測試工具小結
  Keystone的單元測試框架
     使用tox進行測試環境管理
     使用testrepository管理測試的運行
  單元測試用例的代碼架構
  總結
  系列後記

單元測試工具

    Python的單元測試工具不少,爲單元測試提供不一樣方面的功能。OpenStack的項目也基本把如今流行的單元測試工具都用全了。單元測試能夠說是入門OpenStack開發的最難的部分,也是最後一千米。本文,咱們就介紹一下在OpenStack中會用到的單元測試的工具。因爲數量不少,不可能詳細介紹,所以主要作一些概念和用途上的介紹。

unittest

          unittest是Python的標準庫,提供了最基本的單元測試功能,包括單元測試運行器(簡稱runner)和單元測試框架。項目的單元測試代碼的測試類能夠繼承unittest.TestCase類,這樣這個類就可以被runner發現而且執行。同時,unittest.TestCase這個類還定義了setUp(),tearDown(),setUpClass()和tearDownClass()方法,是用來運行單元測試前的設置工做代碼和單元測試後的清理工做代碼,這個也是全部Python代碼遵照的規範,因此第三方的單元測試庫和框架也都遵循這個規範。unittest庫也提供了一個runner,可使用$ python -m unittest test_module的命令來執行某個模塊的單元測試。另外,在Python中指定要運行的單元測試用例的完整語法是:path.to.your.module:ClassOfYourTest.test_method。unittest是學習Python單元測試最基本也最重要的一個庫,完整的說明請查看查看官方文檔

mock

             mock也是另外一個重要的單元測試庫,在Python 2中是做爲一個第三方庫被使用的,到Python 3時,就被歸入了標準庫,可見這個庫的重要性。簡單的說,mock就是用來模擬對象的行爲,這樣在進行單元測試的時候,能夠指定任何對象的返回值,便於測試對外部接口有依賴的代碼。關於mock的使用,能夠查看我以前寫的這篇文章Python Mock的入門

testtools

             testtools是個unittest的擴展框架,主要是在unittest的基礎上提供了更好的assert功能,使得寫單元測試更加方便。具體能夠查看文檔

fixtures

         fixture的意思是固定裝置,在Python的單元測試中,是指某段能夠複用的單元測試setUp和tearDown代碼組合。一個fixture通常用來實現某個組件的setUp和tearDown邏輯,好比測試前要先建立好某些數據,測試後要刪掉這些數據,這些操做就能夠封裝到一個fixture中。這樣不一樣的測試用例就不用重複寫這些代碼,只要使用fixture便可。fixtures模塊是一個第三方模塊,提供了一種簡單的建立fixture類和對象的機制,而且也提供了一些內置的fixture。具體的使用方法能夠查看官方文檔

testscenarios

         testscenarios模塊知足了場景測試的需求。它的基本用法是在測試類中添加一個類屬性scenarios,該屬性是一個元組,定義了每一種場景下不一樣的變量的值。好比說你測試一段數據訪問代碼,你須要測試該代碼在使用不一樣的驅動時,好比MongoDB、SQL、File,是否都能正常工做。咱們有三種辦法:

最笨的辦法是爲不一樣的驅動把同一個測試用例編寫3遍。
 比較好的辦法是,編寫一個統一的非測試用例方法,接收driver做爲參數,執行測試邏輯,而後再分別編寫三個測試用例方法去調用這個非測試用例方法。
 更好的辦法就是使用testscenarios模塊,定義好scenarios變量,而後實現一個測試用例方法。
 testscenarios模塊在OpenStack Ceilometer中被大量使用。更多的信息能夠查看文檔

subunit

          subunit是一個用於傳輸單元測試結果的流協議。通常來講,運行單元測試的時候是把單元測試的結果直接輸出到標準輸出,可是若是運行大量的測試用例,這些測試結果就很難被分析。所以就可使用python-subunit模塊來運行測試用例,而且把測試用例經過subunit協議輸出,這樣測試結果就能夠被分析工具聚合以及分析。python-subunit模塊自帶了一些工具用來解析subunit協議,好比你能夠這樣運行測試用例:$ python -m subunit.run test_module | subunit2pyunit,subunit2pyunit命令會解析subunit協議,而且輸出到標準輸出。關於subunit的更多信息,請查看官方文檔

testrepository

          OpenStack中使用testrepository模塊管理單元測試用例。當一個項目中的測試用例不少時,如何更有效的處理單元測試用例的結果就變得很重要。testrepository的出現就是爲了解決這個問題。testrepository使用python-subunit模塊來運行測試用例,而後分析subunit的輸出並對測試結果進行記錄(記錄到本地文件)。舉例來講,testrepository容許你作這樣的事情:

知道哪些用例運行時間最長
 顯示運行失敗的用例
 從新運行上次運行失敗的用例
 testrepository的更多信息,請查看官方文檔

coverage

           coverage是用來計算代碼運行時的覆蓋率的,也就是統計多少代碼被執行了。它能夠和testrepository一塊兒使用,用來統計單元測試的覆蓋率,在運行完單元測試以後,輸出覆蓋率報告。具體的使用方法能夠查看官方文檔

tox

           tox是用來管理和構建虛擬環境(virtualenv)的。對於一個項目,咱們須要運行Python 2.7的單元測試,也須要運行Python 3.4的單元測試,還須要運行PEP8的代碼檢查。這些不一樣的任務須要依賴不一樣的庫,因此須要使用不一樣的虛擬環境。使用tox的時候,咱們會在tox的配置文件tox.ini中指定不一樣任務的虛擬環境名稱,該任務在虛擬環境中須要安裝哪些包,以及該任務執行的時候須要運行哪些命令。更多信息,請查看官方文檔。

 

單元測試工具小結

     本文介紹了OpenStack中經常使用的單元測試工具的基本用途,但願你們對這些工具備個大概的認識。這裏咱們能夠按照類別總結一下這些工具:

  • 測試環境管理: tox

          使用tox來管理測試運行的虛擬環境,而且調用testrepository來執行測試用例。

  • 測試用例的運行和管理: testrepository, subunit, coverage

          testrepository調用subunit來執行測試用例,對測試結果進行聚合和管理;調用coverage來執行代碼覆蓋率的計算。

  • 測試用例的編寫: unittest, mock, testtools, fixtures, testscenarios

          使用testtools做爲全部測試用例的基類,同時應用mock, fixtures, testscenarios來更好的編寫測試用例。

     接下來咱們來分析Keystone項目的單元測試框架,可讓你看到在OpenStack的實際項目中,這些工具是如何被使用的。

 

 

Keystone的單元測試框架

      如今,咱們以Keystone項目爲例,來看下真實項目中的單元測試是如何架構的。咱們採用自頂向下的方式,先從最上層的部分介紹起。

安裝tox (Centos 7)

1.安裝pip

easy_install pip

2.設置pip源

pip官方源下載比較慢,咱們能夠設置一個國內的源。

$ mkdir ~/.pip

$ vim~/.pip/pip.conf

[global]

timeout =6000

index-url= http://mirrors.aliyun.com/pypi/simple

[install]

trusted-host= mirrors.aliyun.com

3.安裝tox

pip install tox

3.安裝依賴插件

yum install gcc libffi-devel python-devel openssl-devel
yum install git

yum install mysql-devel
yum install postgresql postgresql-devel python-devel
yum install libxslt-devel libxml2-devel

使用tox進行測試環境管理

大部分狀況下,咱們都是經過tox命令來執行單元測試的,而且傳遞環境名稱給tox命令:

[root@qqzhangl keystone]# tox -e py27

tox命令首先會讀取項目根目錄下的tox.ini文件,獲取相關的信息,而後根據配置構建virtualenv,保存在.tox/目錄下,以環境名稱命名:

[root@qqzhangl keystone] ls .tox log pep8 py27

除了log目錄,其餘的都是普通的virtualenv環境,你能夠本身查看一下內容。咱們來看下py27這個環境的相關配置(在tox.ini)中,我直接在內容上註釋一些配置的用途:

[tox]

minversion = 1.6

skipsdist = Trueenvlist = py34,py27,pep8,docs,genconfig,releasenotes 

[testenv] # testenv是默認配置,若是某個配置在環境專屬的section中沒有,就從這個section中讀取

usedevelop = True # usedevelop表示安裝virtualenv的時候,本項目本身的代碼採用開發模式安裝,

也就是不會拷貝代碼到virtualenv目錄中,只是作個連接

install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/mitaka} {opts} {packages} # install_command表示構建環境的時候要執行的命令,通常是使用pip安裝

setenv = VIRTUAL_ENV={envdir}  

deps = -r{toxinidir}/test-requirements.txt

       .[ldap,memcache,mongodb]  # deps指定構建環境的時候須要安裝的依賴包,這個就是做爲pip命令的參數 # keystone這裏使用的寫法比較特殊一點,第二行的.[ldap,memcache,mongodb]是兩個依賴,

第一個點'.'表示當前項目的依賴,也就是requirements.txt,第二個部分[ldap,memcache,mongodb]

表示extra,是在setup.cfg文件中定義的一個段的名稱,該段下定義了額外的依賴,這些能夠查看PEP0508# 通常的項目這裏會採用更簡單的方式來書寫,直接安裝兩個文件中的依賴:

#    -r{toxinidir}/requirements.txt

#    -r{toxinidir}/test-requirements.txt

commands =

  find keystone -type f -name "*.pyc" -delete

  bash tools/pretty_tox.sh '{posargs}' # commands表示構建好virtualenv以後要執行的命令,這裏調用了tools/pretty_tox.sh來執行測試

whitelist_externals =

  bash

  find

passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY PBR_VERSION

[testenv:py34]   # 這個section是爲py34環境定製某些配置的,沒有定製的配置,從[testenv]讀取

commands =

  find keystone -type f -name "*.pyc" -delete

  bash tools/pretty_tox_py3.sh

[testenv:legacy_drivers]

deps = -r{toxinidir}/test-requirements.txt

       nose

       .[ldap,memcache,mongodb]

commands =

  # Run each legacy test separately, to avoid SQL model redefinitions

  find keystone -type f -name "*.pyc" -delete

  nosetests -v \

      keystone/tests/unit/backend/legacy_drivers/assignment/V8/sql.py

  nosetests -v \

      keystone/tests/unit/backend/legacy_drivers/role/V8/sql.py

  nosetests -v \

      keystone/tests/unit/backend/legacy_drivers/federation/V8/api_v3.py

  nosetests -v \

      keystone/tests/unit/backend/legacy_drivers/resource/V8/sql.py

[testenv:pep8] #代碼編碼規範

deps =

     .[bandit]

     {[testenv]deps}

commands =

  flake8

  # Run bash8 during pep8 runs to ensure violations are caught by

  # the check and gate queues

  bashate examples/pki/gen_pki.sh

  # Check that .po and .pot files are valid.

  bash -c "find keystone -type f -regex '.*\.pot?' -print0| \

           xargs -0 -n 1 msgfmt --check-format -o /dev/null"

  # Run security linter

  bandit -r keystone -x tests

[testenv:bandit]

# NOTE(browne): This is required for the integration test job of the bandit

# project. Please do not remove.

deps = .[bandit]

commands = bandit -r keystone -x tests

[testenv:cover] #代碼覆蓋率

# Also do not run test_coverage_ext tests while gathering coverage as those

# tests conflict with coverage.

# NOTE(sdague): this target does not use constraints because

# upstream infra does not yet support it. Once that's fixed, we can

# drop the install_command.

install_command = pip install -U --force-reinstall {opts} {packages}

commands =

  find keystone -type f -name "*.pyc" -delete

  python setup.py testr --coverage --testr-args='{posargs}'

[testenv:venv]

# NOTE(jaegerandi): this target does not use constraints because

# upstream infra does not yet support it. Once that's fixed, we can

# drop the install_command.

install_command = pip install -U --force-reinstall {opts} {packages}

commands = {posargs}

[testenv:debug] #代碼調試

commands =

  find keystone -type f -name "*.pyc" -delete

  oslo_debug_helper {posargs}

passenv =

    KSTEST_ADMIN_URL

    KSTEST_ADMIN_USERNAME

    KSTEST_ADMIN_PASSWORD

    KSTEST_ADMIN_DOMAIN_ID

    KSTEST_PUBLIC_URL

    KSTEST_USER_USERNAME

    KSTEST_USER_PASSWORD

    KSTEST_USER_DOMAIN_ID

    KSTEST_PROJECT_ID

[testenv:functional] 

basepython = python3.4

deps = -r{toxinidir}/test-requirements.txt

setenv = OS_TEST_PATH=./keystone/tests/functional

commands =

  find keystone -type f -name "*.pyc" -delete

  python setup.py testr --slowest --testr-args='{posargs}'

passenv =

    KSTEST_ADMIN_URL

    KSTEST_ADMIN_USERNAME

    KSTEST_ADMIN_PASSWORD

    KSTEST_ADMIN_DOMAIN_ID

    KSTEST_PUBLIC_URL

    KSTEST_USER_USERNAME

    KSTEST_USER_PASSWORD

    KSTEST_USER_DOMAIN_ID

    KSTEST_PROJECT_ID

[flake8]

filename= *.py,keystone-all,keystone-manage

show-source = true

# D100: Missing docstring in public module

# D101: Missing docstring in public class

# D102: Missing docstring in public method

# D103: Missing docstring in public function

# D104: Missing docstring in public package

# D105: Missing docstring in magic method

# D202: No blank lines allowed after docstring.

# D203: 1 blank required before class docstring.

# D205: Blank line required between one-line summary and description.

# D400: First line should end with a period.

# D401: First line should be in imperative mood.

ignore = D100,D101,D102,D103,D104,D105,D203,D205,D400,D401

exclude=.venv,.git,.tox,build,dist,doc,*openstack/common*,*lib/python*,*egg,tools,vendor,.update-venv,*.ini,*.po,*.pot

max-complexity=24

[testenv:docs] #生成代碼文檔

commands=

    bash -c "rm -rf doc/build"

    bash -c "rm -rf doc/source/api"

    python setup.py build_sphinx

[testenv:releasenotes] #生成版本信息

# NOTE(sdague): this target does not use constraints because

# upstream infra does not yet support it. Once that's fixed, we can

# drop the install_command.

install_command = pip install -U --force-reinstall {opts} {packages}

commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html

[testenv:genconfig]  #生成配置文件

commands = oslo-config-generator --config-file=config-generator/keystone.conf

[hacking]

import_exceptions =

  keystone.i18n

  six.moves

local-check-factory = keystone.tests.hacking.checks.factory

  setup.cfg的extra部分以下:

 [extras]
ldap =
  python-ldap>=2.4:python_version=='2.7' # PSF
  ldappool>=1.0:python_version=='2.7' # MPL
memcache =
  python-memcached>=1.56 # PSF
mongodb =
  pymongo!=3.1,>=3.0.2 # Apache-2.0
bandit =
  bandit>=0.17.3 # Apache-2.0

使用testrepository管理測試的運行

上面咱們看到tox.ini文件中的commands參數中執行的是_tools/pretty_tox.sh_命令。這個腳本的內容以下:

#!/usr/bin/env bash

set -o pipefail

TESTRARGS=$1

# testr和setuptools已經集成,因此能夠經過setup.py testr命令來執行
# --testr-args表示傳遞給testr命令的參數,告訴testr要傳遞給subunit的參數
# subunit-trace是os-testr包中的命令(os-testr是OpenStack的一個項目),用來解析subunit的輸出的。
python setup.py testr --testr-args="--subunit $TESTRARGS" | subunit-trace -f   
retval=$?
# NOTE(mtreinish) The pipe above would eat the slowest display from pbr's testr
# wrapper so just manually print the slowest tests.
echo -e "\nSlowest Tests:\n"

# 測試結束後,讓testr顯示出執行時間最長的那些測試用例
testr slowest
exit $retval

tox就是從tools/pretty_tox.sh這個命令開始調用testr來執行單元測試的。testr自己的配置是放在項目根目錄下的.testr.conf文件:

[DEFAULT]
test_command=
    ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./keystone/tests/unit} $LISTOPT $IDOPTION

test_id_option=--load-list $IDFILE
test_list_option=--list
group_regex=.*(test_cert_setup)


# NOTE(morganfainberg): If single-worker mode is wanted (e.g. for live tests)
# the environment variable ``TEST_RUN_CONCURRENCY`` should be set to ``1``. If
# a non-default (1 worker per available core) concurrency is desired, set
# environment variable ``TEST_RUN_CONCURRENCY`` to the desired number of
# workers.
test_run_concurrency=echo ${TEST_RUN_CONCURRENCY:-0}

這個文件中的配置項能夠從testr官方文檔中找到。其中test_command命令表示要執行什麼命令來運行測試用例,這裏使用的是subunit.run,這個咱們在上面提到過了。

到目前爲止的流程就是:

  1. tox建好virtualenv

  2. tox調用testr

  3. testr調用subunit來執行測試用例

每一個OpenStack項目基本上也都是這樣。若是你本身在開發一個Python項目,你也能夠參考這個架構。

 

單元測試用例的代碼架構

        下面咱們來看一下Keystone的單元測試代碼是如何寫的,主要是看一下其層次結構。每一個OpenStack項目的單元測試代碼結構可能都不同,不過你瞭解完Keystone的結構以後,看其餘項目的就會比較快了。

咱們以一個測試類爲例來分析測試代碼的結構:keystone.tests.unit.test_v3_assignment:AssignmentTestCase。下面是這個類的繼承結構,同一級別的縮進表示多重繼承,增長縮進表示父類,這裏刪掉了沒必要要的路徑前綴(從unit目錄開始,以下所示:

# 這個測試類是測RoleAssignment的API的
unit.test_v3_assignment.RoleAssignmentBaseTestCase
-> unit.test_v3.AssignmentTestMixin  這個類包含了一下測試Assignment的工具函數
-> unit.test_v3.RestfulTestCase      這個類是進行V3 REST API測試的基類,實現了V3 API的請求發起和校驗
  -> unit.core.SQLDriverOverride     用於修改各個配置的driver字段爲sql
  -> unit.test_v3.AuthTestMixin      包含建立認證請求的輔助函數
  -> unit.rest.RestfulTestCase       這個類是進行RESP API測試的基類,V2和V3的API測試
都是以這個類爲基類,這個類的setUp方法會初始化數據庫,建立好TestApp。
    -> unit.TestCase                 這個類是Keystone中全部單元測試類的基類,它主要初始化配置,以及初始化log
      -> unit.BaseTestCase           這個類主要是配置測試運行的基本環境,修改一些環境變量,好比HOME等。
          -> testtools.TestCase      使用testtools做爲測試框架
            -> unittest.TestCase     testtools自己是unittest的擴展
[root@qqzhangl keystone]# tox -e py27 keystone.tests.unit.test_v3_assignment.AssignmentTestCase
 py27 develop-inst-noop: /home/unittest/keystone
 py27 installed: amqp==1.4.9,anyjson==0.3.3,appdirs==1.4.0,Babel==2.2.0,bashate==0.4.0,beautifulsoup4==4.4.1,cachetools==1.1.5,cffi==1.5.2,contextlib2==0.5.1,coverage==4.0.3,cryptography==1.2.3,debtcollector==1.3.0,decorator==4.0.9,docutils==0.12,dogpile.cache==0.5.7,dogpile.core==0.4.1,dulwich==0.18.3,ecdsa==0.13,enum34==1.1.2,eventlet==0.18.4,extras==0.0.3,fasteners==0.14.1,fixtures==1.4.0,flake8==2.2.4,flake8-docstrings==0.2.1.post1,funcsigs==0.4,functools32==3.2.3.post2,futures==3.0.5,futurist==0.13.0,greenlet==0.4.9,hacking==0.10.3,httplib2==0.9.2,idna==2.0,ipaddress==1.0.16,iso8601==0.1.11,Jinja2==2.8,jsonschema==2.5.1,-e git+http://git.bjv30.isscloud.com/cloudgo/keystone.git@30b5d9036f3299333a3655c00b5cd510676a48e8#egg=keystone,keystoneauth1==2.4.3,keystonemiddleware==0.0.1.dev4,kombu==3.0.34,ldappool==1.0,linecache2==1.0.0,lxml==3.5.0,MarkupSafe==0.23,mccabe==0.2.1,mock==1.3.0,monotonic==0.6,mox3==0.14.0,msgpack-python==0.4.7,netaddr==0.7.18,netifaces==0.10.4,oauthlib==1.0.3,os-client-config==1.16.0,os-testr==0.6.0,oslo.cache==1.6.0,oslo.concurrency==3.7.1,oslo.config==3.9.0,oslo.context==2.2.0,oslo.db==0.0.1.dev3,oslo.i18n==3.5.0,oslo.log==3.3.0,oslo.messaging==4.6.1,oslo.middleware==3.8.0,oslo.policy==1.6.0,oslo.serialization==2.4.0,oslo.service==1.8.0,oslo.utils==3.8.0,oslosphinx==4.3.0,oslotest==2.4.0,paramiko==1.16.0,passlib==1.6.5,Paste==2.0.2,PasteDeploy==1.5.2,pbr==1.8.1,pep257==0.7.0,pep8==1.5.7,pika==0.10.0,pika-pool==0.1.3,positional==1.0.1,pyasn1==0.1.9,pycadf==2.2.0,pycparser==2.14,pycrypto==2.6.1,pyflakes==0.8.1,Pygments==2.1.3,pyinotify==0.9.6,pymongo==3.2.1,pyOpenSSL==0.15.1,pyrsistent==0.11.12,pysaml2==4.0.2,python-dateutil==2.5.0,python-keystoneclient==0.0.1.dev40,python-ldap==2.4.25,python-memcached==1.57,python-mimeparse==1.5.1,python-subunit==1.2.0,pytz==2015.7,PyYAML==3.11,reno==2.5.0,repoze.lru==0.6,repoze.who==2.2,requests==2.9.1,requestsexceptions==1.1.3,retrying==1.3.3,Routes==2.2,six==1.10.0,Sphinx==1.2.3,SQLAlchemy==1.0.12,sqlalchemy-migrate==0.10.0,sqlparse==0.1.18,stevedore==1.12.0,tempest-lib==1.0.0,Tempita==0.5.2,testrepository==0.0.20,testscenarios==0.5.0,testtools==2.0.0,traceback2==1.4.0,unittest2==1.1.0,waitress==0.8.10,WebOb==1.5.1,WebTest==2.0.20,wrapt==1.10.6,zope.interface==4.1.3
 py27 runtests: PYTHONHASHSEED='2134132608'
 py27 runtests: commands[0] | find keystone -type f -name *.pyc -delete
 py27 runtests: commands[1] | bash tools/pretty_tox.sh keystone.tests.unit.test_v3_assignment.AssignmentTestCase
 running testr
 running=
 ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./keystone/tests/unit} --list

running=
${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./keystone/tests/unit}  --load-list /tmp/tmpQRrBp5
running=
${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./keystone/tests/unit}  --load-list /tmp/tmpkpPca8
running=
${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./keystone/tests/unit}  --load-list /tmp/tmpAsqqdg
running=
${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./keystone/tests/unit}  --load-list /tmp/tmpcKMYi5
{3} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_create_member_role [3.301750s] ... ok
{0} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_crud_user_domain_role_grants_no_user [3.129583s] ... ok
{2} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_create_role [3.084101s] ... ok
{1} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_check_effective_values_for_role_assignments [3.829839s] ... ok
{3} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_create_role_bad_request [0.782877s] ... ok
{0} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_crud_user_project_role_grants [1.012792s] ... ok
{1} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_crud_group_domain_role_grants_no_group [0.751216s] ... ok
{2} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_crud_group_domain_role_grants [1.185124s] ... ok
{3} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_crud_user_domain_role_grants [1.365098s] ... ok
{2} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_crud_group_project_role_grants_no_group [0.868791s] ... ok
{1} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_crud_group_project_role_grants [1.128794s] ... ok
{0} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_delete_grant_from_group_and_project_invalidates_cache [1.382533s] ... ok
{3} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_crud_user_project_role_grants_no_user [0.947176s] ... ok
{1} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_delete_grant_from_user_and_domain_invalidates_cache [0.932734s] ... ok
{2} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_delete_role [1.184809s] ... ok
{0} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_delete_user_and_check_role_assignment_fails [1.040105s] ... ok
{3} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_delete_grant_from_group_and_domain_invalidates_cache [1.143361s] ... ok
{1} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_delete_grant_from_user_and_project_invalidate_cache [1.005817s] ... ok
{0} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_get_effective_role_assignments [1.158699s] ... ok
{1} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_list_roles [0.871036s] ... ok
{2} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_filtered_role_assignments [1.769572s] ... ok
{3} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_delete_user_before_removing_role_assignment_succeeds [1.262221s] ... ok
{1} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_token_revoked_once_group_role_grant_revoked [0.880450s] ... FAILED

Captured traceback:
~~~~~~~~~~~~~~~~~~~
    Traceback (most recent call last):
      File "keystone/tests/unit/test_v3_assignment.py", line 336, in test_token_revoked_once_group_role_grant_revoked
        expected_status=http_client.NOT_FOUND)
      File "keystone/tests/unit/test_v3.py", line 537, in head
        expected_status=expected_status, **kwargs)
      File "keystone/tests/unit/test_v3.py", line 529, in v3_request
        return self.admin_request(path=path, token=token, **kwargs)
      File "keystone/tests/unit/rest.py", line 212, in admin_request
        return self._request(app=self.admin_app, **kwargs)
      File "keystone/tests/unit/rest.py", line 201, in _request
        response = self.restful_request(**kwargs)
      File "keystone/tests/unit/rest.py", line 186, in restful_request
        **kwargs)
      File "keystone/tests/unit/rest.py", line 90, in request
        **kwargs)
      File "/home/unittest/keystone/.tox/py27/lib/python2.7/site-packages/webtest/app.py", line 567, in request
        expect_errors=expect_errors,
      File "/home/unittest/keystone/.tox/py27/lib/python2.7/site-packages/webtest/app.py", line 632, in do_request
        self._check_status(status, res)
      File "/home/unittest/keystone/.tox/py27/lib/python2.7/site-packages/webtest/app.py", line 667, in _check_status
        "Bad response: %s (not %s)", res_status, status)
    webtest.app.AppError: Bad response: 200 OK (not 404)
    

Captured pythonlogging:
~~~~~~~~~~~~~~~~~~~~~~~
    Adding cache-proxy 'oslo_cache.testing.CacheIsolatingProxy' to backend.
    Adding cache-proxy 'oslo_cache.testing.CacheIsolatingProxy' to backend.
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x4e898d0> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x4b8dc90> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x46901d0> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x46901d0> acquired
    Calling creation function
    Released creation lock
    The admin_token_auth middleware presents a security risk and should be removed from the [pipeline:api_v3], [pipeline:admin_api], and [pipeline:public_api] sections of your paste ini file.
    The admin_token_auth middleware presents a security risk and should be removed from the [pipeline:api_v3], [pipeline:admin_api], and [pipeline:public_api] sections of your paste ini file.
    The admin_token_auth middleware presents a security risk and should be removed from the [pipeline:api_v3], [pipeline:admin_api], and [pipeline:public_api] sections of your paste ini file.
    The admin_token_auth middleware presents a security risk and should be removed from the [pipeline:api_v3], [pipeline:admin_api], and [pipeline:public_api] sections of your paste ini file.
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x4b8fa90> acquired
    Calling creation function
    Released creation lock
    There is either no auth token in the request or the certificate issuer is not trusted. No auth context will be set.
    POST http://localhost:80/v3/auth/tokens
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x596a490> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x4b8d050> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x4806450> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x4806450> acquired
    Calling creation function
    Released creation lock
    RBAC: Proceeding without project or domain scope
    RBAC: auth_context: {'access_token_id': None, 'user_id': u'124ec4417a804bfcaa113317e3cdf595', 'consumer_id': None, 'trustor_id': None, 'user_target': None, 'is_delegated_auth': False, 'trust_id': None, 'trustee_id': None, 'token': <KeystoneToken (audit_id=tY7TVIapRPSNoKPVgcNxfQ, audit_chain_id=tY7TVIapRPSNoKPVgcNxfQ) at 0x5e425f0>}
    POST http://localhost:80/v3/auth/tokens
    There is either no auth token in the request or the certificate issuer is not trusted. No auth context will be set.
    POST http://localhost:80/v3/auth/tokens
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x4806290> acquired
    Calling creation function
    Released creation lock
    RBAC: Proceeding without project or domain scope
    RBAC: auth_context: {'access_token_id': None, 'user_id': u'124ec4417a804bfcaa113317e3cdf595', 'consumer_id': None, 'trustor_id': None, 'user_target': None, 'is_delegated_auth': False, 'trust_id': None, 'trustee_id': None, 'token': <KeystoneToken (audit_id=4jw2Y8iBSYi_34W6wseoIA, audit_chain_id=4jw2Y8iBSYi_34W6wseoIA) at 0x725c050>}
    HEAD http://localhost:80/v3/auth/tokens
    RBAC: Authorizing identity:check_token()
    RBAC: using auth context from the request environment
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x5e65810> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x5b61650> acquired
    Calling creation function
    Released creation lock
    There is either no auth token in the request or the certificate issuer is not trusted. No auth context will be set.
    POST http://localhost:80/v3/auth/tokens
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x5e83890> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x5e83f50> acquired
    Calling creation function
    Released creation lock
    RBAC: Proceeding without project or domain scope
    RBAC: auth_context: {'access_token_id': None, 'user_id': u'124ec4417a804bfcaa113317e3cdf595', 'consumer_id': None, 'trustor_id': None, 'user_target': None, 'is_delegated_auth': False, 'trust_id': None, 'trustee_id': None, 'token': <KeystoneToken (audit_id=AEqLyFtMRHG9wfKE0AVrew, audit_chain_id=AEqLyFtMRHG9wfKE0AVrew) at 0x5e1a290>}
    HEAD http://localhost:80/v3/auth/tokens
    RBAC: Authorizing identity:check_token()
    RBAC: using auth context from the request environment
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x5b61a90> acquired
    Calling creation function
    Released creation lock
    
{2} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_get_role [0.886941s] ... ok
{0} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_get_role_assignments [1.906290s] ... ok
{2} keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_update_role [0.603548s] ... ok

==============================
Failed 1 tests - output below:
==============================

keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_token_revoked_once_group_role_grant_revoked
----------------------------------------------------------------------------------------------------------

Captured traceback:
~~~~~~~~~~~~~~~~~~~
    Traceback (most recent call last):
      File "keystone/tests/unit/test_v3_assignment.py", line 336, in test_token_revoked_once_group_role_grant_revoked
        expected_status=http_client.NOT_FOUND)
      File "keystone/tests/unit/test_v3.py", line 537, in head
        expected_status=expected_status, **kwargs)
      File "keystone/tests/unit/test_v3.py", line 529, in v3_request
        return self.admin_request(path=path, token=token, **kwargs)
      File "keystone/tests/unit/rest.py", line 212, in admin_request
        return self._request(app=self.admin_app, **kwargs)
      File "keystone/tests/unit/rest.py", line 201, in _request
        response = self.restful_request(**kwargs)
      File "keystone/tests/unit/rest.py", line 186, in restful_request
        **kwargs)
      File "keystone/tests/unit/rest.py", line 90, in request
        **kwargs)
      File "/home/unittest/keystone/.tox/py27/lib/python2.7/site-packages/webtest/app.py", line 567, in request
        expect_errors=expect_errors,
      File "/home/unittest/keystone/.tox/py27/lib/python2.7/site-packages/webtest/app.py", line 632, in do_request
        self._check_status(status, res)
      File "/home/unittest/keystone/.tox/py27/lib/python2.7/site-packages/webtest/app.py", line 667, in _check_status
        "Bad response: %s (not %s)", res_status, status)
    webtest.app.AppError: Bad response: 200 OK (not 404)
    

Captured pythonlogging:
~~~~~~~~~~~~~~~~~~~~~~~
    Adding cache-proxy 'oslo_cache.testing.CacheIsolatingProxy' to backend.
    Adding cache-proxy 'oslo_cache.testing.CacheIsolatingProxy' to backend.
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x4e898d0> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x4b8dc90> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x46901d0> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x46901d0> acquired
    Calling creation function
    Released creation lock
    The admin_token_auth middleware presents a security risk and should be removed from the [pipeline:api_v3], [pipeline:admin_api], and [pipeline:public_api] sections of your paste ini file.
    The admin_token_auth middleware presents a security risk and should be removed from the [pipeline:api_v3], [pipeline:admin_api], and [pipeline:public_api] sections of your paste ini file.
    The admin_token_auth middleware presents a security risk and should be removed from the [pipeline:api_v3], [pipeline:admin_api], and [pipeline:public_api] sections of your paste ini file.
    The admin_token_auth middleware presents a security risk and should be removed from the [pipeline:api_v3], [pipeline:admin_api], and [pipeline:public_api] sections of your paste ini file.
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x4b8fa90> acquired
    Calling creation function
    Released creation lock
    There is either no auth token in the request or the certificate issuer is not trusted. No auth context will be set.
    POST http://localhost:80/v3/auth/tokens
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x596a490> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x4b8d050> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x4806450> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x4806450> acquired
    Calling creation function
    Released creation lock
    RBAC: Proceeding without project or domain scope
    RBAC: auth_context: {'access_token_id': None, 'user_id': u'124ec4417a804bfcaa113317e3cdf595', 'consumer_id': None, 'trustor_id': None, 'user_target': None, 'is_delegated_auth': False, 'trust_id': None, 'trustee_id': None, 'token': <KeystoneToken (audit_id=tY7TVIapRPSNoKPVgcNxfQ, audit_chain_id=tY7TVIapRPSNoKPVgcNxfQ) at 0x5e425f0>}
    POST http://localhost:80/v3/auth/tokens
    There is either no auth token in the request or the certificate issuer is not trusted. No auth context will be set.
    POST http://localhost:80/v3/auth/tokens
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x4806290> acquired
    Calling creation function
    Released creation lock
    RBAC: Proceeding without project or domain scope
    RBAC: auth_context: {'access_token_id': None, 'user_id': u'124ec4417a804bfcaa113317e3cdf595', 'consumer_id': None, 'trustor_id': None, 'user_target': None, 'is_delegated_auth': False, 'trust_id': None, 'trustee_id': None, 'token': <KeystoneToken (audit_id=4jw2Y8iBSYi_34W6wseoIA, audit_chain_id=4jw2Y8iBSYi_34W6wseoIA) at 0x725c050>}
    HEAD http://localhost:80/v3/auth/tokens
    RBAC: Authorizing identity:check_token()
    RBAC: using auth context from the request environment
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x5e65810> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x5b61650> acquired
    Calling creation function
    Released creation lock
    There is either no auth token in the request or the certificate issuer is not trusted. No auth context will be set.
    POST http://localhost:80/v3/auth/tokens
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x5e83890> acquired
    Calling creation function
    Released creation lock
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x5e83f50> acquired
    Calling creation function
    Released creation lock
    RBAC: Proceeding without project or domain scope
    RBAC: auth_context: {'access_token_id': None, 'user_id': u'124ec4417a804bfcaa113317e3cdf595', 'consumer_id': None, 'trustor_id': None, 'user_target': None, 'is_delegated_auth': False, 'trust_id': None, 'trustee_id': None, 'token': <KeystoneToken (audit_id=AEqLyFtMRHG9wfKE0AVrew, audit_chain_id=AEqLyFtMRHG9wfKE0AVrew) at 0x5e1a290>}
    HEAD http://localhost:80/v3/auth/tokens
    RBAC: Authorizing identity:check_token()
    RBAC: using auth context from the request environment
    NeedRegenerationException
    no value, waiting for create lock
    value creation lock <dogpile.cache.region._LockWrapper object at 0x5b61a90> acquired
    Calling creation function
    Released creation lock
    


======
Totals
======
Ran: 26 tests in 15.0000 sec.
 - Passed: 25
 - Skipped: 0
 - Expected Fail: 0
 - Unexpected Success: 0
 - Failed: 1
Sum of execute time for each test: 37.4153 sec.

==============
Worker Balance
==============
 - Worker 0 (6 tests) => 0:00:09.655349
 - Worker 1 (7 tests) => 0:00:09.422374
 - Worker 2 (7 tests) => 0:00:09.612487
 - Worker 3 (6 tests) => 0:00:08.822696

Slowest Tests:

Test id                                                                                                               Runtime (s)
--------------------------------------------------------------------------------------------------------------------  -----------
keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_check_effective_values_for_role_assignments            3.830
keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_create_member_role                                     3.302
keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_crud_user_domain_role_grants_no_user                   3.130
keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_create_role                                            3.084
keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_get_role_assignments                                   1.906
keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_filtered_role_assignments                              1.770
keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_delete_grant_from_group_and_project_invalidates_cache  1.383
keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_crud_user_domain_role_grants                           1.365
keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_delete_user_before_removing_role_assignment_succeeds   1.262
keystone.tests.unit.test_v3_assignment.AssignmentTestCase.test_crud_group_domain_role_grants                          1.185
ERROR: InvocationError: '/usr/bin/bash tools/pretty_tox.sh keystone.tests.unit.test_v3_assignment.AssignmentTestCase'
___________________________________________________________ summary ___________________________________________________________
ERROR:   py27: commands failed

注意:測試的時候提示缺乏.testr.conf 和.coveragerc文件 這個兩個文件須要從githhub官網的openstack項目中獲取,好比keystone 地址爲https://github.com/openstack/keystone  切換到mitaka版本

相關文章
相關標籤/搜索