示例#1
0
    def async_cmd_check(self):
        """
        Check progress of installation command that was started asynchronously.

        :return: True if command completed, False otherwise
        """
        if self.async_cmd_info is None:
            raise EasyBuildError("No installation command running asynchronously for %s", self.name)
        elif self.async_cmd_info is False:
            self.log.info("No asynchronous command was started for extension %s", self.name)
            return True
        else:
            self.log.debug("Checking on installation of extension %s...", self.name)
            # use small read size, to avoid waiting for a long time until sufficient output is produced
            res = check_async_cmd(*self.async_cmd_info, output_read_size=self.async_cmd_read_size)
            self.async_cmd_output += res['output']
            if res['done']:
                self.log.info("Installation of extension %s completed!", self.name)
                self.async_cmd_info = None
            else:
                self.async_cmd_check_cnt += 1
                self.log.debug("Installation of extension %s still running (checked %d times)",
                               self.name, self.async_cmd_check_cnt)
                # increase read size after sufficient checks,
                # to avoid that installation hangs due to output buffer filling up...
                if self.async_cmd_check_cnt % 10 == 0 and self.async_cmd_read_size < (1024 ** 2):
                    self.async_cmd_read_size *= 2

            return res['done']
示例#2
0
    def test_run_cmd_async(self):
        """Test asynchronously running of a shell command via run_cmd + complete_cmd."""

        os.environ['TEST'] = 'test123'

        test_cmd = "echo 'sleeping...'; sleep 2; echo $TEST"
        cmd_info = run_cmd(test_cmd, asynchronous=True)
        proc = cmd_info[0]

        # change value of $TEST to check that command is completed with correct environment
        os.environ['TEST'] = 'some_other_value'

        # initial poll should result in None, since it takes a while for the command to complete
        ec = proc.poll()
        self.assertEqual(ec, None)

        # wait until command is done
        while ec is None:
            time.sleep(1)
            ec = proc.poll()

        out, ec = complete_cmd(*cmd_info, simple=False)
        self.assertEqual(ec, 0)
        self.assertEqual(out, 'sleeping...\ntest123\n')

        # also test use of check_async_cmd function
        os.environ['TEST'] = 'test123'
        cmd_info = run_cmd(test_cmd, asynchronous=True)

        # first check, only read first 12 output characters
        # (otherwise we'll be waiting until command is completed)
        res = check_async_cmd(*cmd_info, output_read_size=12)
        self.assertEqual(res, {
            'done': False,
            'exit_code': None,
            'output': 'sleeping...\n'
        })

        # 2nd check with default output size (1024) gets full output
        # (keep checking until command is fully done)
        while not res['done']:
            res = check_async_cmd(*cmd_info, output=res['output'])
        self.assertEqual(res, {
            'done': True,
            'exit_code': 0,
            'output': 'sleeping...\ntest123\n'
        })

        # check asynchronous running of failing command
        error_test_cmd = "echo 'FAIL!' >&2; exit 123"
        cmd_info = run_cmd(error_test_cmd, asynchronous=True)
        time.sleep(1)
        error_pattern = 'cmd ".*" exited with exit code 123'
        self.assertErrorRegex(EasyBuildError, error_pattern, check_async_cmd,
                              *cmd_info)

        cmd_info = run_cmd(error_test_cmd, asynchronous=True)
        res = check_async_cmd(*cmd_info, fail_on_error=False)
        # keep checking until command is fully done
        while not res['done']:
            res = check_async_cmd(*cmd_info,
                                  fail_on_error=False,
                                  output=res['output'])
        self.assertEqual(res, {
            'done': True,
            'exit_code': 123,
            'output': "FAIL!\n"
        })

        # also test with a command that produces a lot of output,
        # since that tends to lock up things unless we frequently grab some output...
        verbose_test_cmd = ';'.join([
            "echo start",
            "for i in $(seq 1 50)",
            "do sleep 0.1",
            "for j in $(seq 1000)",
            "do echo foo",
            "done",
            "done",
            "echo done",
        ])
        cmd_info = run_cmd(verbose_test_cmd, asynchronous=True)
        proc = cmd_info[0]

        output = ''
        ec = proc.poll()
        self.assertEqual(ec, None)

        while ec is None:
            time.sleep(1)
            output += get_output_from_process(proc)
            ec = proc.poll()

        out, ec = complete_cmd(*cmd_info, simple=False, output=output)
        self.assertEqual(ec, 0)
        self.assertTrue(out.startswith('start\n'))
        self.assertTrue(out.endswith('\ndone\n'))

        # also test use of check_async_cmd on verbose test command
        cmd_info = run_cmd(verbose_test_cmd, asynchronous=True)

        error_pattern = r"Number of output bytes to read should be a positive integer value \(or zero\)"
        self.assertErrorRegex(EasyBuildError,
                              error_pattern,
                              check_async_cmd,
                              *cmd_info,
                              output_read_size=-1)
        self.assertErrorRegex(EasyBuildError,
                              error_pattern,
                              check_async_cmd,
                              *cmd_info,
                              output_read_size='foo')

        # with output_read_size set to 0, no output is read yet, only status of command is checked
        res = check_async_cmd(*cmd_info, output_read_size=0)
        self.assertEqual(res['done'], False)
        self.assertEqual(res['exit_code'], None)
        self.assertEqual(res['output'], '')

        res = check_async_cmd(*cmd_info)
        self.assertEqual(res['done'], False)
        self.assertEqual(res['exit_code'], None)
        self.assertTrue(res['output'].startswith('start\n'))
        self.assertFalse(res['output'].endswith('\ndone\n'))
        # keep checking until command is complete
        while not res['done']:
            res = check_async_cmd(*cmd_info, output=res['output'])
        self.assertEqual(res['done'], True)
        self.assertEqual(res['exit_code'], 0)
        self.assertTrue(res['output'].startswith('start\n'))
        self.assertTrue(res['output'].endswith('\ndone\n'))