Skip to content

Commit 9faa55a

Browse files
Merge pull request #1008 from linsword13/test-cov
Add tests to various utils
2 parents 62af13d + 043e9da commit 9faa55a

File tree

6 files changed

+169
-66
lines changed

6 files changed

+169
-66
lines changed

lib/ramble/ramble/cmd/debug.py

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,11 @@
77
# except according to those terms.
88

99

10-
import os
1110
import platform
12-
import re
13-
from datetime import datetime
1411

15-
from llnl.util.filesystem import working_dir
16-
17-
import ramble.config
18-
import ramble.paths
1912
import ramble.util.version
2013

2114
import spack.platforms
22-
from spack.util.executable import which
2315

2416
description = "debugging commands for troubleshooting Ramble"
2517
section = "developer"
@@ -31,31 +23,6 @@ def setup_parser(subparser):
3123
sp.add_parser("report", help="print information useful for bug reports")
3224

3325

34-
def _debug_tarball_suffix():
35-
now = datetime.now()
36-
suffix = now.strftime("%Y-%m-%d-%H%M%S")
37-
38-
git = which("git")
39-
if not git:
40-
return "nobranch-nogit-%s" % suffix
41-
42-
with working_dir(ramble.paths.prefix):
43-
if not os.path.isdir(".git"):
44-
return "nobranch.nogit.%s" % suffix
45-
46-
# Get symbolic branch name and strip any special chars (mainly '/')
47-
symbolic = git("rev-parse", "--abbrev-ref", "--short", "HEAD", output=str).strip()
48-
symbolic = re.sub(r"[^\w.-]", "-", symbolic)
49-
50-
# Get the commit hash too.
51-
commit = git("rev-parse", "--short", "HEAD", output=str).strip()
52-
53-
if symbolic == commit:
54-
return f"nobranch.{commit}.{suffix}"
55-
else:
56-
return f"{symbolic}.{commit}.{suffix}"
57-
58-
5926
def report(args):
6027
host_platform = spack.platforms.host()
6128
host_os = host_platform.operating_system("frontend")

lib/ramble/ramble/test/namespace_trie.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def test_add_single(trie):
2222
assert trie.is_prefix("foo")
2323
assert trie.has_value("foo")
2424
assert trie["foo"] == "bar"
25+
assert not trie.is_leaf("foo")
2526

2627

2728
def test_add_multiple(trie):
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Copyright 2022-2025 The Ramble Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
# option. This file may not be copied, modified, or distributed
7+
# except according to those terms.
8+
"""Perform tests of the util/naming functions"""
9+
10+
import pytest
11+
12+
from ramble.util import naming
13+
14+
15+
@pytest.mark.parametrize(
16+
"mod_name,expected_cls_name",
17+
[
18+
("test_mod_1", "TestMod1"),
19+
("2_test_mod", "_2TestMod"),
20+
],
21+
)
22+
def test_mod_to_class(mod_name, expected_cls_name):
23+
assert naming.mod_to_class(mod_name) == expected_cls_name
24+
25+
26+
@pytest.mark.parametrize(
27+
"mod_name,expected_py_mod_name",
28+
[
29+
("app", "app"),
30+
("intel-mlc", "intel_mlc"),
31+
("1-app", "num1_app"),
32+
],
33+
)
34+
def test_ramble_module_to_python_module(mod_name, expected_py_mod_name):
35+
assert naming.ramble_module_to_python_module(mod_name) == expected_py_mod_name
36+
37+
38+
@pytest.mark.parametrize(
39+
"py_mod_name,expected_names",
40+
[
41+
("app", ["app"]),
42+
("py_mod", ["py_mod", "py-mod"]),
43+
("num1_app", ["1_app", "1-app"]),
44+
],
45+
)
46+
def test_possible_ramble_module_names(py_mod_name, expected_names):
47+
assert naming.possible_ramble_module_names(py_mod_name) == expected_names
48+
49+
50+
@pytest.mark.parametrize(
51+
"in_name,expected_out_name",
52+
[
53+
("ImageMagick", "imagemagick"),
54+
("l_mkl", "mkl"),
55+
("ALLCAPS", "allcaps"),
56+
("a_b.c++", "a-b-cpp"),
57+
],
58+
)
59+
def test_simplify_name(in_name, expected_out_name):
60+
assert naming.simplify_name(in_name) == expected_out_name
61+
62+
63+
@pytest.mark.parametrize(
64+
"mod_name,expect_error",
65+
[
66+
("valid-mod", False),
67+
("a.b", True),
68+
("-ab", True),
69+
],
70+
)
71+
def test_validate_module_name(mod_name, expect_error):
72+
if expect_error:
73+
with pytest.raises(naming.InvalidModuleNameError):
74+
naming.validate_module_name(mod_name)
75+
else:
76+
naming.validate_module_name(mod_name)
77+
78+
79+
@pytest.mark.parametrize(
80+
"mod_name,expect_error",
81+
[
82+
("valid-mod", False),
83+
("a.b", False),
84+
("-ab", True),
85+
("valid-mod.a.b-c", False),
86+
],
87+
)
88+
def test_validate_fully_qualified_module_name(mod_name, expect_error):
89+
if expect_error:
90+
with pytest.raises(naming.InvalidFullyQualifiedModuleNameError):
91+
naming.validate_fully_qualified_module_name(mod_name)
92+
else:
93+
naming.validate_fully_qualified_module_name(mod_name)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright 2022-2025 The Ramble Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
# option. This file may not be copied, modified, or distributed
7+
# except according to those terms.
8+
"""Perform tests of the util/output_capture functions"""
9+
10+
from ramble.util import output_capture
11+
12+
13+
def test_output_capture():
14+
mapper = output_capture.output_mapper()
15+
assert (
16+
mapper.generate_out_string("log.out", output_capture.OUTPUT_CAPTURE.STDOUT)
17+
== ' >> "log.out"'
18+
)
19+
assert (
20+
mapper.generate_out_string("log.out", output_capture.OUTPUT_CAPTURE.STDERR)
21+
== ' 2>> "log.out"'
22+
)
23+
assert (
24+
mapper.generate_out_string("log.out", output_capture.OUTPUT_CAPTURE.ALL)
25+
== ' >> "log.out" 2>&1'
26+
)

