Пример #1
0
    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.')):
                    named_unit_test.append(test)
                    continue
                named_tests.append(test)

        if (self.options.unit or named_unit_test) and not named_tests and 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.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

        with TestDaemon(self):
            if self.options.name:
                for name in self.options.name:
                    if os.path.isfile(name):
                        if not name.endswith('.py'):
                            continue
                        if name.startswith(os.path.join('tests', 'unit')):
                            continue
                        results = self.run_suite(os.path.dirname(name),
                                                 name,
                                                 suffix=os.path.basename(name),
                                                 load_from_name=False)
                        status.append(results)
                        continue
                    if name.startswith(('tests.unit.', 'unit.')):
                        continue
                    results = self.run_suite('', name, suffix='test_*.py', load_from_name=True)
                    status.append(results)
            for suite in TEST_SUITES:
                if suite != 'unit' and getattr(self.options, suite):
                    status.append(self.run_integration_suite(**TEST_SUITES[suite]))
        return status
Пример #2
0
    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)

        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)
Пример #3
0
    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)
Пример #4
0
    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)
Пример #5
0
    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)
Пример #6
0
    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)
Пример #7
0
    def __enter__(self):
        '''
        Start a master and minion
        '''
        # Setup the multiprocessing logging queue listener
        salt_log_setup.setup_multiprocessing_logging_listener(
            self.mm_master_opts)

        # Set up PATH to mockbin
        self._enter_mockbin()

        self.master_targets = [self.mm_master_opts, self.mm_sub_master_opts]
        self.minion_targets = set(['minion', 'sub_minion'])

        if self.parser.options.transport == 'zeromq':
            self.start_zeromq_daemons()
        elif self.parser.options.transport == 'raet':
            self.start_raet_daemons()
        elif self.parser.options.transport == 'tcp':
            self.start_tcp_daemons()

        self.pre_setup_minions()
        self.setup_minions()

        #if getattr(self.parser.options, 'ssh', False):
        #self.prep_ssh()

        self.wait_for_minions(time.time(), self.MINIONS_CONNECT_TIMEOUT)

        if self.parser.options.sysinfo:
            try:
                print_header('~~~~~~~ Versions Report ',
                             inline=True,
                             width=getattr(self.parser.options,
                                           'output_columns', PNUM))
            except TypeError:
                print_header('~~~~~~~ Versions Report ', inline=True)

            print('\n'.join(salt.version.versions_report()))

            try:
                print_header('~~~~~~~ Minion Grains Information ',
                             inline=True,
                             width=getattr(self.parser.options,
                                           'output_columns', PNUM))
            except TypeError:
                print_header('~~~~~~~ Minion Grains Information ', inline=True)

            grains = self.client.cmd('minion', 'grains.items')

            minion_opts = self.mm_minion_opts.copy()
            minion_opts['color'] = self.parser.options.no_colors is False
            salt.output.display_output(grains, 'grains', minion_opts)

        try:
            print_header('=',
                         sep='=',
                         inline=True,
                         width=getattr(self.parser.options, 'output_columns',
                                       PNUM))
        except TypeError:
            print_header('', sep='=', inline=True)

        try:
            return self
        finally:
            self.post_setup_minions()
Пример #8
0
    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)
Пример #9
0
    def __enter__(self):
        """
        Start a master and minion
        """
        # Setup the multiprocessing logging queue listener
        salt_log_setup.setup_multiprocessing_logging_listener(
            self.mm_master_opts)

        # Set up PATH to mockbin
        self._enter_mockbin()

        self.master_targets = [self.mm_master_opts, self.mm_sub_master_opts]
        self.minion_targets = set(["mm-minion", "mm-sub-minion"])

        if self.parser.options.transport == "zeromq":
            self.start_zeromq_daemons()
        elif self.parser.options.transport == "raet":
            self.start_raet_daemons()
        elif self.parser.options.transport == "tcp":
            self.start_tcp_daemons()

        self.pre_setup_minions()
        self.setup_minions()

        # if getattr(self.parser.options, 'ssh', False):
        # self.prep_ssh()

        self.wait_for_minions(time.time(), self.MINIONS_CONNECT_TIMEOUT)

        if self.parser.options.sysinfo:
            try:
                print_header(
                    "~~~~~~~ Versions Report ",
                    inline=True,
                    width=getattr(self.parser.options, "output_columns", PNUM),
                )
            except TypeError:
                print_header("~~~~~~~ Versions Report ", inline=True)

            print("\n".join(salt.version.versions_report()))

            try:
                print_header(
                    "~~~~~~~ Minion Grains Information ",
                    inline=True,
                    width=getattr(self.parser.options, "output_columns", PNUM),
                )
            except TypeError:
                print_header("~~~~~~~ Minion Grains Information ", inline=True)

            grains = self.client.cmd("minion", "grains.items")

            minion_opts = self.mm_minion_opts.copy()
            minion_opts["color"] = self.parser.options.no_colors is False
            salt.output.display_output(grains, "grains", minion_opts)

        try:
            print_header(
                "=",
                sep="=",
                inline=True,
                width=getattr(self.parser.options, "output_columns", PNUM),
            )
        except TypeError:
            print_header("", sep="=", inline=True)

        try:
            return self
        finally:
            self.post_setup_minions()
