Skip to content

Commit 2a12683

Browse files
committed
Test environment variable expansion
`Config.launch` should now expand env vars in the same way as the shell based hab cli methods.
1 parent 4e3ab73 commit 2a12683

14 files changed

+356
-0
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "var-expand-a",
3+
"environment": {
4+
"os_specific": true,
5+
"*": {
6+
"set": {
7+
"OS_AGNOSTIC": "agnostic_value",
8+
"FROM_VAR_EXPAND_B": "--{VAR_EXPAND_B!e}--"
9+
}
10+
}
11+
}
12+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"name": "var-expand-b",
3+
"variables": {
4+
"alias_specific_linux": "Linux{;} /{OS_AGNOSTIC!e}/test to {OS_SPECIFIC!e}",
5+
"alias_specific_windows": "Windows{;} c:/{OS_AGNOSTIC!e}/test to {OS_SPECIFIC!e}"
6+
},
7+
"aliases": {
8+
"linux": [
9+
["list_vars", ["python", "{relative_root}/list_vars.py"]],
10+
[
11+
"list_vars_env", {
12+
"cmd": ["python", "{relative_root}/list_vars.py"],
13+
"environment": {
14+
"set": {
15+
"ALIAS_SPECIFIC": "{alias_specific_linux}"
16+
}
17+
}
18+
}
19+
]
20+
],
21+
"windows": [
22+
["list_vars", ["python", "{relative_root}/list_vars.py"]],
23+
[
24+
"list_vars_env", {
25+
"cmd": ["python", "{relative_root}/list_vars.py"],
26+
"environment": {
27+
"set": {
28+
"ALIAS_SPECIFIC": "{alias_specific_windows}"
29+
}
30+
}
31+
}
32+
]
33+
]
34+
},
35+
"environment": {
36+
"os_specific": true,
37+
"*": {
38+
"VAR_EXPAND_B": "var-expand-b-wild"
39+
},
40+
"linux": {
41+
"set": {
42+
"OS_SPECIFIC": "/{OS_AGNOSTIC!e}",
43+
"VAR_EXPAND_B": "var-expand-b-linux"
44+
}
45+
},
46+
"windows": {
47+
"set": {
48+
"OS_SPECIFIC": "c:/{OS_AGNOSTIC!e}",
49+
"VAR_EXPAND_B": "var-expand-b-windows"
50+
}
51+
}
52+
}
53+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import json
2+
import os
3+
4+
var_names = [
5+
"OS_AGNOSTIC",
6+
"OS_SPECIFIC",
7+
"ALIAS_SPECIFIC",
8+
"VAR_EXPAND_B",
9+
"FROM_VAR_EXPAND_B",
10+
]
11+
12+
result = {}
13+
for var_name in var_names:
14+
result[var_name] = os.getenv(var_name, "<UNSET>")
15+
16+
print(json.dumps(result, indent=4))