lib/ramble/ramble/test/util/web.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright 2022-2025 The Ramble Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
# option. This file may not be copied, modified, or distributed
7+
# except according to those terms.
8+
"""Perform tests of the util/web functions"""
9+
10+
import pytest
11+
12+
from ramble.util import web
13+
14+
15+
def test_get_header():
16+
headers = {"Content-type": "text/plain"}
17+
18+
assert web.get_header(headers, "Content-type") == "text/plain"
19+
20+
# test fuzzy lookup
21+
assert web.get_header(headers, "contentType") == "text/plain"
22+
headers["contentType"] = "text/html"
23+
assert web.get_header(headers, "contentType") == "text/html"
24+
25+
# test no match
26+
with pytest.raises(KeyError):
27+
web.get_header(headers, "ContentLength")
28+
29+
30+
def test_gcs_url_exists(monkeypatch):
31+
32+
def _get_client():
33+
return MockGcsClient()
34+
35+
import spack.util.gcs
36+
37+
monkeypatch.setattr(spack.util.gcs, "gcs_client", _get_client)
38+
test_url = "gs://abc/xyz.txt"
39+
with pytest.raises(MockGcsClientError, match="Mock error for bucket abc"):
40+
web.url_exists(test_url)
41+
42+
43+
class MockGcsClient:
44+
def bucket(self, name):
45+
raise MockGcsClientError(f"Mock error for bucket {name}")
46+
47+
48+
class MockGcsClientError(Exception):
49+
pass

lib/ramble/ramble/util/path.py

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,10 @@
1313
import getpass
1414
import os
1515
import re
16-
import subprocess
1716
import tempfile
1817
import urllib.parse
1918

20-
from llnl.util.lang import memoized
21-
2219
import ramble.paths
23-
from ramble.util.logger import logger
2420

2521
__all__ = ["substitute_config_variables", "substitute_path_variables", "canonicalize_path"]
2622

@@ -31,35 +27,6 @@
3127
"tempdir": tempfile.gettempdir(),
3228
}
3329

34-
# This is intended to be longer than the part of the install path
35-
# ramble generates from the root path we give it. Included in the
36-
# estimate:
37-
#
38-
# os-arch -> 30
39-
# compiler -> 30
40-
# package name -> 50 (longest is currently 47 characters)
41-
# version -> 20
42-
# hash -> 32
43-
# buffer -> 138
44-
# ---------------------
45-
# total -> 300
46-
47-
48-
@memoized
49-
def get_system_path_max():
50-
# Choose a conservative default
51-
sys_max_path_length = 256
52-
try:
53-
path_max_proc = subprocess.Popen(
54-
["getconf", "PATH_MAX", "/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT
55-
)
56-
proc_output = str(path_max_proc.communicate()[0].decode())
57-
sys_max_path_length = int(proc_output)
58-
except (ValueError, subprocess.CalledProcessError, OSError):
59-
logger.msg(f"Unable to find system max path length, using: {sys_max_path_length}")
60-
61-
return sys_max_path_length
62-
6330

6431
def substitute_config_variables(path, local_replacements):
6532
"""Substitute placeholders into paths.

0 commit comments

Comments
 (0)