65 """So now we have a URL to a failing test.
66 We need to check that the test is failing for the correct reason - namely a reference file which needs updating
67 The information we need to collect is:
68 - the AMI tag of the failing tests
69 - the merge request number
70 - the location of the reference file
71 - the location of the copied file
72 - the name of the test
73 - the new version number
74 - the new version directory
76 page = requests.get(url)
81 test_match = re.search(
r'All (?P<ami_tag>\w+) athena steps completed successfully', text)
82 ami_tag = test_match.group(
'ami_tag')
if test_match
else None
87 match_attempt_2 = re.search(
r'AMIConfig (?P<ami_tag>\w+)', text)
89 ami_tag = match_attempt_2.group(
'ami_tag')
92 print(
'WARNING: Did not find an AMI tag in the test "{}". Ignoring.'.format(test_name))
95 mr_match = re.search(
r'ARDOC_TestLog_MR-(?P<mr_number>\d+)-(?P<date>\d{4}-\d{2}-\d{2}-\d{2}-\d{2})', url)
97 print(
'FATAL: Could not process the URL as expected. Aborting.')
101 mr_number = mr_match.group(
'mr_number')
102 date = mr_match.group(
'date')
103 human_readable_date =
':'.join(date.split(
'-')[0:3]) +
" at " +
':'.join(date.split(
'-')[3:])
105 if "Your change breaks the digest in test" in text
or 'ERROR Your change modifies the output in test' in text:
107 failing_tests[branch].append(
process_digest_change(text, ami_tag, mr_number, human_readable_date, test_name))
109 if (
'ERROR Your change affects standard outputs in test' in text
or
110 'ERROR Your change breaks the frozen tier0 policy in test' in text
or
111 'ERROR Your change breaks the frozen derivation policy in test' in text):
113 failing_tests[branch].append(
process_diffpool_change(text, ami_tag, mr_number, human_readable_date, test_name))
118 eos_path_root =
'/eos/atlas/atlascerngroupdisk/data-art/grid-input/WorkflowReferences/'
122 copied_file_match = re.search(
r'^ERROR Copied.*', text, flags=re.MULTILINE)
123 if not copied_file_match:
124 print(
"FATAL: Could not find matching copied file")
126 copied_file_path = copied_file_match.group().
split(
'to')[1].
strip().
strip(
"'").
strip(
"'")+
'/'
129 ref_file_match = re.search(
r'INFO Reading the reference file from location.*', text)
130 if not ref_file_match:
131 print(
"FATAL: Could not find matching reference file")
134 ref_file_path = ref_file_match.group().
split(
'location')[1].
strip()
135 existing_version_number= ref_file_path.split(
'/')[-2]
136 branch = ref_file_path.split(
'/')[-4]
137 new_version_number =
'v'+str(int(existing_version_number[1:])+1)
138 new_version_directory = eos_path_root+branch+
'/'+ami_tag+
'/'+new_version_number
139 old_version_directory = eos_path_root+branch+
'/'+ami_tag+
'/'+existing_version_number
142 copied_file_match = re.search(
r'^ERROR Copied.*', text, flags=re.MULTILINE)
143 if not copied_file_match:
144 print(
"FATAL: Could not find matching copied file")
148 ami_tag_check = ref_file_path.split(
'/')[-3].
strip()
149 if ami_tag_check!=ami_tag:
150 print(
'FATAL: Sanity check: "{}" from reference file path "{}" does not match ami tag "{}" extracted previously.'.format(ami_tag_check, ref_file_path, ami_tag))
154 test =
CITest(name=test_name, tag=ami_tag, mr=mr_number, date=human_readable_date, existing_ref = old_version_directory, existing_version = existing_version_number, new_version = new_version_number, new_version_directory = new_version_directory, copied_file_path = copied_file_path, diff=
None, type=
'DiffPool')
159 existing_version_number =
None
160 new_version_directory =
None
161 copied_file_path =
None
162 new_version_number=
None
165 ref_file_match = re.search(
166 r"differs from the reference (?:'|')([^'&]+?)(?:'|')",
169 if not ref_file_match:
170 print(
"FATAL: Could not find matching reference file")
172 ref_file_path = ref_file_match.group(1)
180 for line
in text.split(
'\n'):
181 if 'differs from the reference' in line:
189 diff_lines.append(html.unescape(line))
191 test =
CITest(name=test_name, tag=ami_tag, mr=mr_number, date=human_readable_date, existing_ref = ref_file_path, existing_version = existing_version_number, new_version = new_version_number, new_version_directory = new_version_directory, copied_file_path = copied_file_path, diff=diff_lines, type=
'Content' if 'content.ref' in ref_file_path
else 'Digest')
196 print(
'Updating reference files')
197 print(
'========================')
199 for branch, tests
in failing_tests.items():
201 print(
'Processing test: {} on branch {}'.format(test.name, branch))
202 if test.type ==
'DiffPool':
204 print(
' * This is a DiffPool test but uses a shared reference. No update needed.')
207 print(
' * This is a DiffPool test, and currently has version {} of {}. Will update References.py with new version.'.format(test.existing_version, test.tag))
209 print(
' -> The new version is: {}. Creating directory and copying files on EOS now.'.format(test.new_version))
215 commands = list(dict.fromkeys(commands))
218 if update_local_files:
221 print (
'Updating local References.py file with new version {} for tag {}'.format(test.new_version, test.tag))
223 with open(
'Tools/WorkflowTestRunner/python/References.py',
'r')
as f:
224 lines = f.readlines()
227 if test.existing_version
in line:
228 line = line.replace(test.existing_version, test.new_version)
231 print(
'** WARNING: For tag {} we were looking for existing version {}, but the line in the file is: {}'.format(test.tag, test.existing_version, line), end=
'')
232 print(
'** Are you sure your branch is up-to-date with main? We cannot update an older version of References.py!')
237 print(
'** WARNING - no matching line was found for the AMI tag {} in References.py. Are you sure your branch is up-to-date with main? We cannot update an older version of References.py!'.format(test.tag))
239 with open(
'Tools/WorkflowTestRunner/python/References.py',
'w')
as f:
241 elif test.type ==
'Digest' and update_local_files:
242 print(
' * This is a Digest test. Need to update reference file {}.'.format(test.existing_ref))
246 digest_old = [line
for line
in test.diff
if line.startswith(
'<')]
247 digest_new = [line
for line
in test.diff
if line.startswith(
'>')]
249 with open(
'Tools/PROCTools/data/'+test.existing_ref,
'r')
as f:
250 lines = f.readlines()
251 for current_line, line
in enumerate(lines):
252 split_curr_line = line.split()
253 if (split_curr_line[0] ==
'run'):
258 if (
not split_curr_line[0].isnumeric())
or (
not split_curr_line[1].isnumeric()):
259 print(
'FATAL: Found a line in current digest which does not start with run/event numbers: {}'.format(line))
262 split_old_diff_line = digest_old[diff_line].
split()
263 split_old_diff_line.pop(0)
264 split_new_diff_line = digest_new[diff_line].
split()
265 split_new_diff_line.pop(0)
268 if split_curr_line[0] == split_old_diff_line[0]
and split_curr_line[1] == split_old_diff_line[1]:
270 if split_curr_line!=split_old_diff_line:
271 print(
'FATAL: It seems like this line was already changed.')
272 print(
'Line we expected: {}'.format(test.old_diff_lines[diff_line]))
273 print(
'Line we got : {}'.format(line))
277 if split_curr_line[0] == split_new_diff_line[0]
and split_curr_line[1] == split_new_diff_line[1]:
279 data.append(
"".join([
"{:>12}".format(x)
for x
in split_new_diff_line])+
'\n')
280 if ((diff_line+1)<len(digest_old)):
287 print(
' -> Updating PROCTools digest file {}'.format(test.existing_ref))
288 with open(
'Tools/PROCTools/data/'+test.existing_ref,
'w')
as f:
290 elif test.type ==
'Content' and update_local_files:
291 print(
' * This is a Content test. Need to update reference file {}.'.format(test.existing_ref))
292 subprocess.run(f
'patch --quiet Tools/PROCTools/data/{test.existing_ref}',
293 input=
'\n'.join(test.diff)+
'\n',
294 text=
True, shell=
True, check=
True)
301 If called with actually_update=False, this function will return a list of commands which would have been executed.
306 if test.shared_ref
is True:
309 if test.new_version_directory
not in dirs_created:
310 commands.append(
"mkdir -p " + test.new_version_directory)
311 dirs_created.append(test.new_version_directory)
315 commands.append(
"cp " + test.copied_file_path +
"* "+ test.new_version_directory+
"/")
316 commands.append(
"cp -n " + test.existing_ref +
"/* "+ test.new_version_directory+
"/")
318 print(
' -> Copying files from {} to {}'.format(test.copied_file_path, test.new_version_directory))
320 for command
in commands:
322 subprocess.call( command, shell=
True)
323 except Exception
as e:
324 print(
'Command failed due to:', e)
325 print(
'Do you have EOS available on this machine?')
326 except Exception
as e:
327 print(
'FATAL: Unable to copy files due to:', e)
330 f = open(test.new_version_directory+
'/info.txt',
'w')
331 f.write(
'Merge URL: https://gitlab.cern.ch/atlas/athena/-/merge_requests/{}\n'.format(test.mr))
332 f.write(
'Date: {}\n'.format(test.date))
333 f.write(
'AMI: {}\n'.format(test.tag))
334 f.write(
'Test name: {}\n'.format(test.name))
335 f.write(
'Files copied from: {}\n'.format(test.copied_file_path))
411 print(
'Summary of tests which need work:')
413 if not failing_tests:
414 print(
" -> None found. Aborting.")
418 reference_folders = []
419 for branch,tests
in failing_tests.items():
420 print (
' * Branch: {}'.format(branch))
423 if test.type ==
'DiffPool':
424 if not test.new_version_directory:
425 print(
'FATAL: No path to "new version" for test {} of type DiffPool.'.format(test.name))
428 if os.path.exists(test.new_version_directory):
429 msg = f
'WARNING: The directory {test.new_version_directory} already exists. Are you sure you want to overwrite the existing references?'
430 if input(
"%s (y/N) " % msg).lower() !=
'y':
433 if (
not test.shared_ref
and test.existing_ref
not in reference_folders):
434 reference_folders.append(test.existing_ref)
435 elif check_for_duplicates
and not test.shared_ref:
436 print(
'FATAL: Found two tests which both change the same reference file: {}, which is not supported.'.format(test.existing_ref))
437 print(
'Consider running again in --test-run mode, to get a copy of the copy commands that could be run.')
438 print(
'The general advice is to take the largest file (since it will have the most events).')
441 return 'https://gitlab.cern.ch/atlas/athena/-/merge_requests/'+mr
__init__(self, name, tag, mr, date, existing_ref, existing_version, new_version, new_version_directory, copied_file_path, diff, type)