tests/site_main_check.habcache

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,6 +1794,93 @@
17941794
},
17951795
"name": "the_dcc_plugin_e",
17961796
"version": "1.1"
1797+
},
1798+
"{config-root}/distros/var-expand-a/1.0/.hab.json": {
1799+
"environment": {
1800+
"*": {
1801+
"set": {
1802+
"FROM_VAR_EXPAND_B": "--{VAR_EXPAND_B!e}--",
1803+
"OS_AGNOSTIC": "agnostic_value"
1804+
}
1805+
},
1806+
"os_specific": true
1807+
},
1808+
"name": "var-expand-a",
1809+
"version": "1.0"
1810+
},
1811+
"{config-root}/distros/var-expand-b/1.0/.hab.json": {
1812+
"aliases": {
1813+
"linux": [
1814+
[
1815+
"list_vars",
1816+
[
1817+
"python",
1818+
"{relative_root}/list_vars.py"
1819+
]
1820+
],
1821+
[
1822+
"list_vars_env",
1823+
{
1824+
"cmd": [
1825+
"python",
1826+
"{relative_root}/list_vars.py"
1827+
],
1828+
"environment": {
1829+
"set": {
1830+
"ALIAS_SPECIFIC": "{alias_specific_linux}"
1831+
}
1832+
}
1833+
}
1834+
]
1835+
],
1836+
"windows": [
1837+
[
1838+
"list_vars",
1839+
[
1840+
"python",
1841+
"{relative_root}/list_vars.py"
1842+
]
1843+
],
1844+
[
1845+
"list_vars_env",
1846+
{
1847+
"cmd": [
1848+
"python",
1849+
"{relative_root}/list_vars.py"
1850+
],
1851+
"environment": {
1852+
"set": {
1853+
"ALIAS_SPECIFIC": "{alias_specific_windows}"
1854+
}
1855+
}
1856+
}
1857+
]
1858+
]
1859+
},
1860+
"environment": {
1861+
"*": {
1862+
"VAR_EXPAND_B": "var-expand-b-wild"
1863+
},
1864+
"linux": {
1865+
"set": {
1866+
"OS_SPECIFIC": "/{OS_AGNOSTIC!e}",
1867+
"VAR_EXPAND_B": "var-expand-b-linux"
1868+
}
1869+
},
1870+
"os_specific": true,
1871+
"windows": {
1872+
"set": {
1873+
"OS_SPECIFIC": "c:/{OS_AGNOSTIC!e}",
1874+
"VAR_EXPAND_B": "var-expand-b-windows"
1875+
}
1876+
}
1877+
},
1878+
"name": "var-expand-b",
1879+
"variables": {
1880+
"alias_specific_linux": "Linux{;} /{OS_AGNOSTIC!e}/test to {OS_SPECIFIC!e}",
1881+
"alias_specific_windows": "Windows{;} c:/{OS_AGNOSTIC!e}/test to {OS_SPECIFIC!e}"
1882+
},
1883+
"version": "1.0"
17971884
}
17981885
}
17991886
},

tests/test_env_var_expansion.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
from __future__ import annotations
2+
3+
import copy
4+
import re
5+
import subprocess
6+
import sys
7+
from dataclasses import dataclass, field
8+
from pathlib import Path
9+
10+
import pytest
11+
12+
from hab.formatter import Formatter
13+
14+
15+
@dataclass
16+
class FileRef:
17+
path: Path
18+
name: str = field(init=False)
19+
shell: str | None = field(default=None)
20+
platform: str = field(init=False)
21+
distros: list = field(init=False)
22+
alias: str = field(init=False)
23+
_parser = re.compile(
24+
r"(?P<platform>[^-]+)-(?P<distros>[^-]+)-(?P<alias>[^.]+).json"
25+
)
26+
27+
def __post_init__(self) -> None:
28+
if not hasattr(self, "name"):
29+
self.name = self.path.stem
30+
match = self._parser.match(self.path.name)
31+
if not match:
32+
raise ValueError(f"Invalid filename: {self.path}")
33+
kwargs = match.groupdict()
34+
self.platform = kwargs["platform"]
35+
self.distros = kwargs["distros"].split(",")
36+
self.alias = kwargs["alias"]
37+
38+
@classmethod
39+
def from_glob(cls, path, glob_str="*.json"):
40+
ret = []
41+
for filename in path.glob(glob_str):
42+
ret.append(cls(filename))
43+
return ret
44+
45+
@classmethod
46+
def shell_matrix(cls, file_refs, shells: dict[str, list]) -> list:
47+
ret = []
48+
for file_ref in file_refs:
49+
plat_shells = shells.get(file_ref.platform, [])
50+
for shell in plat_shells:
51+
ref = copy.copy(file_ref)
52+
ref.shell = shell
53+
ret.append(ref)
54+
ret.sort(key=lambda i: repr(i))
55+
return ret
56+
57+
def __repr__(self) -> str:
58+
if self.shell:
59+
return f"{self.shell},{self.name}"
60+
return self.name
61+
62+
63+
references = FileRef.from_glob(Path(__file__).parent / "var_expanding")
64+
shell_references = FileRef.shell_matrix(
65+
references, {"windows": ["bash_win", "bat", "ps1"], "linux": ["bash_linux"]}
66+
)
67+
68+
69+
@pytest.mark.parametrize("reference", shell_references, ids=lambda f: repr(f))
70+
def test_expanding(reference, config_root, tmp_path, run_hab):
71+
# Skip tests that will not run on the current platform
72+
run_hab.skip_wrong_platform(reference.shell)
73+
74+
runner = run_hab(config_root, tmp_path, stderr=subprocess.PIPE)
75+
sub_cmd = []
76+
for d in reference.distros:
77+
sub_cmd.extend(["-r", f"var-expand-{d}"])
78+
sub_cmd += ["launch", ",", reference.alias]
79+
proc = runner.run_in_shell(reference.shell, sub_cmd)
80+
81+
with runner.std_on_failure(proc):
82+
# Check that the env vars were set as expected
83+
assert proc.returncode == 0
84+
85+
# Replace `{;;}` with the correct pathsep for the test. This is required because
86+
# bash on windows uses the linux pathsep
87+
languages = {
88+
"bat": "batch",
89+
"ps1": "ps",
90+
"bash_win": "shwin",
91+
"bash_linux": "sh",
92+
}
93+
pathsep = Formatter.shell_formats[languages[reference.shell]][";"]
94+
check = reference.path.open().read()
95+
check = check.replace("{;;}", pathsep)
96+
97+
assert proc.stdout == check
98+
99+
100+
@pytest.mark.parametrize("reference", references, ids=lambda f: repr(f))
101+
def test_launch(habcached_resolver, reference):
102+
pathsep = ":"
103+
if sys.platform.startswith("linux"):
104+
if reference.platform != "linux":
105+
raise pytest.skip("test doesn't apply on linux")
106+
elif sys.platform == "win32":
107+
pathsep = ";"
108+
if reference.platform != "windows":
109+
raise pytest.skip("test doesn't apply on windows")
110+
111+
forced_requirements = []
112+
for d in reference.distros:
113+
forced_requirements.extend([f"var-expand-{d}"])
114+
cfg = habcached_resolver.resolve(",", forced_requirements=forced_requirements)
115+
116+
proc = cfg.launch(reference.alias, args=None, blocking=True, stderr=subprocess.PIPE)
117+
assert proc.returncode == 0
118+
119+
# Replace `{;;}` with the correct pathsep for the test. This is required because
120+
# bash on windows uses the linux pathsep
121+
check = reference.path.open().read()
122+
check = check.replace("{;;}", pathsep)
123+
124+
assert check == proc.output_stdout

