diff --git a/src/ert/resources/forward-models/res/script/ecl_run.py b/src/ert/resources/forward-models/res/script/ecl_run.py index 93dec112d2b..6975da5d632 100644 --- a/src/ert/resources/forward-models/res/script/ecl_run.py +++ b/src/ert/resources/forward-models/res/script/ecl_run.py @@ -280,6 +280,10 @@ def runPath(self): def baseName(self): return self.base_name + @property + def prt_path(self): + return Path(self.run_path) / (self.baseName() + ".PRT") + def numCpu(self): return self.num_cpu @@ -489,6 +493,7 @@ def summary_block(self): return ecl_sum def assertECLEND(self): + tail_length = 5000 result = self.readECLEND() if result.errors > 0: error_list = self.parseErrors() @@ -502,7 +507,9 @@ def assertECLEND(self): extra_message = ( f"\n\nWarning, mismatch between stated Error count ({result.errors}) " f"and number of ERROR messages found in PRT ({len(error_messages)})." - ) + f"\n\nTail ({tail_length} bytes) of PRT-file {self.prt_path}:\n\n" + ) + tail_textfile(self.prt_path, 5000) + raise EclError( "Eclipse simulation failed with:" f"{result.errors:d} errors:\n\n{error_and_slave_msg}{extra_message}" @@ -517,7 +524,7 @@ def readECLEND(self): report_file = os.path.join(self.run_path, f"{self.base_name}.ECLEND") if not os.path.isfile(report_file): - report_file = os.path.join(self.run_path, f"{self.base_name}.PRT") + report_file = self.prt_path errors = None bugs = None @@ -539,12 +546,11 @@ def readECLEND(self): def parseErrors(self) -> List[str]: """Extract multiline ERROR messages from the PRT file""" - prt_file = os.path.join(self.runPath(), f"{self.baseName()}.PRT") error_list = [] error_e100_regexp = re.compile(error_pattern_e100, re.MULTILINE) error_e300_regexp = re.compile(error_pattern_e300, re.MULTILINE) slave_started_regexp = re.compile(slave_started_pattern, re.MULTILINE) - with open(prt_file, "r", encoding="utf-8") as filehandle: + with open(self.prt_path, "r", encoding="utf-8") as filehandle: content = filehandle.read() for regexp in [error_e100_regexp, error_e300_regexp, slave_started_regexp]: @@ -604,3 +610,14 @@ def run(config: EclConfig, argv): except EclError as msg: print(msg, file=sys.stderr) sys.exit(-1) + + +def tail_textfile(file_path: Path, num_chars: int) -> str: + if not file_path.exists(): + return f"No output file {file_path}" + with open(file_path, encoding="utf-8") as file: + file.seek(0, 2) + file_end_position = file.tell() + seek_position = max(0, file_end_position - num_chars) + file.seek(seek_position) + return file.read()[-num_chars:] diff --git a/tests/unit_tests/resources/test_ecl_run_new_config.py b/tests/unit_tests/resources/test_ecl_run_new_config.py index b1e4222a676..59ff4ccaa51 100644 --- a/tests/unit_tests/resources/test_ecl_run_new_config.py +++ b/tests/unit_tests/resources/test_ecl_run_new_config.py @@ -525,6 +525,37 @@ def test_too_few_parsed_error_messages_gives_warning(): assert "Warning, mismatch between stated Error count" in str(exception_info.value) +@pytest.mark.usefixtures("use_tmpdir") +def test_tail_of_prt_file_is_included_when_error_count_inconsistency(): + prt_error = ( + "this_should_not_be_included " + + "\n" * 10000 + + """ + this_should_be_included + + @--MESSAGE AT TIME 0.0 DAYS ( 1-JAN-2000): + @ THIS IS JUST A MESSAGE, NOTHING ELSE""" + ) + eclend = """ + Error summary + Comments 0 + Warnings 0 + Problems 0 + Errors 1 + Bugs 0""" + + Path("ECLCASE.PRT").write_text(prt_error + "\n" + eclend, encoding="utf-8") + Path("ECLCASE.ECLEND").write_text(eclend, encoding="utf-8") + + Path("ECLCASE.DATA").write_text("", encoding="utf-8") + + run = ecl_run.EclRun("ECLCASE.DATA", "dummysimulatorobject") + with pytest.raises(ecl_run.EclError) as exception_info: + run.assertECLEND() + assert "this_should_be_included" in str(exception_info.value) + assert "this_should_not_be_included" not in str(exception_info.value) + + @pytest.mark.usefixtures("use_tmpdir") def test_correct_number_of_parsed_error_messages_gives_no_warning(): prt_error = """\