12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115 |
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- """
- Discover all instances of unittest.TestCase in this directory.
- """
- # pylint: disable=file-perms
- # Import python libs
- from __future__ import absolute_import, print_function
- import collections
- import os
- import sys
- import time
- import warnings
- TESTS_DIR = os.path.dirname(os.path.normpath(os.path.abspath(__file__)))
- if os.name == "nt":
- TESTS_DIR = TESTS_DIR.replace("\\", "\\\\")
- CODE_DIR = os.path.dirname(TESTS_DIR)
- # Let's inject CODE_DIR so salt is importable if not there already
- if "" in sys.path:
- sys.path.remove("")
- if TESTS_DIR in sys.path:
- sys.path.remove(TESTS_DIR)
- if CODE_DIR in sys.path and sys.path[0] != CODE_DIR:
- sys.path.remove(CODE_DIR)
- if CODE_DIR not in sys.path:
- sys.path.insert(0, CODE_DIR)
- if TESTS_DIR not in sys.path:
- sys.path.insert(1, TESTS_DIR)
- try:
- import tests
- if not tests.__file__.startswith(CODE_DIR):
- print("Found tests module not from salt in {}".format(tests.__file__))
- sys.modules.pop("tests")
- module_dir = os.path.dirname(tests.__file__)
- if module_dir in sys.path:
- sys.path.remove(module_dir)
- del tests
- except ImportError:
- pass
- # Import salt libs
- from salt.ext import six # isort:skip
- try:
- from tests.support.paths import TMP, SYS_TMP_DIR, INTEGRATION_TEST_DIR
- from tests.support.paths import CODE_DIR as SALT_ROOT
- except ImportError as exc:
- try:
- import tests
- print("Found tests module not from salt in {}".format(tests.__file__))
- except ImportError:
- print("Unable to import salt test module")
- print("PYTHONPATH:", os.environ.get("PYTHONPATH"))
- print("Current sys.path:")
- import pprint
- pprint.pprint(sys.path)
- six.reraise(*sys.exc_info())
- from tests.integration import TestDaemon, TestDaemonStartFailed # isort:skip
- from tests.multimaster import MultimasterTestDaemon # isort:skip
- import salt.utils.platform # isort:skip
- if not salt.utils.platform.is_windows():
- import resource
- # Import Salt Testing libs
- from tests.support.parser import PNUM, print_header # isort:skip
- from tests.support.parser.cover import SaltCoverageTestingParser # isort:skip
- XML_OUTPUT_DIR = os.environ.get(
- "SALT_XML_TEST_REPORTS_DIR", os.path.join(TMP, "xml-test-reports")
- )
- HTML_OUTPUT_DIR = os.environ.get(
- "SALT_HTML_TEST_REPORTS_DIR", os.path.join(TMP, "html-test-reports")
- )
- TEST_DIR = os.path.dirname(INTEGRATION_TEST_DIR)
- try:
- if SALT_ROOT:
- os.chdir(SALT_ROOT)
- except OSError as err:
- print("Failed to change directory to salt's source: {0}".format(err))
- # Soft and hard limits on max open filehandles
- MAX_OPEN_FILES = {
- "integration": {"soft_limit": 3072, "hard_limit": 4096},
- "unit": {"soft_limit": 1024, "hard_limit": 2048},
- }
- # Combine info from command line options and test suite directories. A test
- # suite is a python package of test modules relative to the tests directory.
- TEST_SUITES_UNORDERED = {
- "unit": {"display_name": "Unit", "path": "unit"},
- "kitchen": {"display_name": "Kitchen", "path": "kitchen"},
- "multimaster": {"display_name": "Multimaster", "path": "multimaster"},
- "module": {"display_name": "Module", "path": "integration/modules"},
- "state": {"display_name": "State", "path": "integration/states"},
- "cli": {"display_name": "CLI", "path": "integration/cli"},
- "client": {"display_name": "Client", "path": "integration/client"},
- "doc": {"display_name": "Documentation", "path": "integration/doc"},
- "ext_pillar": {"display_name": "External Pillar", "path": "integration/pillar"},
- "grains": {"display_name": "Grains", "path": "integration/grains"},
- "shell": {"display_name": "Shell", "path": "integration/shell"},
- "runners": {"display_name": "Runners", "path": "integration/runners"},
- "renderers": {"display_name": "Renderers", "path": "integration/renderers"},
- "returners": {"display_name": "Returners", "path": "integration/returners"},
- "ssh-int": {"display_name": "SSH Integration", "path": "integration/ssh"},
- "spm": {"display_name": "SPM", "path": "integration/spm"},
- "loader": {"display_name": "Loader", "path": "integration/loader"},
- "outputter": {"display_name": "Outputter", "path": "integration/output"},
- "fileserver": {"display_name": "Fileserver", "path": "integration/fileserver"},
- "wheel": {"display_name": "Wheel", "path": "integration/wheel"},
- "api": {"display_name": "NetAPI", "path": "integration/netapi"},
- "cloud_provider": {
- "display_name": "Cloud Provider",
- "path": "integration/cloud/clouds",
- },
- "minion": {"display_name": "Minion", "path": "integration/minion"},
- "reactor": {"display_name": "Reactor", "path": "integration/reactor"},
- "proxy": {"display_name": "Proxy", "path": "integration/proxy"},
- "external_api": {"display_name": "ExternalAPIs", "path": "integration/externalapi"},
- "daemons": {"display_name": "Daemon", "path": "integration/daemons"},
- "sdb": {"display_name": "Sdb", "path": "integration/sdb"},
- "logging": {"display_name": "Logging", "path": "integration/logging"},
- }
- TEST_SUITES = collections.OrderedDict(
- sorted(TEST_SUITES_UNORDERED.items(), key=lambda x: x[0])
- )
- class SaltTestsuiteParser(SaltCoverageTestingParser):
- support_docker_execution = True
- support_destructive_tests_selection = True
- support_expensive_tests_selection = True
- source_code_basedir = SALT_ROOT
- def _get_suites(
- self,
- include_unit=False,
- include_cloud_provider=False,
- include_proxy=False,
- include_kitchen=False,
- include_multimaster=False,
- ):
- """
- Return a set of all test suites except unit and cloud provider tests
- unless requested
- """
- suites = set(TEST_SUITES.keys())
- if not include_unit:
- suites -= set(["unit"])
- if not include_cloud_provider:
- suites -= set(["cloud_provider"])
- if not include_proxy:
- suites -= set(["proxy"])
- if not include_kitchen:
- suites -= set(["kitchen"])
- if not include_multimaster:
- suites -= set(["multimaster"])
- return suites
- def _check_enabled_suites(
- self,
- include_unit=False,
- include_cloud_provider=False,
- include_proxy=False,
- include_kitchen=False,
- include_multimaster=False,
- ):
- """
- Query whether test suites have been enabled
- """
- suites = self._get_suites(
- include_unit=include_unit,
- include_cloud_provider=include_cloud_provider,
- include_proxy=include_proxy,
- include_kitchen=include_kitchen,
- include_multimaster=include_multimaster,
- )
- return any([getattr(self.options, suite) for suite in suites])
- def _enable_suites(
- self,
- include_unit=False,
- include_cloud_provider=False,
- include_proxy=False,
- include_kitchen=False,
- include_multimaster=False,
- ):
- """
- Enable test suites for current test run
- """
- suites = self._get_suites(
- include_unit=include_unit,
- include_cloud_provider=include_cloud_provider,
- include_proxy=include_proxy,
- include_kitchen=include_kitchen,
- include_multimaster=include_multimaster,
- )
- for suite in suites:
- setattr(self.options, suite, True)
- def setup_additional_options(self):
- self.add_option(
- "--sysinfo",
- default=False,
- action="store_true",
- help="Print some system information.",
- )
- self.add_option(
- "--transport",
- default="zeromq",
- choices=("zeromq", "tcp"),
- help=(
- "Select which transport to run the integration tests with, "
- "zeromq or tcp. Default: %default"
- ),
- )
- self.add_option(
- "--interactive",
- default=False,
- action="store_true",
- help="Do not run any tests. Simply start the daemons.",
- )
- self.output_options_group.add_option(
- "--no-colors",
- "--no-colours",
- default=False,
- action="store_true",
- help="Disable colour printing.",
- )
- self.test_selection_group.add_option(
- "-m",
- "--module",
- "--module-tests",
- dest="module",
- default=False,
- action="store_true",
- help="Run tests for modules",
- )
- self.test_selection_group.add_option(
- "-S",
- "--state",
- "--state-tests",
- dest="state",
- default=False,
- action="store_true",
- help="Run tests for states",
- )
- self.test_selection_group.add_option(
- "-C",
- "--cli",
- "--cli-tests",
- dest="cli",
- default=False,
- action="store_true",
- help="Run tests for cli",
- )
- self.test_selection_group.add_option(
- "-c",
- "--client",
- "--client-tests",
- dest="client",
- default=False,
- action="store_true",
- help="Run tests for client",
- )
- self.test_selection_group.add_option(
- "-d",
- "--doc",
- "--doc-tests",
- dest="doc",
- default=False,
- action="store_true",
- help="Run tests for documentation",
- )
- self.test_selection_group.add_option(
- "-I",
- "--ext-pillar",
- "--ext-pillar-tests",
- dest="ext_pillar",
- default=False,
- action="store_true",
- help="Run ext_pillar tests",
- )
- self.test_selection_group.add_option(
- "-G",
- "--grains",
- "--grains-tests",
- dest="grains",
- default=False,
- action="store_true",
- help="Run tests for grains",
- )
- self.test_selection_group.add_option(
- "-s",
- "--shell",
- "--shell-tests",
- dest="shell",
- default=False,
- action="store_true",
- help="Run shell tests",
- )
- self.test_selection_group.add_option(
- "-r",
- "--runners",
- "--runner-tests",
- dest="runners",
- default=False,
- action="store_true",
- help="Run salt/runners/*.py tests",
- )
- self.test_selection_group.add_option(
- "-R",
- "--renderers",
- "--renderer-tests",
- dest="renderers",
- default=False,
- action="store_true",
- help="Run salt/renderers/*.py tests",
- )
- self.test_selection_group.add_option(
- "--reactor",
- dest="reactor",
- default=False,
- action="store_true",
- help="Run salt/reactor/*.py tests",
- )
- self.test_selection_group.add_option(
- "--minion",
- "--minion-tests",
- dest="minion",
- default=False,
- action="store_true",
- help="Run tests for minion",
- )
- self.test_selection_group.add_option(
- "--returners",
- dest="returners",
- default=False,
- action="store_true",
- help="Run salt/returners/*.py tests",
- )
- self.test_selection_group.add_option(
- "--spm",
- dest="spm",
- default=False,
- action="store_true",
- help="Run spm integration tests",
- )
- self.test_selection_group.add_option(
- "--setup",
- dest="setup",
- default=False,
- action="store_true",
- help="Run setup integration tests",
- )
- self.test_selection_group.add_option(
- "-l",
- "--loader",
- "--loader-tests",
- dest="loader",
- default=False,
- action="store_true",
- help="Run loader tests",
- )
- self.test_selection_group.add_option(
- "-u",
- "--unit",
- "--unit-tests",
- dest="unit",
- default=False,
- action="store_true",
- help="Run unit tests",
- )
- self.test_selection_group.add_option(
- "-k",
- "--kitchen",
- "--kitchen-tests",
- dest="kitchen",
- default=False,
- action="store_true",
- help="Run kitchen tests",
- )
- self.test_selection_group.add_option(
- "--fileserver",
- "--fileserver-tests",
- dest="fileserver",
- default=False,
- action="store_true",
- help="Run Fileserver tests",
- )
- self.test_selection_group.add_option(
- "-w",
- "--wheel",
- "--wheel-tests",
- dest="wheel",
- action="store_true",
- default=False,
- help="Run wheel tests",
- )
- self.test_selection_group.add_option(
- "-o",
- "--outputter",
- "--outputter-tests",
- dest="outputter",
- action="store_true",
- default=False,
- help="Run outputter tests",
- )
- self.test_selection_group.add_option(
- "--cloud-provider",
- "--cloud-provider-tests",
- dest="cloud_provider",
- action="store_true",
- default=False,
- help=(
- "Run cloud provider tests. These tests create and delete "
- "instances on cloud providers. Must provide valid credentials "
- "in salt/tests/integration/files/conf/cloud.*.d to run tests."
- ),
- )
- self.test_selection_group.add_option(
- "--ssh",
- "--ssh-tests",
- dest="ssh",
- action="store_true",
- default=False,
- help="Run salt-ssh tests. These tests will spin up a temporary "
- "SSH server on your machine. In certain environments, this "
- "may be insecure! Default: False",
- )
- self.test_selection_group.add_option(
- "--ssh-int",
- dest="ssh-int",
- action="store_true",
- default=False,
- help="Run salt-ssh integration tests. Requires to be run with --ssh"
- "to spin up the SSH server on your machine.",
- )
- self.test_selection_group.add_option(
- "-A",
- "--api",
- "--api-tests",
- dest="api",
- action="store_true",
- default=False,
- help="Run salt-api tests",
- )
- self.test_selection_group.add_option(
- "--sdb",
- "--sdb-tests",
- dest="sdb",
- action="store_true",
- default=False,
- help="Run sdb tests",
- )
- self.test_selection_group.add_option(
- "-P",
- "--proxy",
- "--proxy-tests",
- dest="proxy",
- action="store_true",
- default=False,
- help="Run salt-proxy tests",
- )
- self.test_selection_group.add_option(
- "--external",
- "--external-api",
- "--external-api-tests",
- dest="external_api",
- action="store_true",
- default=False,
- help="Run venafi runner tests",
- )
- self.test_selection_group.add_option(
- "--daemons",
- "--daemon-tests",
- dest="daemons",
- action="store_true",
- default=False,
- help="Run salt/daemons/*.py tests",
- )
- self.test_selection_group.add_option(
- "--scheduler",
- dest="scheduler",
- action="store_true",
- default=False,
- help="Run scheduler integration tests",
- )
- self.test_selection_group.add_option(
- "--logging",
- dest="logging",
- action="store_true",
- default=False,
- help="Run logging integration tests",
- )
- self.test_selection_group.add_option(
- "--multimaster",
- dest="multimaster",
- action="store_true",
- default=False,
- help="Start multimaster daemons and run multimaster integration tests",
- )
- def validate_options(self):
- if self.options.cloud_provider or self.options.external_api:
- # Turn on expensive tests execution
- os.environ["EXPENSIVE_TESTS"] = "True"
- # This fails even with salt.utils.platform imported in the global
- # scope, unless we import it again here.
- import salt.utils.platform
- if salt.utils.platform.is_windows():
- import salt.utils.win_functions
- current_user = salt.utils.win_functions.get_current_user()
- if current_user == "SYSTEM":
- is_admin = True
- else:
- is_admin = salt.utils.win_functions.is_admin(current_user)
- if (
- self.options.coverage
- and any(
- (self.options.name, not is_admin, not self.options.run_destructive)
- )
- and self._check_enabled_suites(include_unit=True)
- ):
- warnings.warn("Test suite not running with elevated priviledges")
- else:
- is_admin = os.geteuid() == 0
- if (
- self.options.coverage
- and any(
- (self.options.name, not is_admin, not self.options.run_destructive)
- )
- and self._check_enabled_suites(include_unit=True)
- ):
- self.error(
- "No sense in generating the tests coverage report when "
- "not running the full test suite, including the "
- "destructive tests, as 'root'. It would only produce "
- "incorrect results."
- )
- # When no tests are specifically enumerated on the command line, setup
- # a default run: +unit -cloud_provider
- if not self.options.name and not self._check_enabled_suites(
- include_unit=True,
- include_cloud_provider=True,
- include_proxy=True,
- include_kitchen=True,
- include_multimaster=True,
- ):
- self._enable_suites(include_unit=True, include_multimaster=True)
- self.start_coverage(
- branch=True, source=[os.path.join(SALT_ROOT, "salt")],
- )
- # Print out which version of python this test suite is running on
- print(" * Python Version: {0}".format(" ".join(sys.version.split())))
- # Transplant configuration
- TestDaemon.transplant_configs(transport=self.options.transport)
- MultimasterTestDaemon.transplant_configs(transport=self.options.transport)
- def post_execution_cleanup(self):
- SaltCoverageTestingParser.post_execution_cleanup(self)
- if self.options.clean:
- TestDaemon.clean()
- def run_integration_suite(self, path="", display_name=""):
- """
- Run an integration test suite
- """
- full_path = os.path.join(TEST_DIR, path)
- return self.run_suite(
- full_path, display_name, suffix="test_*.py", failfast=self.options.failfast,
- )
- def start_daemons_only(self):
- if not salt.utils.platform.is_windows():
- self.set_filehandle_limits("integration")
- try:
- print_header(
- " * Setting up Salt daemons for interactive use",
- top=False,
- width=getattr(self.options, "output_columns", PNUM),
- )
- except TypeError:
- print_header(" * Setting up Salt daemons for interactive use", top=False)
- try:
- with TestDaemon(self):
- print_header(" * Salt daemons started")
- master_conf = TestDaemon.config("master")
- minion_conf = TestDaemon.config("minion")
- proxy_conf = TestDaemon.config("proxy")
- sub_minion_conf = TestDaemon.config("sub_minion")
- syndic_conf = TestDaemon.config("syndic")
- syndic_master_conf = TestDaemon.config("syndic_master")
- print_header(" * Syndic master configuration values (MoM)", top=False)
- print("interface: {0}".format(syndic_master_conf["interface"]))
- print("publish port: {0}".format(syndic_master_conf["publish_port"]))
- print("return port: {0}".format(syndic_master_conf["ret_port"]))
- print("\n")
- print_header(" * Syndic configuration values", top=True)
- print("interface: {0}".format(syndic_conf["interface"]))
- print("syndic master: {0}".format(syndic_conf["syndic_master"]))
- print(
- "syndic master port: {0}".format(syndic_conf["syndic_master_port"])
- )
- print("\n")
- print_header(" * Master configuration values", top=True)
- print("interface: {0}".format(master_conf["interface"]))
- print("publish port: {0}".format(master_conf["publish_port"]))
- print("return port: {0}".format(master_conf["ret_port"]))
- print("\n")
- print_header(" * Minion configuration values", top=True)
- print("interface: {0}".format(minion_conf["interface"]))
- print("master: {0}".format(minion_conf["master"]))
- print("master port: {0}".format(minion_conf["master_port"]))
- if minion_conf["ipc_mode"] == "tcp":
- print("tcp pub port: {0}".format(minion_conf["tcp_pub_port"]))
- print("tcp pull port: {0}".format(minion_conf["tcp_pull_port"]))
- print("\n")
- print_header(" * Sub Minion configuration values", top=True)
- print("interface: {0}".format(sub_minion_conf["interface"]))
- print("master: {0}".format(sub_minion_conf["master"]))
- print("master port: {0}".format(sub_minion_conf["master_port"]))
- if sub_minion_conf["ipc_mode"] == "tcp":
- print("tcp pub port: {0}".format(sub_minion_conf["tcp_pub_port"]))
- print("tcp pull port: {0}".format(sub_minion_conf["tcp_pull_port"]))
- print("\n")
- print_header(" * Proxy Minion configuration values", top=True)
- print("interface: {0}".format(proxy_conf["interface"]))
- print("master: {0}".format(proxy_conf["master"]))
- print("master port: {0}".format(proxy_conf["master_port"]))
- if minion_conf["ipc_mode"] == "tcp":
- print("tcp pub port: {0}".format(proxy_conf["tcp_pub_port"]))
- print("tcp pull port: {0}".format(proxy_conf["tcp_pull_port"]))
- print("\n")
- print_header(
- " Your client configuration is at {0}".format(
- TestDaemon.config_location()
- )
- )
- print(
- "To access the minion: salt -c {0} minion test.ping".format(
- TestDaemon.config_location()
- )
- )
- while True:
- time.sleep(1)
- except TestDaemonStartFailed:
- self.exit(status=2)
- def start_multimaster_daemons_only(self):
- if not salt.utils.platform.is_windows():
- self.set_filehandle_limits("integration")
- try:
- print_header(
- " * Setting up Salt daemons for interactive use",
- top=False,
- width=getattr(self.options, "output_columns", PNUM),
- )
- except TypeError:
- print_header(" * Setting up Salt daemons for interactive use", top=False)
- try:
- with MultimasterTestDaemon(self):
- print_header(" * Salt daemons started")
- master_conf = MultimasterTestDaemon.config("mm_master")
- sub_master_conf = MultimasterTestDaemon.config("mm_sub_master")
- minion_conf = MultimasterTestDaemon.config("mm_minion")
- sub_minion_conf = MultimasterTestDaemon.config("mm_sub_minion")
- print_header(" * Master configuration values", top=True)
- print("interface: {0}".format(master_conf["interface"]))
- print("publish port: {0}".format(master_conf["publish_port"]))
- print("return port: {0}".format(master_conf["ret_port"]))
- print("\n")
- print_header(" * Second master configuration values", top=True)
- print("interface: {0}".format(sub_master_conf["interface"]))
- print("publish port: {0}".format(sub_master_conf["publish_port"]))
- print("return port: {0}".format(sub_master_conf["ret_port"]))
- print("\n")
- print_header(" * Minion configuration values", top=True)
- print("interface: {0}".format(minion_conf["interface"]))
- print("masters: {0}".format(", ".join(minion_conf["master"])))
- if minion_conf["ipc_mode"] == "tcp":
- print("tcp pub port: {0}".format(minion_conf["tcp_pub_port"]))
- print("tcp pull port: {0}".format(minion_conf["tcp_pull_port"]))
- print("\n")
- print_header(" * Sub Minion configuration values", top=True)
- print("interface: {0}".format(sub_minion_conf["interface"]))
- print("masters: {0}".format(", ".join(sub_minion_conf["master"])))
- if sub_minion_conf["ipc_mode"] == "tcp":
- print("tcp pub port: {0}".format(sub_minion_conf["tcp_pub_port"]))
- print("tcp pull port: {0}".format(sub_minion_conf["tcp_pull_port"]))
- print("\n")
- print_header(
- " Your client configurations are at {0}".format(
- ", ".join(MultimasterTestDaemon.config_location())
- )
- )
- print("To access minions from different masters use:")
- for location in MultimasterTestDaemon.config_location():
- print(" salt -c {0} minion test.ping".format(location))
- while True:
- time.sleep(1)
- except TestDaemonStartFailed:
- self.exit(status=2)
- def set_filehandle_limits(self, limits="integration"):
- """
- Set soft and hard limits on open file handles at required thresholds
- for integration tests or unit tests
- """
- # Get current limits
- if salt.utils.platform.is_windows():
- import win32file
- prev_hard = win32file._getmaxstdio()
- prev_soft = 512
- else:
- prev_soft, prev_hard = resource.getrlimit(resource.RLIMIT_NOFILE)
- # Get required limits
- min_soft = MAX_OPEN_FILES[limits]["soft_limit"]
- min_hard = MAX_OPEN_FILES[limits]["hard_limit"]
- # Check minimum required limits
- set_limits = False
- if prev_soft < min_soft:
- soft = min_soft
- set_limits = True
- else:
- soft = prev_soft
- if prev_hard < min_hard:
- hard = min_hard
- set_limits = True
- else:
- hard = prev_hard
- # Increase limits
- if set_limits:
- print(
- " * Max open files settings is too low (soft: {0}, hard: {1}) "
- "for running the tests".format(prev_soft, prev_hard)
- )
- print(
- " * Trying to raise the limits to soft: "
- "{0}, hard: {1}".format(soft, hard)
- )
- try:
- if salt.utils.platform.is_windows():
- hard = 2048 if hard > 2048 else hard
- win32file._setmaxstdio(hard)
- else:
- resource.setrlimit(resource.RLIMIT_NOFILE, (soft, hard))
- except Exception as err: # pylint: disable=broad-except
- print(
- "ERROR: Failed to raise the max open files settings -> "
- "{0}".format(err)
- )
- print("Please issue the following command on your console:")
- print(" ulimit -n {0}".format(soft))
- self.exit()
- finally:
- print("~" * getattr(self.options, "output_columns", PNUM))
- def run_integration_tests(self):
- """
- Execute the integration tests suite
- """
- named_tests = []
- named_unit_test = []
- if self.options.name:
- for test in self.options.name:
- if test.startswith(
- (
- "tests.unit.",
- "unit.",
- "test.kitchen.",
- "kitchen.",
- "test.multimaster.",
- "multimaster.",
- )
- ):
- named_unit_test.append(test)
- continue
- named_tests.append(test)
- if (
- (
- self.options.unit
- or self.options.kitchen
- or self.options.multimaster
- or named_unit_test
- )
- and not named_tests
- and (
- self.options.from_filenames
- or not self._check_enabled_suites(include_cloud_provider=True)
- )
- ):
- # We're either not running any integration test suites, or we're
- # only running unit tests by passing --unit or by passing only
- # `unit.<whatever>` to --name. We don't need the tests daemon
- # running
- return [True]
- if not salt.utils.platform.is_windows():
- self.set_filehandle_limits("integration")
- try:
- print_header(
- " * Setting up Salt daemons to execute tests",
- top=False,
- width=getattr(self.options, "output_columns", PNUM),
- )
- except TypeError:
- print_header(" * Setting up Salt daemons to execute tests", top=False)
- status = []
- # Return an empty status if no tests have been enabled
- if (
- not self._check_enabled_suites(
- include_cloud_provider=True, include_proxy=True
- )
- and not self.options.name
- ):
- return status
- try:
- with TestDaemon(self):
- if self.options.name:
- for name in self.options.name:
- name = name.strip()
- if not name:
- continue
- if os.path.isfile(name):
- if not name.endswith(".py"):
- continue
- if name.startswith(
- (
- os.path.join("tests", "unit"),
- os.path.join("tests", "multimaster"),
- )
- ):
- continue
- results = self.run_suite(
- os.path.dirname(name),
- name,
- suffix=os.path.basename(name),
- failfast=self.options.failfast,
- load_from_name=False,
- )
- status.append(results)
- continue
- if name.startswith(
- (
- "tests.unit.",
- "unit.",
- "tests.multimaster.",
- "multimaster.",
- )
- ):
- continue
- results = self.run_suite(
- "",
- name,
- suffix="test_*.py",
- load_from_name=True,
- failfast=self.options.failfast,
- )
- status.append(results)
- return status
- for suite in TEST_SUITES:
- if (
- suite != "unit"
- and suite != "multimaster"
- and getattr(self.options, suite)
- ):
- status.append(self.run_integration_suite(**TEST_SUITES[suite]))
- return status
- except TestDaemonStartFailed:
- self.exit(status=2)
- def run_multimaster_tests(self):
- """
- Execute the multimaster tests suite
- """
- named_tests = []
- named_unit_test = []
- if self.options.name:
- for test in self.options.name:
- if test.startswith(("tests.multimaster.", "multimaster.")):
- named_tests.append(test)
- # TODO: check 'from_filenames'
- if not self.options.multimaster and not named_tests:
- # We're not running any multimaster test suites.
- return [True]
- if not salt.utils.platform.is_windows():
- self.set_filehandle_limits("integration")
- try:
- print_header(
- " * Setting up multimaster Salt daemons to execute tests",
- top=False,
- width=getattr(self.options, "output_columns", PNUM),
- )
- except TypeError:
- print_header(
- " * Setting up multimaster Salt daemons to execute tests", top=False
- )
- status = []
- try:
- with MultimasterTestDaemon(self):
- if self.options.name:
- for name in self.options.name:
- name = name.strip()
- if not name:
- continue
- if os.path.isfile(name):
- if not name.endswith(".py"):
- continue
- if not name.startswith(
- os.path.join("tests", "multimaster")
- ):
- continue
- results = self.run_suite(
- os.path.dirname(name),
- name,
- suffix=os.path.basename(name),
- load_from_name=False,
- )
- status.append(results)
- continue
- if not name.startswith(("tests.multimaster.", "multimaster.")):
- continue
- results = self.run_suite(
- "", name, suffix="test_*.py", load_from_name=True
- )
- status.append(results)
- return status
- status.append(self.run_integration_suite(**TEST_SUITES["multimaster"]))
- return status
- except TestDaemonStartFailed:
- self.exit(status=2)
- def run_unit_tests(self):
- """
- Execute the unit tests
- """
- named_unit_test = []
- if self.options.name:
- for test in self.options.name:
- if not test.startswith(("tests.unit.", "unit.")):
- continue
- named_unit_test.append(test)
- if not named_unit_test and (
- self.options.from_filenames or not self.options.unit
- ):
- # We are not explicitly running the unit tests and none of the
- # names passed to --name (or derived via --from-filenames) is a
- # unit test.
- return [True]
- status = []
- if self.options.unit:
- # MacOS needs more open filehandles for running unit test suite
- self.set_filehandle_limits("unit")
- results = self.run_suite(
- os.path.join(TEST_DIR, "unit"),
- "Unit",
- suffix="test_*.py",
- failfast=self.options.failfast,
- )
- status.append(results)
- # We executed ALL unittests, we can skip running unittests by name
- # below
- return status
- for name in named_unit_test:
- results = self.run_suite(
- os.path.join(TEST_DIR, "unit"),
- name,
- suffix="test_*.py",
- load_from_name=True,
- failfast=self.options.failfast,
- )
- status.append(results)
- return status
- def run_kitchen_tests(self):
- """
- Execute the kitchen tests
- """
- named_kitchen_test = []
- if self.options.name:
- for test in self.options.name:
- if not test.startswith(("tests.kitchen.", "kitchen.")):
- continue
- named_kitchen_test.append(test)
- if not self.options.kitchen and not named_kitchen_test:
- # We are not explicitly running the unit tests and none of the
- # names passed to --name is a unit test.
- return [True]
- status = []
- if self.options.kitchen:
- results = self.run_suite(
- os.path.join(TEST_DIR, "kitchen"), "Kitchen", suffix="test_*.py"
- )
- status.append(results)
- # We executed ALL unittests, we can skip running unittests by name
- # below
- return status
- for name in named_kitchen_test:
- results = self.run_suite(
- os.path.join(TEST_DIR, "kitchen"),
- name,
- suffix="test_*.py",
- load_from_name=True,
- )
- status.append(results)
- return status
- def main(**kwargs):
- """
- Parse command line options for running specific tests
- """
- try:
- parser = SaltTestsuiteParser(
- TEST_DIR,
- xml_output_dir=XML_OUTPUT_DIR,
- tests_logfile=os.path.join(SYS_TMP_DIR, "salt-runtests.log"),
- )
- parser.parse_args()
- # Override parser options (helpful when importing runtests.py and
- # running from within a REPL). Using kwargs.items() to avoid importing
- # six, as this feature will rarely be used.
- for key, val in kwargs.items():
- setattr(parser.options, key, val)
- overall_status = []
- if parser.options.interactive:
- if parser.options.multimaster:
- parser.start_multimaster_daemons_only()
- else:
- parser.start_daemons_only()
- status = parser.run_integration_tests()
- overall_status.extend(status)
- status = parser.run_multimaster_tests()
- overall_status.extend(status)
- status = parser.run_unit_tests()
- overall_status.extend(status)
- status = parser.run_kitchen_tests()
- overall_status.extend(status)
- false_count = overall_status.count(False)
- if false_count > 0:
- parser.finalize(1)
- parser.finalize(0)
- except KeyboardInterrupt:
- print("\nCaught keyboard interrupt. Exiting.\n")
- exit(0)
- if __name__ == "__main__":
- main()
|