tests/test_resolver.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,10 @@ def test_distros(self, resolver):
368368
" the_dcc_plugin_e==0.9",
369369
" the_dcc_plugin_e==1.0",
370370
" the_dcc_plugin_e==1.1",
371+
"var-expand-a",
372+
" var-expand-a==1.0",
373+
"var-expand-b",
374+
" var-expand-b==1.0",
371375
]
372376
assert result == check
373377

@@ -423,6 +427,10 @@ def test_distros_truncate(self, resolver):
423427
" the_dcc_plugin_e==0.9",
424428
" ...",
425429
" the_dcc_plugin_e==1.1",
430+
"var-expand-a",
431+
" var-expand-a==1.0",
432+
"var-expand-b",
433+
" var-expand-b==1.0",
426434
]
427435
assert result == check
428436

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"OS_AGNOSTIC": "agnostic_value",
3+
"OS_SPECIFIC": "/agnostic_value",
4+
"ALIAS_SPECIFIC": "<UNSET>",
5+
"VAR_EXPAND_B": "var-expand-b-linux",
6+
"FROM_VAR_EXPAND_B": "----"
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"OS_AGNOSTIC": "agnostic_value",
3+
"OS_SPECIFIC": "/agnostic_value",
4+
"ALIAS_SPECIFIC": "Linux{;;} /agnostic_value/test to /agnostic_value",
5+
"VAR_EXPAND_B": "var-expand-b-linux",
6+
"FROM_VAR_EXPAND_B": "----"
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"OS_AGNOSTIC": "agnostic_value",
3+
"OS_SPECIFIC": "/",
4+
"ALIAS_SPECIFIC": "<UNSET>",
5+
"VAR_EXPAND_B": "var-expand-b-linux",
6+
"FROM_VAR_EXPAND_B": "--var-expand-b-linux--"
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"OS_AGNOSTIC": "agnostic_value",
3+
"OS_SPECIFIC": "/",
4+
"ALIAS_SPECIFIC": "Linux{;;} /agnostic_value/test to /",
5+
"VAR_EXPAND_B": "var-expand-b-linux",
6+
"FROM_VAR_EXPAND_B": "--var-expand-b-linux--"
7+
}

0 commit comments

Comments
 (0)