diff --git a/conf/README.rst b/conf/README.rst index e92eb8cd..796549fa 100644 --- a/conf/README.rst +++ b/conf/README.rst @@ -4,3 +4,8 @@ This directory contains examples of configuration files required to run the integration tests. + +See full documentation of usmqe test configuration in `Test Configuration`_ +document. + +.. _`Test Configuration`: https://github.com/Tendrl/usmqe-tests/blob/master/docs/test_configuration.rst diff --git a/conf/example_pytest.ini b/conf/example_pytest.ini deleted file mode 100644 index 35208d3c..00000000 --- a/conf/example_pytest.ini +++ /dev/null @@ -1,25 +0,0 @@ -[pytest] - -# usmqe configuration -# add the following options into the top level pytest.ini file -USM_CONFIG = conf/example_usm.ini -USM_HOST_CONFIG = conf/example.hosts -USM_USERNAME = admin -USM_PASSWORD = -USM_URL = -USM_APIURL = -USM_LOG_LEVEL = logging.DEBUG -USM_KEYFILE = "~/.ssh/id_rsa" -USM_CA_CERT = False -USM_RAUT_SELENIUM_SERVER = -USM_LDAP_SERVER = None -USM_LDAP_PORT = 389 -USM_LDAP_BASE = None -USM_LDAP_DOMAINADMIN = None -USM_LDAP_PASSWORD = None -USM_LDAP_UID = "cn" -USM_LDAP_FIRSTNAME = "displayName" -USM_LDAP_LASTNAME = "sn" -USM_LDAP_DISPLAYNAME = None -USM_LDAP_EMAIL = "mail" -USM_LDAP_USER_FILE = None diff --git a/conf/example.hosts b/conf/example_usm.hosts similarity index 100% rename from conf/example.hosts rename to conf/example_usm.hosts diff --git a/conf/example_usm.ini b/conf/example_usm.ini index 330439eb..4b308a1a 100644 --- a/conf/example_usm.ini +++ b/conf/example_usm.ini @@ -1,10 +1,12 @@ -# this is example of usm qe configuration file -[usm] -log_level = DEBUG -username = -password = -url = https://example-usm3-server.usmqe.tendrl.org:10443 -ca_cert = conf/tendrl_ca.crt +# This is example of USM QE configuration file. -[raut] -SELENIUM_SERVER = None +# All options in `usmqepytest` section will be loaded during pytest start +# so that it will be available as if it were specified directly in pytest.ini +# (see plugin/usmqe_config.py for details). +[usmqepytest] +usm_log_level = DEBUG +usm_username = +usm_password = +usm_web_url = https://example-usm3-server.usmqe.tendrl.org +usm_api_url = %(usm_web_url):9393/api/1.0/ +usm_ca_cert = conf/tendrl_ca.crt diff --git a/docs/test_configuration.rst b/docs/test_configuration.rst index 5fc0d182..d35c0f8b 100644 --- a/docs/test_configuration.rst +++ b/docs/test_configuration.rst @@ -2,7 +2,124 @@ Test Configuraion =================== -USM QE Tests are executed under ``usmqe`` user account on QE Server -machine (see :ref:`qe-server-label` for more details). +Configuration of *USM QE integration tests* project piggibacks/reuses pytest +ini-options parser, so that all USM QE configuration options could be specified +in ``pytest.ini`` file. To prevent a conflict with pytest ini-option names, we +use ``usm_`` prefix in a name of every option. -TODO: include all the details here +Configuration Scheme +==================== + +Since there are `multiple ways to configure pytest`_, we defined the following +scheme: + +* Main *pytest config file* `pytest.ini`_ is committed in the root directory + of ``usmqe-tests`` repository. This file contains pytest configuration + and *default values* for most important USM QE configuration options. Under + normal circumstances (configuring ``usmqe-tests`` before test run) one would + not need to change this file at all, because any default value specified here + can be reconfigured in USM QE config file (with the exception of + ``usm_config`` and ``usm_host_config`` options). + +* *USM QE config file* is expected to contain actual configuration. See an + example in `conf/example_usm.ini`_, while the actual path of this file is + configured in ``usm_config`` option in main ``pytest.ini`` file. Any option + specified there overrides the default from main ``pytest.ini``. This is the + file one is supposed to create and change as needed. You need to provide + all important config values in this file to be able to run the tests. + +* Ansible *host inventory file* (see an example in ``conf/example.hosts``), + which is used both by ansible and by USM QE inventory module to organize + machines into groups by it's role in test cluster. Actual path of this file + is configured in ``usm_host_config`` option in main ``pytest.ini`` file. + +* Moreover ad hoc reconfiguration of any USM QE option is possible via pytest + command line option ``--override-ini``. See an example how to use different + *host inventory file* for a particular test run: + + .. code-block:: console + + $ py.test -o=usm_host_config=conf/mbukatov01.hosts usmqe_tests/foo/bar + + This is usefull for test runs started by hand during test development or + debugging. + + +Details for Test Development +============================ + +To access data from the host inventory, use functions provided by +``usmqe.inventory`` module: + +.. code-block:: python + + import usmqe.inventory as inventory + + for host in inventory.role2hosts("ceph_osd"): + print("check storage server {0}".format(host)) + +To access USM QE configuration, use standard pytest configuration functions: + +.. code-block:: python + + import pytest + + pytest.config.getini("usm_username") + +Obviously this assumes that the ``usm_username`` option has been specified in +USM QE config file (which is referenced via ``usm_config`` option). The minimal +ini file for the previous example to work would look like this:: + + [usmqepytest] + usm_username = admin + +Reading of both *USM QE config file* and *host inventory file* is implemented +in ``plugin/usmqe_config.py`` module, while management of *host inventory file* +is handled by ``usmqe/inventory.py`` module. + + +Configuration before test run +============================= + +We assume that: + +* *QE Server machine* has been configured as described in + :ref:`qe-server-label` + +* You have *host inventory file* for the test cluster, which has been already + deployed (our deployment automation should generate the inventory file + in the end of the process). + +* You are logged as ``usmqe`` user on the QE Server + +Now, you need to: + +* Check that ``usmqe`` user has a private ssh key in ``~/.ssh/id_rsa`` file + (this is default location of ssh key specified in ``usm_keyfile`` option of + ``pytest.ini``) and has it's public ssh key deployed on all machines of test + cluster. + +* Store *host inventory file* in ``conf/clustername.hosts`` and specify this + path in ``usm_host_config`` option of ``pytest.ini``. + +* Verify that ssh and ansible are configured so that one can reach all machines + from test cluster: + + .. code-block:: console + + [usmqe@qeserver ~]$ ansible -i conf/clustername.hosts -m ping -u root all + +* Initiate new *USM QE config file*: ``cp conf/example_usm.ini conf/usm.ini`` + and check that ``usm_config`` option of ``pytest.ini`` file points to this + file. + +* Provide all mandatory options in *usm config file* initialized in a previous + step. This includes: ``username``, ``password``, ``web_url`` and ``api_url``. + The actual list depends on the test suite you are going to run (eg. api + tests doesn't care about ``web_url`` while LDAP integration tests would need + to know address of the LDAP server). + + +.. _`multiple ways to configure pytest`: http://doc.pytest.org/en/latest/customize.html +.. _`pytest.ini`: https://github.com/Tendrl/usmqe-tests/blob/master/pytest.ini +.. _`conf/example_usm.ini`: https://github.com/Tendrl/usmqe-tests/blob/master/conf/example_usm.ini diff --git a/plugin/usmqe_config.py b/plugin/usmqe_config.py index 05ae81b6..237d103c 100644 --- a/plugin/usmqe_config.py +++ b/plugin/usmqe_config.py @@ -17,20 +17,9 @@ def pytest_addoption(parser): """ Add ini options to be accepted by pytest. """ - parser.addini('USM_CONFIG', 'USM configuration') - parser.addini( - 'USM_HOST_CONFIG', 'USM host configuration', default='sample.hosts') - parser.addini('USM_USERNAME', 'USM username for login', default='admin') - parser.addini('USM_PASSWORD', 'USM password for login') - parser.addini('USM_URL', 'USM url') - parser.addini('USM_APIURL', 'USM url for api') - parser.addini( - 'USM_LOG_LEVEL', 'USM log test level', default='logging.DEBUG') - parser.addini( - 'USM_KEYFILE', 'USM key file for passwordless ssh', - default='~/.ssh/id_rsa') - parser.addini( - 'USM_CA_CERT', 'USM use CA certificate', type='bool', default=False) + # defaults are specified in root pytest.ini file + parser.addini('usm_config', 'USM configuration') + parser.addini('usm_host_config', 'USM host configuration') @pytest.fixture(autouse=True, scope="session") @@ -40,13 +29,13 @@ def load_inventory(): To use content from inventory file just *import inventory* and then use proper function from ``usmqe.inventory``. - Name of inventory file is stored in ``USM_HOST_CONFIG`` option in + Name of inventory file is stored in ``usm_host_config`` option in ``pytest.ini``. Its value can be overriden by ``pytest -o - USM_HOST_CONFIG=path``. + usm_host_config=path``. """ # update machine config (reading ansible inventory) hosts = ConfigParser(allow_no_value=True) - hosts.read(pytest.config.getini("USM_HOST_CONFIG")) + hosts.read(pytest.config.getini("usm_host_config")) for rolename in hosts.sections(): for hostname, _ in hosts.items(rolename): usmqe.inventory.add_host_entry(rolename, hostname) @@ -57,33 +46,22 @@ def load_config(): """ Loads configuration from pytest.ini file. - If there is configured external configuration file(USM_CONFIG) + If there is configured external configuration file(usm_config) then ini values are updated by values from configuration file. All configuration entries can be overriden by:: - $ py.test -o USM_USERNAME=admin2 + $ py.test -o=usm_username=admin2 """ - if pytest.config.getini("USM_CONFIG"): + if pytest.config.getini("usm_config"): conf = ConfigParser() - conf.read(pytest.config.getini("USM_CONFIG")) - - for section in ('raut', 'usm', 'ldap'): - if section in conf.sections(): - for key, value in conf.items(section): - if section == 'usm': - name = "USM_{0}".format(key.upper()) - else: - name = "USM_{0}_{1}".format( - section.upper(), key.upper()) - - override_value = pytest.config._get_override_ini_value( - name) - if override_value is None: - pytest.config._inicache[name] = value - else: - pytest.config._inicache[name] = override_value - - if not pytest.config.getini("USM_APIURL"): - pytest.config._inicache["USM_APIURL"] = \ - "{}/api/v1/".format(pytest.config.getini("USM_URL")) + conf.read(pytest.config.getini("usm_config")) + if "usmqepytest" not in conf.sections(): + # TODO: report a problem + return + for key, value in conf.items("usmqepytest"): + override_value = pytest.config._get_override_ini_value(key) + if override_value is None: + pytest.config._inicache[key] = value + else: + pytest.config._inicache[key] = override_value diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..1b7a43fb --- /dev/null +++ b/pytest.ini @@ -0,0 +1,45 @@ +[pytest] + +# +# USM QE config section (see plugin/usmqe_config.py) +# + +# Path to the main usmqe config file (that is the file one should edit to +# change configuration of usm qe tests). +usm_config = conf/usm.ini + +# Path to the host inventory file (list of all machines of a test cluster +# grouped into roles). This file is used both by ansible and usm qe tests. +usm_host_config = conf/usm.hosts + +# Predefined usmqe configuration values. +# You should not change them here, but edit ini file referenced in usm_config +# +# For add hoc changes, one can redefine the values from the command line: +# +# $ py.test -o=usm_username=admin2 + +# usm config group +usm_log_level = logging.DEBUG +usm_username = admin +usm_password = +usm_web_url = +usm_api_url = +usm_ca_cert = False +usm_keyfile = "~/.ssh/id_rsa" + +# webstr config group: webstr specific options +usm_webstr_selenium_server = + +# ldap config group: LDAP specific options +usm_ldap_server = None +usm_ldap_port = 389 +usm_ldap_base = None +usm_ldap_domainadmin = None +usm_ldap_password = None +usm_ldap_uid = "cn" +usm_ldap_firstname = "displayName" +usm_ldap_lastname = "sn" +usm_ldap_displayname = None +usm_ldap_email = "mail" +usm_ldap_user_file = None diff --git a/usmqe/api/skyringapi/skyringapi.py b/usmqe/api/skyringapi/skyringapi.py index 5c0a8c7d..4a170442 100644 --- a/usmqe/api/skyringapi/skyringapi.py +++ b/usmqe/api/skyringapi/skyringapi.py @@ -33,7 +33,7 @@ class Api(object): def __init__(self, copy_from=None): self.cookies = {} - self.verify = pytest.config.getini("USM_CA_CERT") + self.verify = pytest.config.getini("usm_ca_cert") if copy_from: self.cookies = copy_from.cookies self.verify = copy_from.verify @@ -141,7 +141,7 @@ def login(self, username, password, asserts_in=None): if asserts_in: asserts.update(asserts_in) data = json.dumps({'username': username, 'password': password}) - req = requests.post(pytest.config.getini("USM_APIURL") + "auth/login", + req = requests.post(pytest.config.getini("usm_api_url") + "auth/login", data, verify=self.verify) Api.print_req_info(req) Api.check_response(req, asserts) @@ -173,7 +173,7 @@ def logout(self, asserts_in=None): }) if asserts_in: asserts.update(asserts_in) - req = requests.post(pytest.config.getini("USM_APIURL") + "auth/logout", + req = requests.post(pytest.config.getini("usm_api_url") + "auth/logout", cookies=self.cookies, verify=self.verify) Api.print_req_info(req) Api.check_response(req, asserts) diff --git a/usmqe/api/skyringapi/user.py b/usmqe/api/skyringapi/user.py index 74607bab..b527844e 100644 --- a/usmqe/api/skyringapi/user.py +++ b/usmqe/api/skyringapi/user.py @@ -31,7 +31,7 @@ def users(self, asserts_in=None): }) if asserts_in: asserts.update(asserts_in) - req = requests.get(pytest.config.getini("USM_APIURL") + "users/", + req = requests.get(pytest.config.getini("usm_api_url") + "users/", cookies=self.cookies, verify=self.verify) ApiUser.print_req_info(req) ApiUser.check_response(req, asserts) @@ -71,7 +71,7 @@ def users_replace(self, users, asserts_in=None): data[-1]["email"] %= usr data[-1]["password"] = usr data = json.dumps(data) - req = requests.put(pytest.config.getini("USM_APIURL") + "users", + req = requests.put(pytest.config.getini("usm_api_url") + "users", data, cookies=self.cookies, verify=self.verify) ApiUser.print_req_info(req) ApiUser.check_response(req, asserts) @@ -106,7 +106,7 @@ def users_add(self, user_in, asserts_in=None): issue = None if data: data = json.dumps(data) - req = requests.post(pytest.config.getini("USM_APIURL") + "users", + req = requests.post(pytest.config.getini("usm_api_url") + "users", data, cookies=self.cookies, verify=self.verify) ApiUser.print_req_info(req) if req.status_code == 500 and \ @@ -135,7 +135,7 @@ def user(self, user_in, asserts_in=None): if asserts_in: asserts.update(asserts_in) req = requests.get( - pytest.config.getini("USM_APIURL") + "users/%s" % user_in, + pytest.config.getini("usm_api_url") + "users/%s" % user_in, cookies=self.cookies, verify=self.verify) ApiUser.print_req_info(req) ApiUser.check_response(req, asserts) @@ -174,7 +174,7 @@ def user_add(self, user_in, asserts_in=None): elif isinstance(user_in, dict): data = user_in req = requests.put( - pytest.config.getini("USM_APIURL") + "users/%s" % data["username"], + pytest.config.getini("usm_api_url") + "users/%s" % data["username"], json.dumps(data), cookies=self.cookies, verify=self.verify) ApiUser.print_req_info(req) ApiUser.check_response(req, asserts) @@ -195,7 +195,7 @@ def user_del(self, user_in, asserts_in=None): if asserts_in: asserts.update(asserts_in) req = requests.delete( - pytest.config.getini("USM_APIURL") + "users/%s" % user_in, + pytest.config.getini("usm_api_url") + "users/%s" % user_in, cookies=self.cookies, verify=self.verify) ApiUser.print_req_info(req) ApiUser.check_response(req, asserts) diff --git a/usmqe_tests/skyringapi/test_user.py b/usmqe_tests/skyringapi/test_user.py index e64ea78a..85c5a5f9 100644 --- a/usmqe_tests/skyringapi/test_user.py +++ b/usmqe_tests/skyringapi/test_user.py @@ -54,7 +54,7 @@ def test_login_valid(): Return code should be **200** with data ``{"message": "Logged in"}``. It should return session cookie. """ - test.login(pytest.config.getini("USM_USERNAME"), pytest.config.getini("USM_PASSWORD")) + test.login(pytest.config.getini("usm_username"), pytest.config.getini("usm_password")) test.logout() @@ -121,7 +121,7 @@ def test_logout(): .. test_result:: 1 :include: api/user.login_valid:1 """ - test.login(pytest.config.getini("USM_USERNAME"), pytest.config.getini("USM_PASSWORD")) + test.login(pytest.config.getini("usm_username"), pytest.config.getini("usm_password")) """@pylatest api/user.logout .. test_step:: 2 @@ -181,7 +181,7 @@ def test_user_get(): .. test_result:: 1 :include: api/user.login_valid:1 """ - test.login(pytest.config.getini("USM_USERNAME"), pytest.config.getini("USM_PASSWORD")) + test.login(pytest.config.getini("usm_username"), pytest.config.getini("usm_password")) """@pylatest api/user.get .. test_step:: 2 @@ -217,7 +217,7 @@ def test_user_get_not_found(): .. test_result:: 1 :include: api/user.login_valid:1 """ - test.login(pytest.config.getini("USM_USERNAME"), pytest.config.getini("USM_PASSWORD")) + test.login(pytest.config.getini("usm_username"), pytest.config.getini("usm_password")) """@pylatest api/user.get_nonexistent .. test_step:: 2 @@ -266,7 +266,7 @@ def test_user_add_del(self): .. test_result:: 1 :include: api/user.login_valid:1 """ - test.login(pytest.config.getini("USM_USERNAME"), pytest.config.getini("USM_PASSWORD")) + test.login(pytest.config.getini("usm_username"), pytest.config.getini("usm_password")) """@pylatest api/user.add_delete .. test_step:: 2