Skip to content

Commit e63a4e7

Browse files
Fix more tests for graalvm (#484)
- Enable most missing tests for graalvm. - Fix golden file containing exceptions for consistency (some had the full relative path to jsonnet, some did not) - Add code handle OutOfMemory in the Materializer. The GraalVM binary will basically run much longer before throwing a StackOverflow and instead hits limits with heap allocations during Materialization
1 parent 63808c8 commit e63a4e7

121 files changed

Lines changed: 212 additions & 219 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

sjsonnet/src/sjsonnet/Materializer.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ abstract class Materializer {
7070
} catch {
7171
case _: StackOverflowError =>
7272
Error.fail("Stackoverflow while materializing, possibly due to recursive value", v.pos)
73+
case _: OutOfMemoryError =>
74+
Error.fail("Stackoverflow while materializing, possibly due to recursive value", v.pos)
7375
}
7476

7577
def reverse(pos: Position, v: ujson.Value): Val = v match {

sjsonnet/test/graalvm/run_test_suites.py

Lines changed: 53 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,25 @@ def strip_trailing_empty_lines(text: str) -> str:
1515
lines.pop()
1616
return '\n'.join(lines)
1717

18+
root_dir = os.getcwd()
1819

19-
def run_binary(binary_path: str, test_dir: str, jsonnet_file: str) -> Tuple[str, int]:
20+
def run_binary(binary_path: str, jsonnet_file: str) -> Tuple[str, int]:
2021
"""Run the binary on a jsonnet file and return output and exit code."""
21-
cmd = [binary_path, '-Xss100m', '-J', test_dir, jsonnet_file]
22+
cmd = [
23+
binary_path,
24+
'--ext-str', 'var1=test',
25+
'--ext-code', 'var2=local f(a, b) = {[a]: b, \"y\": 2}; f(\"x\", 1)',
26+
'--ext-str', 'stringVar=2 + 2',
27+
'--ext-code', 'codeVar=3 + 3',
28+
'--ext-code', 'errorVar=error \'xxx\'',
29+
'--ext-code', 'staticErrorVar=)',
30+
'--ext-code', 'UndeclaredX=x',
31+
'--ext-code', 'selfRecursiveVar=[42, std.extVar(\"selfRecursiveVar\")[0] + 1]',
32+
'--ext-code', 'mutuallyRecursiveVar1=[42, std.extVar(\"mutuallyRecursiveVar2\")[0] + 1]',
33+
'--ext-code', 'mutuallyRecursiveVar2=[42, std.extVar(\"mutuallyRecursiveVar1\")[0] + 1]',
34+
'--tla-str', 'var1=test',
35+
'--tla-code', 'var2={\"x\": 1, \"y\": 2}',
36+
jsonnet_file]
2237
try:
2338
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
2439
return result.stdout + result.stderr, result.returncode
@@ -35,26 +50,31 @@ def setUpClass(cls):
3550
"""Set up the test class by building the GraalVM native binary."""
3651
if not hasattr(cls, '_binary_built'):
3752
subprocess.run(["./mill", "sjsonnet.graal.nativeImage"], check=True, cwd=".")
38-
BaseGraalVMTestSuite._binary_built = True
39-
cls.binary_path = "out/sjsonnet/graal/nativeImage.dest/native-executable"
53+
BaseGraalVMTestSuite._binary_built = True
54+
cls.binary_path = os.path.join(root_dir, "out/sjsonnet/graal/nativeImage.dest/native-executable")
4055

41-
def run_individual_test(self, test_dir: str, suite_name: str, jsonnet_file: str, base_name: str):
56+
@classmethod
57+
def tearDownClass(cls):
58+
"""Clean up the test class by removing the GraalVM native binary."""
59+
os.chdir(root_dir)
60+
61+
def run_individual_test(self, jsonnet_file: str, base_name: str):
4262
"""Run a single jsonnet test and assert it passes."""
4363
# Run the binary on the jsonnet file and capture output
44-
output, exit_code = run_binary(self.binary_path, test_dir, jsonnet_file)
45-
with open(os.path.join(test_dir, f"{base_name}.jsonnet.golden"), 'r', encoding='utf-8') as f:
64+
output, exit_code = run_binary(self.binary_path, jsonnet_file)
65+
with open(f"{base_name}.jsonnet.golden", 'r', encoding='utf-8') as f:
4666
golden_content = f.read()
4767

48-
# Strip test directory path from output only for go_test_suite
49-
if suite_name == "go_test_suite":
50-
normalized_output = strip_trailing_empty_lines(output.replace(f"{test_dir}/", ""))
51-
normalized_golden_content = strip_trailing_empty_lines(golden_content.replace(f"{test_dir}/", ""))
52-
else:
53-
normalized_output = strip_trailing_empty_lines(output)
54-
normalized_golden_content = strip_trailing_empty_lines(golden_content)
68+
normalized_output = strip_trailing_empty_lines(output.replace('Exception in thread "main" ', ''))
69+
normalized_golden_content = strip_trailing_empty_lines(golden_content.replace('Exception in thread "main" ', ''))
70+
if jsonnet_file.endswith("trace.jsonnet"):
71+
normalized_output = normalized_output.replace("true", "").strip()
72+
normalized_golden_content = normalized_golden_content.replace("true", "").strip()
5573

5674
# Compare with golden file, ignoring trailing empty lines
57-
if len(normalized_golden_content) > 10000 and normalized_golden_content != normalized_output:
75+
if normalized_golden_content.startswith("java.lang.StackOverflowError") and normalized_output.startswith("java.lang.StackOverflowError"):
76+
return
77+
elif len(normalized_golden_content) > 10000 and normalized_golden_content != normalized_output:
5878
print(f"normalized_golden_content: {normalized_golden_content[:100]}")
5979
print(f"normalized_output: {normalized_output[:100]}")
6080
self.fail("Mismatch - but content very very large")
@@ -63,43 +83,25 @@ def run_individual_test(self, test_dir: str, suite_name: str, jsonnet_file: str,
6383

6484
class MainTestSuite(BaseGraalVMTestSuite):
6585
"""Test suite for the main jsonnet test files."""
86+
87+
@classmethod
88+
def setUpClass(cls):
89+
super(MainTestSuite, cls).setUpClass()
90+
os.chdir(os.path.join(root_dir, "sjsonnet/test/resources/test_suite"))
6691

6792
def test_all_files(self):
6893
"""Test all files in the main test suite using subTest for each file."""
69-
test_dir = "sjsonnet/test/resources/test_suite"
70-
suite_name = "test_suite"
71-
72-
if not os.path.exists(test_dir):
73-
self.fail(f"Test directory {test_dir} not found")
74-
7594
# Skip list for main test suite
7695
skip_list = [
77-
"error.obj_recursive_manifest",
78-
"error.recursive_object_non_term",
79-
"error.recursive_import",
80-
"error.recursive_function_nonterm",
81-
"error.function_infinite_default",
82-
"error.obj_recursive",
83-
"error.array_recursive_manifest",
84-
"error.function_no_default_arg",
85-
"error.invariant.option",
86-
"error.negative_shfit",
96+
# Some slight differences with how graalvm throws exceptions
8797
"error.overflow",
8898
"error.overflow2",
8999
"error.overflow3",
90-
"error.parse_json",
91-
"error.parse.string.invalid_escape",
92-
"error.top_level_func",
93-
"stdlib",
94-
"tla.simple",
95-
"trace"
96100
]
97101

98102
# Find all .jsonnet files in the test directory
99-
jsonnet_pattern = os.path.join(test_dir, "*.jsonnet")
100-
jsonnet_files = glob.glob(jsonnet_pattern)
101-
102-
self.assertTrue(jsonnet_files, f"No .jsonnet files found in {test_dir}")
103+
jsonnet_files = glob.glob("*.jsonnet")
104+
self.assertTrue(jsonnet_files, f"No .jsonnet files found in {os.getcwd()}")
103105

104106
for jsonnet_file in sorted(jsonnet_files):
105107
base_name = Path(jsonnet_file).stem
@@ -109,32 +111,24 @@ def test_all_files(self):
109111
continue
110112

111113
with self.subTest(file=base_name):
112-
self.run_individual_test(test_dir, suite_name, jsonnet_file, base_name)
114+
self.run_individual_test(jsonnet_file, base_name)
113115

114116
class GoTestSuite(BaseGraalVMTestSuite):
115117
"""Test suite for the Go jsonnet test files."""
118+
119+
@classmethod
120+
def setUpClass(cls):
121+
super(GoTestSuite, cls).setUpClass()
122+
os.chdir(os.path.join(root_dir, "sjsonnet/test/resources/go_test_suite"))
116123

117124
def test_all_files(self):
118125
"""Test all files in the go test suite using subTest for each file."""
119-
test_dir = "sjsonnet/test/resources/go_test_suite"
120-
suite_name = "go_test_suite"
121-
122-
if not os.path.exists(test_dir):
123-
self.fail(f"Test directory {test_dir} not found")
124-
125-
# Skip list for go_test_suite
126+
# Skip list for go_test_suite - almost all of them due to floating point precision differences
126127
skip_list = [
127128
"builtin_cos",
128129
"builtin_exp4",
129130
"builtin_log3",
130131
"div3",
131-
"extvar_code",
132-
"extvar_error",
133-
"extvar_hermetic",
134-
"extvar_mutually_recursive",
135-
"extvar_self_recursive",
136-
"extvar_static_error",
137-
"extvar_string",
138132
"function_too_many_params",
139133
"native1",
140134
"native2",
@@ -150,10 +144,8 @@ def test_all_files(self):
150144
]
151145

152146
# Find all .jsonnet files in the test directory
153-
jsonnet_pattern = os.path.join(test_dir, "*.jsonnet")
154-
jsonnet_files = glob.glob(jsonnet_pattern)
155-
156-
self.assertTrue(jsonnet_files, f"No .jsonnet files found in {test_dir}")
147+
jsonnet_files = glob.glob("*.jsonnet")
148+
self.assertTrue(jsonnet_files, f"No .jsonnet files found in {os.getcwd()}")
157149

158150
for jsonnet_file in sorted(jsonnet_files):
159151
base_name = Path(jsonnet_file).stem
@@ -163,7 +155,7 @@ def test_all_files(self):
163155
continue
164156

165157
with self.subTest(file=base_name):
166-
self.run_individual_test(test_dir, suite_name, jsonnet_file, base_name)
158+
self.run_individual_test(jsonnet_file, base_name)
167159

168160

169161
if __name__ == "__main__":
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
sjsonnet.StaticError: Unknown variable: x
2-
at [Id x].(sjsonnet/test/resources/go_test_suite/arrcomp5.jsonnet:1:14)
2+
at [Id x].(arrcomp5.jsonnet:1:14)
33

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
sjsonnet.StaticError: Unknown variable: y
2-
at [Id y].(sjsonnet/test/resources/go_test_suite/arrcomp_if4.jsonnet:1:33)
2+
at [Id y].(arrcomp_if4.jsonnet:1:33)
33

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
sjsonnet.Error: Expected a number for offset in substr, got string
2-
at [std.substr].(sjsonnet/test/resources/go_test_suite/builtinSubStr_second_parameter_not_number.jsonnet:1:11)
2+
at [std.substr].(builtinSubStr_second_parameter_not_number.jsonnet:1:11)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
sjsonnet.Error: Expected a number for len in substr, got string
2-
at [std.substr].(sjsonnet/test/resources/go_test_suite/builtinSubStr_third_parameter_not_number.jsonnet:1:11)
2+
at [std.substr].(builtinSubStr_third_parameter_not_number.jsonnet:1:11)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
sjsonnet.StaticError: Can't use $ outside of an object
2-
at [$].(sjsonnet/test/resources/go_test_suite/dollar_bad.jsonnet:1:1)
2+
at [$].(dollar_bad.jsonnet:1:1)
33

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
sjsonnet.Error: xxx
2-
at [Error].(sjsonnet/test/resources/go_test_suite/error_from_array.jsonnet:1:2)
3-
at [Lookup].(sjsonnet/test/resources/go_test_suite/error_from_array.jsonnet:1:14)
2+
at [Error].(error_from_array.jsonnet:1:2)
3+
at [Lookup].(error_from_array.jsonnet:1:14)
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
sjsonnet.Error: xxx
2-
at [Error].(sjsonnet/test/resources/go_test_suite/error_from_func.jsonnet:1:25)
3-
at [Apply1].(sjsonnet/test/resources/go_test_suite/error_from_func.jsonnet:1:37)
2+
at [Error].(error_from_func.jsonnet:1:25)
3+
at [Apply1].(error_from_func.jsonnet:1:37)
44

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
sjsonnet.Error: Couldn't manifest function with params [x]
2-
at .(sjsonnet/test/resources/go_test_suite/error_function_fail.jsonnet:1:8)
3-
at [Error].(sjsonnet/test/resources/go_test_suite/error_function_fail.jsonnet:1:1)
2+
at .(error_function_fail.jsonnet:1:8)
3+
at [Error].(error_function_fail.jsonnet:1:1)
44

0 commit comments

Comments
 (0)