Skip to content

Commit dab7954

Browse files
committed
relink.py: Add --timing option.
1 parent 863bc4f commit dab7954

2 files changed

Lines changed: 108 additions & 6 deletions

File tree

relink.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import pwd
1010
import argparse
1111
import logging
12+
import time
1213

1314
DEFAULT_SOURCE_ROOT = "/glade/campaign/cesm/cesmdata/cseg/inputdata/"
1415
DEFAULT_TARGET_ROOT = (
@@ -185,27 +186,40 @@ def parse_arguments():
185186
action="store_true",
186187
help="Show what would be done without making any changes",
187188
)
189+
parser.add_argument(
190+
"--timing",
191+
action="store_true",
192+
help="Measure and display the execution time",
193+
)
188194

189195
return parser.parse_args()
190196

191-
192-
if __name__ == "__main__":
197+
def main():
193198

194199
args = parse_arguments()
195200

196201
# Configure logging based on verbosity flags
197202
if args.quiet:
198-
LOG_LEVEL = logging.WARNING
203+
log_level = logging.WARNING
199204
elif args.verbose:
200-
LOG_LEVEL = logging.DEBUG
205+
log_level = logging.DEBUG
201206
else:
202-
LOG_LEVEL = logging.INFO
207+
log_level = logging.INFO
203208

204-
logging.basicConfig(level=LOG_LEVEL, format="%(message)s", stream=sys.stdout)
209+
logging.basicConfig(level=log_level, format="%(message)s", stream=sys.stdout)
205210

206211
my_username = os.environ["USER"]
207212

213+
start_time = time.time()
214+
208215
# --- Execution ---
209216
find_and_replace_owned_files(
210217
args.source_root, args.target_root, my_username, dry_run=args.dry_run
211218
)
219+
220+
if args.timing:
221+
elapsed_time = time.time() - start_time
222+
logger.info("Execution time: %.2f seconds", elapsed_time)
223+
224+
if __name__ == "__main__":
225+
main()

tests/test_relink.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,94 @@ def test_dry_run_default(self, mock_default_dirs):
466466
args = relink.parse_arguments()
467467
assert args.dry_run is False
468468

469+
def test_timing_flag(self, mock_default_dirs):
470+
"""Test that --timing flag is parsed correctly."""
471+
with patch("sys.argv", ["relink.py", "--timing"]):
472+
args = relink.parse_arguments()
473+
assert args.timing is True
474+
475+
def test_timing_default(self, mock_default_dirs):
476+
"""Test that timing defaults to False."""
477+
with patch("sys.argv", ["relink.py"]):
478+
args = relink.parse_arguments()
479+
assert args.timing is False
480+
481+
482+
class TestTiming:
483+
"""Test suite for timing functionality."""
484+
485+
@pytest.fixture
486+
def temp_dirs(self):
487+
"""Create temporary source and target directories for testing."""
488+
source_dir = tempfile.mkdtemp(prefix="test_source_")
489+
target_dir = tempfile.mkdtemp(prefix="test_target_")
490+
491+
yield source_dir, target_dir
492+
493+
# Cleanup
494+
shutil.rmtree(source_dir, ignore_errors=True)
495+
shutil.rmtree(target_dir, ignore_errors=True)
496+
497+
def test_timing_message_logged(self, tmp_path, caplog):
498+
"""Test that timing message is logged when timing is enabled."""
499+
# Create real directories
500+
source_dir = tmp_path / "source"
501+
target_dir = tmp_path / "target"
502+
source_dir.mkdir()
503+
target_dir.mkdir()
504+
505+
# Create a file
506+
source_file = source_dir / "test_file.txt"
507+
target_file = target_dir / "test_file.txt"
508+
source_file.write_text("source")
509+
target_file.write_text("target")
510+
511+
# Mock sys.argv to simulate running with --timing
512+
test_argv = [
513+
"relink.py",
514+
"--source-root", str(source_dir),
515+
"--target-root", str(target_dir),
516+
"--timing"
517+
]
518+
519+
with patch("sys.argv", test_argv):
520+
with caplog.at_level(logging.INFO):
521+
# Call main() which includes the timing logic
522+
relink.main()
523+
524+
# Verify timing message was logged
525+
assert "Execution time:" in caplog.text
526+
assert "seconds" in caplog.text
527+
528+
def test_timing_not_logged_by_default(self, tmp_path, caplog):
529+
"""Test that timing message is not logged when timing is disabled."""
530+
# Create real directories
531+
source_dir = tmp_path / "source"
532+
target_dir = tmp_path / "target"
533+
source_dir.mkdir()
534+
target_dir.mkdir()
535+
536+
# Create a file
537+
source_file = source_dir / "test_file.txt"
538+
target_file = target_dir / "test_file.txt"
539+
source_file.write_text("source")
540+
target_file.write_text("target")
541+
542+
# Mock sys.argv WITHOUT --timing flag
543+
test_argv = [
544+
"relink.py",
545+
"--source-root", str(source_dir),
546+
"--target-root", str(target_dir)
547+
]
548+
549+
with patch("sys.argv", test_argv):
550+
with caplog.at_level(logging.INFO):
551+
# Call main() without timing flag
552+
relink.main()
553+
554+
# Verify timing message was NOT logged
555+
assert "Execution time:" not in caplog.text
556+
469557

470558
class TestDryRun:
471559
"""Test suite for dry-run functionality."""

0 commit comments

Comments
 (0)