|
| 1 | +#!/usr/bin/env python3 |
| 2 | +############################################################### |
| 3 | +# Copyright 2025 Lawrence Livermore National Security, LLC |
| 4 | +# (c.f. AUTHORS, NOTICE.LLNS, COPYING) |
| 5 | +# |
| 6 | +# This file is part of the Flux resource manager framework. |
| 7 | +# For details, see https://github.com/flux-framework. |
| 8 | +# |
| 9 | +# SPDX-License-Identifier: LGPL-3.0 |
| 10 | +############################################################### |
| 11 | + |
| 12 | +import json |
| 13 | +import os |
| 14 | +import time |
| 15 | +import unittest |
| 16 | + |
| 17 | +import subflux # noqa: F401 |
| 18 | +from flux.eventlog import EventLogFormatter |
| 19 | +from pycotap import TAPTestRunner |
| 20 | + |
| 21 | +TEST_EVENTLOG = """\ |
| 22 | +{"timestamp":1738774194.078433,"name":"submit","context":{"userid":1001,"urgency":16,"flags":0,"version":1}} |
| 23 | +{"timestamp":1738774194.0947378,"name":"validate"} |
| 24 | +{"timestamp":1738774194.1073177,"name":"depend"} |
| 25 | +{"timestamp":1738774194.107436,"name":"priority","context":{"priority":16}} |
| 26 | +{"timestamp":1738774194.110116,"name":"alloc","context":{"annotations":{"sched":{"resource_summary":"rank[0-3]/core[0-7]"}}}} |
| 27 | +{"timestamp":1738774194.1177957,"name":"start"} |
| 28 | +{"timestamp":1738774194.1820674,"name":"finish","context":{"status":0}} |
| 29 | +{"timestamp":1738774194.1853716,"name":"release","context":{"ranks":"all","final":true}} |
| 30 | +{"timestamp":1738774194.1854134,"name":"free"} |
| 31 | +{"timestamp":1738774194.1854289,"name":"clean"} |
| 32 | +""" |
| 33 | + |
| 34 | +TEST_EVENTLOG_OUTPUT = """\ |
| 35 | +1738774194.078433 submit userid=1001 urgency=16 flags=0 version=1 |
| 36 | +1738774194.094738 validate |
| 37 | +1738774194.107318 depend |
| 38 | +1738774194.107436 priority priority=16 |
| 39 | +1738774194.110116 alloc annotations={"sched":{"resource_summary":"rank[0-3]/core[0-7]"}} |
| 40 | +1738774194.117796 start |
| 41 | +1738774194.182067 finish status=0 |
| 42 | +1738774194.185372 release ranks="all" final=true |
| 43 | +1738774194.185413 free |
| 44 | +1738774194.185429 clean |
| 45 | +""" |
| 46 | + |
| 47 | +TEST_EVENTLOG_OUTPUT_HUMAN_UTC = """\ |
| 48 | +[Feb05 16:49] submit userid=1001 urgency=16 flags=0 version=1 |
| 49 | +[ +0.016305] validate |
| 50 | +[ +0.028885] depend |
| 51 | +[ +0.029003] priority priority=16 |
| 52 | +[ +0.031683] alloc annotations={"sched":{"resource_summary":"rank[0-3]/core[0-7]"}} |
| 53 | +[ +0.039363] start |
| 54 | +[ +0.103634] finish status=0 |
| 55 | +[ +0.106939] release ranks="all" final=true |
| 56 | +[ +0.106980] free |
| 57 | +[ +0.106996] clean |
| 58 | +""" |
| 59 | +TEST_EVENTLOG_OUTPUT_HUMAN_COLOR = """\ |
| 60 | +[1m[32m[Feb05 16:49][0m [33msubmit[0m [34muserid[0m=[37m1001[0m [34murgency[0m=[37m16[0m [34mflags[0m=[37m0[0m [34mversion[0m=[37m1[0m |
| 61 | +[32m[ +0.016305][0m [33mvalidate[0m |
| 62 | +[32m[ +0.028885][0m [33mdepend[0m |
| 63 | +[32m[ +0.029003][0m [33mpriority[0m [34mpriority[0m=[37m16[0m |
| 64 | +[32m[ +0.031683][0m [33malloc[0m [34mannotations[0m=[35m{"sched":{"resource_summary":"rank[0-3]/core[0-7]"}}[0m |
| 65 | +[32m[ +0.039363][0m [33mstart[0m |
| 66 | +[32m[ +0.103634][0m [33mfinish[0m [34mstatus[0m=[37m0[0m |
| 67 | +[32m[ +0.106939][0m [33mrelease[0m [34mranks[0m=[35m"all"[0m [34mfinal[0m=[35mtrue[0m |
| 68 | +[32m[ +0.106980][0m [33mfree[0m |
| 69 | +[32m[ +0.106996][0m [33mclean[0m |
| 70 | +""" |
| 71 | + |
| 72 | +TEST_EVENTLOG_OUTPUT_OFFSET = """\ |
| 73 | +0.000000 submit userid=1001 urgency=16 flags=0 version=1 |
| 74 | +0.016305 validate |
| 75 | +0.028885 depend |
| 76 | +0.029003 priority priority=16 |
| 77 | +0.031683 alloc annotations={"sched":{"resource_summary":"rank[0-3]/core[0-7]"}} |
| 78 | +0.039363 start |
| 79 | +0.103634 finish status=0 |
| 80 | +0.106939 release ranks="all" final=true |
| 81 | +0.106980 free |
| 82 | +0.106996 clean |
| 83 | +""" |
| 84 | + |
| 85 | +TEST_EVENTLOG_OUTPUT_ISO_ZULU = """\ |
| 86 | +2025-02-05T16:49:54.078433Z submit userid=1001 urgency=16 flags=0 version=1 |
| 87 | +2025-02-05T16:49:54.094737Z validate |
| 88 | +2025-02-05T16:49:54.107317Z depend |
| 89 | +2025-02-05T16:49:54.107435Z priority priority=16 |
| 90 | +2025-02-05T16:49:54.110116Z alloc annotations={"sched":{"resource_summary":"rank[0-3]/core[0-7]"}} |
| 91 | +2025-02-05T16:49:54.117795Z start |
| 92 | +2025-02-05T16:49:54.182067Z finish status=0 |
| 93 | +2025-02-05T16:49:54.185371Z release ranks="all" final=true |
| 94 | +2025-02-05T16:49:54.185413Z free |
| 95 | +2025-02-05T16:49:54.185428Z clean |
| 96 | +""" |
| 97 | + |
| 98 | +test_eventlog_json = [x for x in TEST_EVENTLOG.splitlines()] |
| 99 | +test_eventlog = [json.loads(x) for x in TEST_EVENTLOG.splitlines()] |
| 100 | +test_eventlog_raw = [x for x in TEST_EVENTLOG_OUTPUT.splitlines()] |
| 101 | +test_eventlog_human = [x for x in TEST_EVENTLOG_OUTPUT_HUMAN_UTC.splitlines()] |
| 102 | +test_eventlog_human_color = [x for x in TEST_EVENTLOG_OUTPUT_HUMAN_COLOR.splitlines()] |
| 103 | +test_eventlog_offset = [x for x in TEST_EVENTLOG_OUTPUT_OFFSET.splitlines()] |
| 104 | +test_eventlog_iso_zulu = [x for x in TEST_EVENTLOG_OUTPUT_ISO_ZULU.splitlines()] |
| 105 | + |
| 106 | + |
| 107 | +class TestEventLogFormatter(unittest.TestCase): |
| 108 | + |
| 109 | + def test_invalid_args(self): |
| 110 | + with self.assertRaises(ValueError): |
| 111 | + EventLogFormatter(format="foo") |
| 112 | + with self.assertRaises(ValueError): |
| 113 | + EventLogFormatter(timestamp_format="foo") |
| 114 | + with self.assertRaises(ValueError): |
| 115 | + EventLogFormatter(color="foo") |
| 116 | + |
| 117 | + def test_raw(self): |
| 118 | + evf = EventLogFormatter() |
| 119 | + for entry, expected in zip(test_eventlog, test_eventlog_raw): |
| 120 | + self.assertEqual(evf.format(entry).strip(), expected) |
| 121 | + |
| 122 | + def test_human(self): |
| 123 | + evf = EventLogFormatter(timestamp_format="human") |
| 124 | + for entry, expected in zip(test_eventlog, test_eventlog_human): |
| 125 | + self.assertEqual(evf.format(entry).strip(), expected) |
| 126 | + |
| 127 | + def test_offset(self): |
| 128 | + evf = EventLogFormatter(timestamp_format="offset") |
| 129 | + for entry, expected in zip(test_eventlog, test_eventlog_offset): |
| 130 | + self.assertEqual(evf.format(entry).strip(), expected) |
| 131 | + |
| 132 | + def test_iso(self): |
| 133 | + evf = EventLogFormatter(timestamp_format="iso") |
| 134 | + for entry, expected in zip(test_eventlog, test_eventlog_iso_zulu): |
| 135 | + self.assertEqual(evf.format(entry).strip(), expected) |
| 136 | + |
| 137 | + def test_json(self): |
| 138 | + evf = EventLogFormatter(format="json") |
| 139 | + for entry, expected in zip(test_eventlog, test_eventlog_json): |
| 140 | + self.assertEqual(evf.format(entry).strip(), expected) |
| 141 | + |
| 142 | + def test_color(self): |
| 143 | + evf = EventLogFormatter(timestamp_format="human", color="always") |
| 144 | + for entry, expected in zip(test_eventlog, test_eventlog_human_color): |
| 145 | + self.assertEqual(evf.format(entry).strip(), expected) |
| 146 | + |
| 147 | + |
| 148 | +if __name__ == "__main__": |
| 149 | + os.environ["TZ"] = "UTC" |
| 150 | + time.tzset() |
| 151 | + unittest.main(testRunner=TAPTestRunner(), buffer=False) |
0 commit comments