def test_process_bad_pgid(self): """ If a timeout is requested but the process is not the root of the process group, raise an exception. """ stdout = "stdout\n" stderr = "stderr\n" cmd = process_cmd_template.format(process_target, stdout, stderr) process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=os.environ) if sys.version_info < (2, 7): self.assertRaises(ExtensionError, capture_from_process, process, cmd, 10) else: with self.assertRaises(ExtensionError) as ee: capture_from_process(process, cmd, 10) body = str(ee.exception) if sys.version_info >= (3, 2): self.assertRegex(body, "process group") else: self.assertRegexpMatches(body, "process group")
def test_process_bad_pgid(self): """ If a timeout is requested but the process is not the root of the process group, raise an exception. """ stdout = "stdout\n" stderr = "stderr\n" cmd = process_cmd_template.format(process_target, stdout, stderr) process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=os.environ) if sys.version_info < (2, 7): self.assertRaises(ExtensionError, capture_from_process, process, cmd, 10) else: with self.assertRaises(ExtensionError) as ee: capture_from_process(process, cmd, 10) body = str(ee.exception) if sys.version_info >= (3, 2): self.assertRegex(body, "process group") else: self.assertRegexpMatches(body, "process group")
def test_process_timeout_non_forked(self): """ non-forked process runs for 20 seconds, timeout is 10 seconds we expect: - test to run in just over 10 seconds - exception should be thrown - output should be collected """ cmd = "{0} -t 20".format(process_target) process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=os.environ, preexec_fn=os.setsid) try: capture_from_process(process, 'sleep 20', 10, EXTENSION_ERROR_CODE) self.fail('Timeout exception was expected') except ExtensionError as e: body = str(e) self.assertTrue('Timeout(10)' in body) self.assertTrue('Iteration 9' in body) self.assertFalse('Iteration 11' in body) self.assertEqual(EXTENSION_ERROR_CODE, e.code) except Exception as gen_ex: self.fail('Unexpected exception: {0}'.format(gen_ex))
def launch_command(self, cmd, timeout=300): begin_utc = datetime.datetime.utcnow() self.logger.verbose("Launch command: [{0}]", cmd) base_dir = self.get_base_dir() try: # This should be .run(), but due to the wide variety # of Python versions we must support we must use .communicate(). # Some extensions erroneously begin cmd with a slash; don't interpret those # as root-relative. (Issue #1170) full_path = os.path.join(base_dir, cmd.lstrip(os.sep)) process = subprocess.Popen(full_path, shell=True, cwd=base_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=os.environ, preexec_fn=os.setsid) except OSError as e: raise ExtensionError("Failed to launch '{0}': {1}".format( full_path, e.strerror)) msg = capture_from_process(process, cmd, timeout) ret = process.poll() if ret is None or ret != 0: raise ExtensionError("Non-zero exit code: {0}, {1}\n{2}".format( ret, cmd, msg)) duration = elapsed_milliseconds(begin_utc) self.report_event(message="{0}\n{1}".format(cmd, msg), duration=duration, log_event=False)
def test_process_behaved_forked(self): """ forked process runs for 10 seconds, timeout is 20 seconds we expect: - test to run in under 3 seconds - no exception should be thrown - output is not collected """ cmd = "{0} -t 10 &".format(process_target) process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=os.environ, preexec_fn=os.setsid) start = datetime.datetime.utcnow() try: body = capture_from_process(process, 'sleep 10 &', 20) except Exception as e: self.fail('No exception should be thrown for a well behaved process which forks: {0}'.format(e)) duration = datetime.datetime.utcnow() - start self.assertTrue(duration < datetime.timedelta(seconds=3)) self.assertEqual('[stdout]\ncannot collect stdout\n\n[stderr]\n', body)
def launch_command(self, cmd, timeout=300, extension_error_code=1000, env=None): begin_utc = datetime.datetime.utcnow() self.logger.verbose("Launch command: [{0}]", cmd) base_dir = self.get_base_dir() if env is None: env = {} env.update(os.environ) try: # This should be .run(), but due to the wide variety # of Python versions we must support we must use .communicate(). # Some extensions erroneously begin cmd with a slash; don't interpret those # as root-relative. (Issue #1170) full_path = os.path.join(base_dir, cmd.lstrip(os.path.sep)) def pre_exec_function(): """ Change process state before the actual target process is started. Effectively, this runs between the fork() and the exec() of sub-process creation. :return: """ os.setsid() CGroups.add_to_extension_cgroup(self.ext_handler.name) process = subprocess.Popen(full_path, shell=True, cwd=base_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, preexec_fn=pre_exec_function) except OSError as e: raise ExtensionError("Failed to launch '{0}': {1}".format(full_path, e.strerror), code=extension_error_code) cg = CGroups.for_extension(self.ext_handler.name) CGroupsTelemetry.track_extension(self.ext_handler.name, cg) msg = capture_from_process(process, cmd, timeout, extension_error_code) ret = process.poll() if ret is None: raise ExtensionError("Process {0} was not terminated: {1}\n{2}".format(process.pid, cmd, msg), code=extension_error_code) if ret != 0: raise ExtensionError("Non-zero exit code: {0}, {1}\n{2}".format(ret, cmd, msg), code=extension_error_code) duration = elapsed_milliseconds(begin_utc) log_msg = "{0}\n{1}".format(cmd, "\n".join([line for line in msg.split('\n') if line != ""])) self.logger.verbose(log_msg) self.report_event(message=log_msg, duration=duration, log_event=False)
def launch_command(self, cmd, timeout=300, extension_error_code=1000, env=None): begin_utc = datetime.datetime.utcnow() self.logger.verbose("Launch command: [{0}]", cmd) base_dir = self.get_base_dir() if env is None: env = {} env.update(os.environ) try: # This should be .run(), but due to the wide variety # of Python versions we must support we must use .communicate(). # Some extensions erroneously begin cmd with a slash; don't interpret those # as root-relative. (Issue #1170) full_path = os.path.join(base_dir, cmd.lstrip(os.path.sep)) def pre_exec_function(): """ Change process state before the actual target process is started. Effectively, this runs between the fork() and the exec() of sub-process creation. :return: """ os.setsid() CGroups.add_to_extension_cgroup(self.ext_handler.name) process = subprocess.Popen(full_path, shell=True, cwd=base_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, preexec_fn=pre_exec_function) except OSError as e: raise ExtensionError("Failed to launch '{0}': {1}".format(full_path, e.strerror), code=extension_error_code) cg = CGroups.for_extension(self.ext_handler.name) CGroupsTelemetry.track_extension(self.ext_handler.name, cg) msg = capture_from_process(process, cmd, timeout, extension_error_code) ret = process.poll() if ret is None: raise ExtensionError("Process {0} was not terminated: {1}\n{2}".format(process.pid, cmd, msg), code=extension_error_code) if ret != 0: raise ExtensionError("Non-zero exit code: {0}, {1}\n{2}".format(ret, cmd, msg), code=extension_error_code) duration = elapsed_milliseconds(begin_utc) log_msg = "{0}\n{1}".format(cmd, "\n".join([line for line in msg.split('\n') if line != ""])) self.logger.verbose(log_msg) self.report_event(message=log_msg, duration=duration, log_event=False)
def test_process_stdout_stderr(self): """ If the command has no timeout, the process need not be the leader of its own process group. """ stdout = "The quick brown fox jumps over the lazy dog.\n" stderr = "The five boxing wizards jump quickly.\n" expected = "[stdout]\n{0}\n\n[stderr]\n{1}".format(stdout, stderr) cmd = process_cmd_template.format(process_target, stdout, stderr) process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=os.environ) actual = capture_from_process(process, cmd) self.assertEqual(expected, actual)
def test_process_stdout_stderr(self): """ If the command has no timeout, the process need not be the leader of its own process group. """ stdout = "The quick brown fox jumps over the lazy dog.\n" stderr = "The five boxing wizards jump quickly.\n" expected = "[stdout]\n{0}\n\n[stderr]\n{1}".format(stdout, stderr) cmd = process_cmd_template.format(process_target, stdout, stderr) process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=os.environ) actual = capture_from_process(process, cmd) self.assertEqual(expected, actual)
def test_process_behaved_non_forked(self): """ non-forked process runs for 10 seconds, timeout is 20 seconds we expect: - test to run in just over 10 seconds - no exception should be thrown - output should be collected """ cmd = "{0} -t 10".format(process_target) process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=os.environ, preexec_fn=os.setsid) try: body = capture_from_process(process, 'sleep 10', 20) except Exception as gen_ex: self.fail('Unexpected exception: {0}'.format(gen_ex)) self.assertFalse('Timeout' in body) self.assertTrue('Iteration 9' in body) self.assertTrue('Iteration 10' in body)