Skip to content

Commit a253ab2

Browse files
jamesjames
authored andcommitted
fix: resolve node for Java smoke host
References sdk-smoke Java failure in run 28129531025.
1 parent 3f8e6f4 commit a253ab2

1 file changed

Lines changed: 79 additions & 3 deletions

File tree

java/src/test/java/com/jestevery/codebridge/ProtocolHostProcess.java

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
import java.io.IOException;
66
import java.io.InputStreamReader;
77
import java.util.ArrayList;
8+
import java.util.LinkedHashSet;
89
import java.util.List;
10+
import java.util.Locale;
911
import java.util.Map;
12+
import java.util.Set;
1013
import java.util.concurrent.TimeUnit;
1114

1215
import com.google.gson.Gson;
@@ -19,10 +22,10 @@ class ProtocolHostProcess implements AutoCloseable {
1922

2023
ProtocolHostProcess(int port, boolean autoPong, boolean sendControl, boolean dropPong) throws IOException, InterruptedException {
2124
File script = new File("src/test/resources/ProtocolHost.js");
22-
String node = "/usr/local/bin/node";
23-
ProcessBuilder pb = new ProcessBuilder(node, script.getAbsolutePath());
25+
ProcessBuilder pb = new ProcessBuilder();
2426
Map<String, String> env = pb.environment();
25-
env.put("PATH", System.getenv("PATH"));
27+
String node = resolveNodeCommand(env);
28+
pb.command(node, script.getAbsolutePath());
2629
env.put("PORT", Integer.toString(port));
2730
env.put("SECRET", "dev-secret");
2831
env.put("AUTO_PONG", autoPong ? "true" : "false");
@@ -50,6 +53,79 @@ class ProtocolHostProcess implements AutoCloseable {
5053
}
5154
}
5255

56+
private static String resolveNodeCommand(Map<String, String> env) throws IOException {
57+
// CODE_BRIDGE_NODE may point at a specific node binary for environments
58+
// where the Java test process does not inherit the expected PATH.
59+
String override = trimToNull(env.get("CODE_BRIDGE_NODE"));
60+
if (override != null) {
61+
if (isPathLike(override)) {
62+
File file = new File(override);
63+
if (file.isFile() && file.canExecute()) {
64+
return file.getAbsolutePath();
65+
}
66+
throw new IOException("CODE_BRIDGE_NODE must point to an executable node binary: " + override);
67+
}
68+
69+
String resolved = findExecutableOnPath(override, env.get("PATH"));
70+
if (resolved != null) {
71+
return resolved;
72+
}
73+
throw new IOException("CODE_BRIDGE_NODE was set but not found on PATH: " + override);
74+
}
75+
76+
String resolved = findExecutableOnPath("node", env.get("PATH"));
77+
if (resolved != null) {
78+
return resolved;
79+
}
80+
throw new IOException("node executable not found on PATH; set CODE_BRIDGE_NODE to the node binary for Java protocol tests");
81+
}
82+
83+
private static String findExecutableOnPath(String command, String path) {
84+
if (trimToNull(path) == null) {
85+
return null;
86+
}
87+
88+
for (String dir : path.split(File.pathSeparator)) {
89+
if (dir.isBlank()) {
90+
continue;
91+
}
92+
for (String candidate : executableCandidates(command)) {
93+
File file = new File(dir, candidate);
94+
if (file.isFile() && file.canExecute()) {
95+
return file.getAbsolutePath();
96+
}
97+
}
98+
}
99+
return null;
100+
}
101+
102+
private static Set<String> executableCandidates(String command) {
103+
Set<String> candidates = new LinkedHashSet<>();
104+
candidates.add(command);
105+
106+
String pathExt = System.getenv("PATHEXT");
107+
if (pathExt != null) {
108+
for (String extension : pathExt.split(File.pathSeparator)) {
109+
if (!extension.isBlank()
110+
&& !command.toLowerCase(Locale.ROOT).endsWith(extension.toLowerCase(Locale.ROOT))) {
111+
candidates.add(command + extension);
112+
}
113+
}
114+
}
115+
return candidates;
116+
}
117+
118+
private static boolean isPathLike(String command) {
119+
return new File(command).isAbsolute() || command.contains("/") || command.contains("\\");
120+
}
121+
122+
private static String trimToNull(String value) {
123+
if (value == null || value.trim().isEmpty()) {
124+
return null;
125+
}
126+
return value.trim();
127+
}
128+
53129
List<Map<String, Object>> readEvents(long timeoutMs) throws IOException {
54130
long deadline = System.currentTimeMillis() + timeoutMs;
55131
List<Map<String, Object>> events = new ArrayList<>();

0 commit comments

Comments
 (0)