Skip to content

Commit bf7fd5f

Browse files
committed
Add native conditional resource tests
1 parent d83855c commit bf7fd5f

10 files changed

Lines changed: 248 additions & 0 deletions

File tree

substratevm/mx.substratevm/mx_substratevm.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,7 @@ def conditional_config_task(native_image):
770770
''')
771771
run_agent_conditional_config_test(agent_path, conditional_config_filter_path)
772772
run_nic_conditional_config_test(agent_path, conditional_config_filter_path)
773+
run_native_conditional_resource_tests(native_image)
773774

774775

775776
def run_nic_conditional_config_test(agent_path, conditional_config_filter_path):
@@ -845,6 +846,14 @@ def run_agent_conditional_config_test(agent_path, conditional_config_filter_path
845846
'com.oracle.svm.configure.test.conditionalconfig.ConfigurationVerifier'])
846847

847848

849+
def run_native_conditional_resource_tests(native_image):
850+
_native_junit(
851+
native_image,
852+
['com.oracle.svm.configure.test.conditionalconfig.ConditionalResourceRegistrationTest'],
853+
['--exact-reachability-metadata=java.lang', '--exact-reachability-metadata=java.util', '-H:+ReportExceptionStackTraces']
854+
)
855+
856+
848857
def javac_image_command(javac_path):
849858
return [join(javac_path, 'javac'), '-proc:none'] + (
850859
# We need to set java.home as com.sun.tools.javac.file.Locations.<clinit> can't handle `null`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"resources": [
3+
{
4+
"condition": {
5+
"typeReached": "com.oracle.svm.configure.test.conditionalconfig.ExactResourceUnsatisfiedConditionMarker"
6+
},
7+
"glob": "com/oracle/svm/configure/test/conditionalconfig/resources/NativeConditionalExactUnsatisfied.txt"
8+
},
9+
{
10+
"condition": {
11+
"typeReached": "com.oracle.svm.configure.test.conditionalconfig.ExactResourceSatisfiedConditionMarker"
12+
},
13+
"glob": "com/oracle/svm/configure/test/conditionalconfig/resources/NativeConditionalExactSatisfied.txt"
14+
},
15+
{
16+
"condition": {
17+
"typeReached": "com.oracle.svm.configure.test.conditionalconfig.GlobResourceUnsatisfiedConditionMarker"
18+
},
19+
"glob": "com/oracle/svm/configure/test/conditionalconfig/resources/native-glob/unsatisfied/**/NativeConditionalGlobUnsatisfied.txt"
20+
},
21+
{
22+
"condition": {
23+
"typeReached": "com.oracle.svm.configure.test.conditionalconfig.GlobResourceSatisfiedConditionMarker"
24+
},
25+
"glob": "com/oracle/svm/configure/test/conditionalconfig/resources/native-glob/satisfied/**/NativeConditionalGlobSatisfied.txt"
26+
},
27+
{
28+
"condition": {
29+
"typeReached": "com.oracle.svm.configure.test.conditionalconfig.BundleUnsatisfiedConditionMarker"
30+
},
31+
"bundle": "com.oracle.svm.configure.test.conditionalconfig.bundles.NativeConditionalUnsatisfiedBundle"
32+
},
33+
{
34+
"condition": {
35+
"typeReached": "com.oracle.svm.configure.test.conditionalconfig.BundleSatisfiedConditionMarker"
36+
},
37+
"bundle": "com.oracle.svm.configure.test.conditionalconfig.bundles.NativeConditionalSatisfiedBundle"
38+
}
39+
]
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright (c) 2026, 2026, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.configure.test.conditionalconfig;
26+
27+
final class ExactResourceUnsatisfiedConditionMarker {
28+
}
29+
30+
final class ExactResourceSatisfiedConditionMarker {
31+
static void touch() {
32+
}
33+
}
34+
35+
final class GlobResourceUnsatisfiedConditionMarker {
36+
}
37+
38+
final class GlobResourceSatisfiedConditionMarker {
39+
static void touch() {
40+
}
41+
}
42+
43+
final class BundleUnsatisfiedConditionMarker {
44+
}
45+
46+
final class BundleSatisfiedConditionMarker {
47+
static void touch() {
48+
}
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
* Copyright (c) 2026, 2026, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.configure.test.conditionalconfig;
26+
27+
import java.io.IOException;
28+
import java.io.InputStream;
29+
import java.net.URL;
30+
import java.util.Locale;
31+
import java.util.MissingResourceException;
32+
import java.util.ResourceBundle;
33+
34+
import org.junit.Assert;
35+
import org.junit.Test;
36+
37+
public class ConditionalResourceRegistrationTest {
38+
39+
private static final String RESOURCE_ROOT = "com/oracle/svm/configure/test/conditionalconfig/resources/";
40+
private static final String ABSOLUTE_RESOURCE_ROOT = "/" + RESOURCE_ROOT;
41+
private static final String BUNDLE_ROOT = "com.oracle.svm.configure.test.conditionalconfig.bundles.";
42+
private static final Module TEST_MODULE = ConditionalResourceRegistrationTest.class.getModule();
43+
44+
private static final String EXACT_UNSATISFIED_RESOURCE = RESOURCE_ROOT + "NativeConditionalExactUnsatisfied.txt";
45+
private static final String EXACT_SATISFIED_RESOURCE = RESOURCE_ROOT + "NativeConditionalExactSatisfied.txt";
46+
private static final String GLOB_UNSATISFIED_RESOURCE = RESOURCE_ROOT + "native-glob/unsatisfied/deep/NativeConditionalGlobUnsatisfied.txt";
47+
private static final String GLOB_SATISFIED_RESOURCE = RESOURCE_ROOT + "native-glob/satisfied/deep/NativeConditionalGlobSatisfied.txt";
48+
49+
private static final String UNSATISFIED_BUNDLE = BUNDLE_ROOT + "NativeConditionalUnsatisfiedBundle";
50+
private static final String SATISFIED_BUNDLE = BUNDLE_ROOT + "NativeConditionalSatisfiedBundle";
51+
52+
private static final String MATCHING_METADATA_MESSAGE =
53+
"Matching reachability metadata was found for this access, but it is currently inactive because its runtime conditions were not satisfied.";
54+
private static final String UNSATISFIED_CONDITIONS_HINT =
55+
"To fix this, either change/remove the metadata condition, or make sure the condition is reached before this access.";
56+
private static final String UNSATISFIED_CONDITIONS_LABEL = "Unsatisfied runtime conditions:";
57+
58+
private static final String CONDITION_PACKAGE = "com.oracle.svm.configure.test.conditionalconfig.";
59+
private static final String EXACT_UNSATISFIED_CONDITION = CONDITION_PACKAGE + "ExactResourceUnsatisfiedConditionMarker";
60+
private static final String GLOB_UNSATISFIED_CONDITION = CONDITION_PACKAGE + "GlobResourceUnsatisfiedConditionMarker";
61+
private static final String BUNDLE_UNSATISFIED_CONDITION = CONDITION_PACKAGE + "BundleUnsatisfiedConditionMarker";
62+
63+
@Test
64+
public void exactResourceBecomesAvailableAfterConditionIsReached() throws IOException {
65+
ExactResourceSatisfiedConditionMarker.touch();
66+
try (InputStream stream = TEST_MODULE.getResourceAsStream(EXACT_SATISFIED_RESOURCE)) {
67+
Assert.assertNotNull("Condition-satisfied resource should be available.", stream);
68+
Assert.assertEquals("native-conditional-exact-satisfied", new String(stream.readAllBytes()).trim());
69+
}
70+
}
71+
72+
@Test
73+
public void exactResourceUrlResolvesAfterConditionIsReached() throws IOException {
74+
ExactResourceSatisfiedConditionMarker.touch();
75+
URL url = ConditionalResourceRegistrationTest.class.getResource("/" + EXACT_SATISFIED_RESOURCE);
76+
Assert.assertNotNull("Condition-satisfied resource URL should be available.", url);
77+
try (InputStream stream = url.openStream()) {
78+
Assert.assertEquals("native-conditional-exact-satisfied", new String(stream.readAllBytes()).trim());
79+
}
80+
}
81+
82+
@Test
83+
public void globResourceBecomesAvailableAfterConditionIsReached() throws IOException {
84+
GlobResourceSatisfiedConditionMarker.touch();
85+
try (InputStream stream = TEST_MODULE.getResourceAsStream(GLOB_SATISFIED_RESOURCE)) {
86+
Assert.assertNotNull("Condition-satisfied glob resource should be available.", stream);
87+
Assert.assertEquals("native-conditional-glob-satisfied", new String(stream.readAllBytes()).trim());
88+
}
89+
}
90+
91+
@Test
92+
public void globResourceUrlResolvesAfterConditionIsReached() throws IOException {
93+
GlobResourceSatisfiedConditionMarker.touch();
94+
URL url = ConditionalResourceRegistrationTest.class.getClassLoader().getResource(GLOB_SATISFIED_RESOURCE);
95+
Assert.assertNotNull("Condition-satisfied glob resource URL should be available.", url);
96+
try (InputStream stream = url.openStream()) {
97+
Assert.assertEquals("native-conditional-glob-satisfied", new String(stream.readAllBytes()).trim());
98+
}
99+
}
100+
101+
@Test
102+
public void bundleWithInactiveConditionRemainsUnavailable() {
103+
assertInactiveBundleAccess(new ThrowingAction() {
104+
@Override
105+
public Object run() {
106+
return ResourceBundle.getBundle(UNSATISFIED_BUNDLE, Locale.ROOT);
107+
}
108+
}, UNSATISFIED_BUNDLE, BUNDLE_UNSATISFIED_CONDITION);
109+
}
110+
111+
@Test
112+
public void bundleBecomesAvailableAfterConditionIsReached() {
113+
BundleSatisfiedConditionMarker.touch();
114+
ResourceBundle bundle = ResourceBundle.getBundle(SATISFIED_BUNDLE, Locale.ROOT);
115+
Assert.assertEquals("native-conditional-bundle-satisfied", bundle.getString("message"));
116+
}
117+
118+
private static void assertInactiveBundleAccess(ThrowingAction action, String expectedBundleName, String expectedCondition) {
119+
try {
120+
Object result = action.run();
121+
if (result instanceof ResourceBundle bundle) {
122+
Assert.fail("Inactive metadata access should not resolve a resource bundle: " + bundle.getBaseBundleName());
123+
}
124+
Assert.assertNull("Inactive metadata access should either return null or throw.", result);
125+
} catch (MissingResourceException e) {
126+
// Expected for resource bundle lookups when the conditional metadata stays inactive.
127+
} catch (Throwable t) {
128+
Assert.assertTrue("Expected a missing registration error.", t instanceof Error);
129+
Assert.assertEquals("com.oracle.svm.core.jdk.resources.MissingResourceRegistrationError", t.getClass().getName());
130+
String message = t.getMessage();
131+
Assert.assertNotNull("Missing registration error must have a message.", message);
132+
Assert.assertTrue("Error message should mention the missing bundle.", message.contains(expectedBundleName));
133+
if (message.contains(MATCHING_METADATA_MESSAGE)) {
134+
Assert.assertTrue("Inactive metadata diagnostics should contain the remediation hint.", message.contains(UNSATISFIED_CONDITIONS_HINT));
135+
Assert.assertTrue("Inactive metadata diagnostics should list unsatisfied conditions.", message.contains(UNSATISFIED_CONDITIONS_LABEL));
136+
Assert.assertTrue("Inactive metadata diagnostics should mention the expected condition.", message.contains("\"typeReached\": \"" + expectedCondition + "\""));
137+
}
138+
}
139+
}
140+
141+
private interface ThrowingAction {
142+
Object run() throws Throwable;
143+
}
144+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
message=native-conditional-bundle-satisfied
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
message=native-conditional-bundle-unsatisfied
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
native-conditional-exact-satisfied
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
native-conditional-exact-unsatisfied
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
native-conditional-glob-satisfied
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
native-conditional-glob-unsatisfied

0 commit comments

Comments
 (0)