def test(self) -> CheckResult: create_files(self._test_case.files) # startThreads(testCase.getProcesses()) if Settings.do_reset_output: OutputHandler.reset_output() result = None try: result = self._test_runner.test(self) except BaseException as ex: self.set_error_in_test(ex) # stopThreads(testCase.getProcesses(), pool) delete_files(self._test_case.files) if result is None: self._check_errors() if isinstance(self._error_in_test, TestPassed): result = correct() if result is None: raise UnexpectedError("Result is None after testing") return result
def _fail(self, reason: str): from hstest.stage_test import StageTest StageTest.curr_test_run.set_error_in_test( InfiniteLoopException(reason)) from hstest.dynamic.output.output_handler import OutputHandler OutputHandler.print("INFINITE LOOP DETECTED") raise ExitException()
def __get_execution_output(self) -> str: OutputHandler.print('Program executor - __get_execution_output()') if self._machine.in_state(ProgramState.EXCEPTION_THROWN): raise TestedProgramThrewException() OutputHandler.print( 'Program executor - __get_execution_output() NO EXCEPTION') if self.__return_output_after_execution: return self.get_output() return ""
def _request_input(self): if self.__no_more_input: return None OutputHandler.print( 'Program executor - _request_input() invoked, set state WAITING') self._machine.set_and_wait(ProgramState.WAITING, ProgramState.RUNNING) input_local = self._input self._input = None return input_local
def eject_next_line(self) -> Optional[str]: if len(self._input_lines) == 0: self._eject_next_input() if len(self._input_lines) == 0: return None next_line = self._input_lines.pop(0) + '\n' OutputHandler.inject_input('> ' + next_line) loop_detector.input_requested() return next_line
def set_up(): with SystemHandler.__lock: if SystemHandler.__locked: raise ErrorWithFeedback( "Cannot start the testing process more than once") SystemHandler.__locked = True SystemHandler.__locker_thread = current_thread() OutputHandler.replace_stdout() InputHandler.replace_input() ExitHandler.replace_exit()
def __str__(self): if self.test_number == 0: when_error_happened = ' during testing' elif self.test_number > 0: when_error_happened = f' in test #{self.test_number}' else: when_error_happened = '' result = self.get_type() + when_error_happened if self.error_text: result += '\n\n' + self.error_text.strip() if self.stack_trace: result += '\n\n' + self.stack_trace.strip() full_out = OutputHandler.get_dynamic_output() full_err = str_to_stacktrace(OutputHandler.get_err()) arguments = self.__get_args() trimmed_out = self.__trim_lines(full_out) trimmed_err = self.__trim_lines(full_err) worth_showing_err = len(full_err.strip()) != 0 and full_err.strip() not in result worth_showing_out = len(full_out.strip()) != 0 and full_out.strip() not in result worth_showing_args = len(arguments.strip()) != 0 from hstest.stage_test import StageTest test_run = StageTest.curr_test_run if worth_showing_out or worth_showing_err or worth_showing_args: result += '\n\n' if worth_showing_out or worth_showing_err: result += "Please find below the output of your program during this failed test.\n" if test_run and test_run.input_used: result += "Note that the '>' character indicates the beginning of the input line.\n" result += "\n---\n\n" if worth_showing_args: result += arguments + '\n\n' if worth_showing_out: if worth_showing_err: result += 'stdout:\n' result += trimmed_out + '\n\n' if worth_showing_err: result += "stderr:\n" + trimmed_err return result.strip()
def check_pipe(self, read_pipe, write_pipe, write_stdout=False, write_stderr=False): with self.lock: self._pipes_watching += 1 OutputHandler.print( f'Start watching {"stdout" if write_stdout else "stderr"} ' f'Pipes watching = {self._pipes_watching}') while not self.is_finished(): try: new_output = read_pipe.read(1) except ValueError: self.check_alive() continue if len(new_output) == 0: with self.lock: self._pipes_watching -= 1 OutputHandler.print( f'Out of {"stdout" if write_stdout else "stderr"}... ' f'Maybe program terminated. Pipes watching = {self._pipes_watching}' ) if self._pipes_watching == 0: self._alive = False self.terminate() break try: if self.register_output: write_pipe.write(new_output) except ExitException: self._alive = False self.terminate() break if write_stdout: self.stdout += new_output if write_stderr: self.stderr += new_output self.check_alive()
def tear_down(): if current_thread() != SystemHandler.__locker_thread: raise ErrorWithFeedback( "Cannot tear down the testing process from the other thread") with SystemHandler.__lock: if not SystemHandler.__locked: raise ErrorWithFeedback( "Cannot tear down the testing process more than once") SystemHandler.__locked = False SystemHandler.__locker_thread = None OutputHandler.revert_stdout() InputHandler.revert_input() ExitHandler.revert_exit()
def start(self, *args: str): if not self._machine.in_state(ProgramState.NOT_STARTED): raise UnexpectedError(f"Cannot start the program {self} twice") self._launch(*args) if self.__in_background: self._machine.wait_not_state(ProgramState.NOT_STARTED) return "" self._machine.wait_not_states(ProgramState.NOT_STARTED, ProgramState.RUNNING) OutputHandler.print( 'Program executor - after waiting in start() method') return self.__get_execution_output()
def __str__(self): if self.test_number == 0: when_error_happened = ' during testing' else: when_error_happened = f' in test #{self.test_number}' result = self.get_type() + when_error_happened if self.error_text: result += '\n\n' + self.error_text.strip() if self.stack_trace: result += '\n\n' + self.stack_trace.strip() full_log = OutputHandler.get_dynamic_output() worth_showing_log = len( full_log.strip()) != 0 and full_log.strip() not in result arguments = '' from hstest.stage_test import StageTest test_run = StageTest.curr_test_run if test_run is not None: tested_programs = test_run.tested_programs programs_with_args = [ p for p in tested_programs if len(p.run_args) ] for pr in programs_with_args: arguments += 'Arguments' if len(tested_programs) > 1: arguments += f' for {pr}' pr_args = [ f'"{arg}"' if ' ' in arg else arg for arg in pr.run_args ] arguments += f': {" ".join(pr_args)}\n' arguments = arguments.strip() if worth_showing_log or len(arguments): result += '\n\n' if worth_showing_log: result += "Please find below the output of your program during this failed test.\n" if test_run and test_run.input_used: result += "Note that the '>' character indicates the beginning of the input line.\n" result += "\n---\n\n" if len(arguments): result += arguments + '\n\n' if worth_showing_log: result += full_log return result.strip()
def __init__(self, test_num: int, cause: BaseException): super().__init__() self.test_number = test_num self.error_text = 'We have recorded this bug ' \ 'and will fix it soon.\n\n' + get_report() self.stack_trace = get_stacktrace(cause, hide_internals=False) if isinstance(cause, UnexpectedError) and cause.exception is not None: self.stack_trace += '\n' + get_stacktrace(cause.exception, hide_internals=False) program_stderr: str = OutputHandler.get_err() if program_stderr: self.stack_trace = self.stack_trace.strip( ) + '\n\n' + program_stderr
def check_cpuload(self): while self._alive: try: cpu_load = self.ps.cpu_percent() OutputHandler.print(f'Check cpuload - {cpu_load}') self.cpu_load_history.append(cpu_load) if len(self.cpu_load_history) > self.cpu_load_length: self.cpu_load_history.pop(0) except NoSuchProcess: OutputHandler.print('Check cpuload finished, waiting output') self.wait_output() OutputHandler.print( 'Check cpuload finished, set alive = false') self._alive = False break sleep(0.01) self.check_alive()
def test(self, test_run: TestRun) -> Optional[CheckResult]: test_case = test_run.test_case result: CheckResult = self._run_file(test_run) if result is None: error = test_run.error_in_test if error is None: try: return test_case.check_func(OutputHandler.get_output(), test_case.attach) except BaseException as ex: error = ex test_run.set_error_in_test(error) if isinstance(error, TestPassed): return correct() elif isinstance(error, WrongAnswer): return wrong(error.feedback) else: return None return result
def tear_down(): OutputHandler.revert_stdout() InputHandler.revert_input() ExitHandler.revert_exit()
def get_output(self) -> str: return OutputHandler.get_partial_output()
def __print_test_num(self, num: int): total_tests = '' if num == self._curr_test_global else f' ({self._curr_test_global})' OutputHandler.get_real_out().write( RED_BOLD + f'\nStart test {num}{total_tests}' + RESET + '\n' )
def terminate(self): OutputHandler.print('Terminate called') with self.lock: OutputHandler.print('Terminate - LOCK ACQUIRED') if not self.terminated: OutputHandler.print('Terminate - BEFORE WAIT STDERR') self.wait_output() OutputHandler.print('Terminate - AFTER WAIT STDERR') self._alive = False OutputHandler.print('Terminate - SELF ALIVE == FALSE') is_exit_replaced = ExitHandler.is_replaced() if is_exit_replaced: ExitHandler.revert_exit() OutputHandler.print('Terminate - EXIT REVERTED') try: parent = Process(self.process.pid) OutputHandler.print(f'Terminate - parent == {parent}') for child in parent.children(recursive=True): OutputHandler.print(f'Terminate - child kill {child}') child.kill() OutputHandler.print(f'Terminate - parent kill {parent}') parent.kill() except NoSuchProcess: OutputHandler.print(f'Terminate - NO SUCH PROCESS') pass finally: OutputHandler.print(f'Terminate - finally before kill') self.process.kill() OutputHandler.print(f'Terminate - finally before wait') self.process.wait() self.process.stdout.close() self.process.stderr.close() self.process.stdin.close() if is_exit_replaced: ExitHandler.replace_exit() OutputHandler.print(f'Terminate - EXIT REPLACED AGAIN') self.terminated = True OutputHandler.print(f'Terminate - TERMINATED') OutputHandler.print(f'Terminate - finished')
def set_up(): OutputHandler.replace_stdout() InputHandler.replace_input() ExitHandler.replace_exit()