Пример #10
0
    def __enter__(self):
        '''
        Start a master and minion
        '''
        # Setup the multiprocessing logging queue listener
        salt_log_setup.setup_multiprocessing_logging_listener(
            self.master_opts
        )

        # Set up PATH to mockbin
        self._enter_mockbin()

        if not HAS_GITFS:
            sys.stdout.write(
                ' * {LIGHT_RED}No suitable provider for git_pillar is installed. Install\n'
                '   GitPython or Pygit2.{ENDC}\n'.format(
                    **self.colors
                )
            )

        if self.parser.options.transport == 'zeromq':
            self.start_zeromq_daemons()
        elif self.parser.options.transport == 'raet':
            self.start_raet_daemons()
        elif self.parser.options.transport == 'tcp':
            self.start_tcp_daemons()

        self.minion_targets = set(['minion', 'sub_minion'])
        self.pre_setup_minions()
        self.setup_minions()

        if getattr(self.parser.options, 'ssh', False):
            self.prep_ssh()

        if self.parser.options.sysinfo:
            try:
                print_header(
                    '~~~~~~~ Versions Report ', inline=True,
                    width=getattr(self.parser.options, 'output_columns', PNUM)
                )
            except TypeError:
                print_header('~~~~~~~ Versions Report ', inline=True)

            print('\n'.join(salt.version.versions_report()))

            try:
                print_header(
                    '~~~~~~~ Minion Grains Information ', inline=True,
                    width=getattr(self.parser.options, 'output_columns', PNUM)
                )
            except TypeError:
                print_header('~~~~~~~ Minion Grains Information ', inline=True)

            grains = self.client.cmd('minion', 'grains.items')

            minion_opts = self.minion_opts.copy()
            minion_opts['color'] = self.parser.options.no_colors is False
            salt.output.display_output(grains, 'grains', minion_opts)

        try:
            print_header(
                '=', sep='=', inline=True,
                width=getattr(self.parser.options, 'output_columns', PNUM)
            )
        except TypeError:
            print_header('', sep='=', inline=True)

        try:
            return self
        finally:
            self.post_setup_minions()
Пример #11
0
    def wait_for_minion_connections(self, targets, timeout):
        salt.utils.appendproctitle('WaitForMinionConnections')
        sys.stdout.write(
            ' {LIGHT_BLUE}*{ENDC} Waiting at most {0} for minions({1}) to '
            'connect back\n'.format(
                (timeout > 60 and
                 timedelta(seconds=timeout) or
                 '{0} secs'.format(timeout)),
                ', '.join(targets),
                **self.colors
            )
        )
        sys.stdout.flush()
        expected_connections = set(targets)
        now = datetime.now()
        expire = now + timedelta(seconds=timeout)
        while now <= expire:
            sys.stdout.write(
                '\r{0}\r'.format(
                    ' ' * getattr(self.parser.options, 'output_columns', PNUM)
                )
            )
            sys.stdout.write(
                ' * {LIGHT_YELLOW}[Quit in {0}]{ENDC} Waiting for {1}'.format(
                    '{0}'.format(expire - now).rsplit('.', 1)[0],
                    ', '.join(expected_connections),
                    **self.colors
                )
            )
            sys.stdout.flush()

            try:
                responses = self.client.cmd(
                    list(expected_connections), 'test.ping', tgt_type='list',
                )
            # we'll get this exception if the master process hasn't finished starting yet
            except SaltClientError:
                time.sleep(0.1)
                now = datetime.now()
                continue
            for target in responses:
                if target not in expected_connections:
                    # Someone(minion) else "listening"?
                    continue
                expected_connections.remove(target)
                sys.stdout.write(
                    '\r{0}\r'.format(
                        ' ' * getattr(self.parser.options, 'output_columns',
                                      PNUM)
                    )
                )
                sys.stdout.write(
                    '   {LIGHT_GREEN}*{ENDC} {0} connected.\n'.format(
                        target, **self.colors
                    )
                )
                sys.stdout.flush()

            if not expected_connections:
                return

            time.sleep(1)
            now = datetime.now()
        else:  # pylint: disable=W0120
            print(
                '\n {LIGHT_RED}*{ENDC} WARNING: Minions failed to connect '
                'back. Tests requiring them WILL fail'.format(**self.colors)
            )
            try:
                print_header(
                    '=', sep='=', inline=True,
                    width=getattr(self.parser.options, 'output_columns', PNUM)

                )
            except TypeError:
                print_header('=', sep='=', inline=True)
            raise SystemExit()