Skip to content

Commit b2dae39

Browse files
authored
JS-755 Cleanup embedded Node runtime when provisioning fails (#6633)
1 parent f5b142e commit b2dae39

4 files changed

Lines changed: 88 additions & 0 deletions

File tree

sonar-plugin/bridge/src/main/java/org/sonar/plugins/javascript/bridge/EmbeddedNode.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ public void deploy() throws IOException {
201201
LOG.debug("Deployed node version {}", detected);
202202
isAvailable = true;
203203
} catch (Exception e) {
204+
cleanupDeployedRuntime();
204205
LOG.warn(
205206
"""
206207
Embedded Node.js failed to deploy in {}.
@@ -214,6 +215,19 @@ public void deploy() throws IOException {
214215
}
215216
}
216217

218+
private void cleanupDeployedRuntime() {
219+
deleteIfExists(binary());
220+
deleteIfExists(deployLocation.resolve(VERSION_FILENAME));
221+
}
222+
223+
private static void deleteIfExists(Path path) {
224+
try {
225+
Files.deleteIfExists(path);
226+
} catch (IOException cleanupError) {
227+
LOG.debug("Failed to cleanup embedded Node.js artifact {}", path, cleanupError);
228+
}
229+
}
230+
217231
private static boolean isDifferent(InputStream newVersionIs, Path currentVersionPath)
218232
throws IOException {
219233
var newVersionString = new String(newVersionIs.readAllBytes(), StandardCharsets.UTF_8);
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* SonarQube JavaScript Plugin
3+
* Copyright (C) 2011-2025 SonarSource Sàrl
4+
* mailto:info AT sonarsource DOT com
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12+
* See the Sonar Source-Available License for more details.
13+
*
14+
* You should have received a copy of the Sonar Source-Available License
15+
* along with this program; if not, see https://sonarsource.com/license/ssal/
16+
*/
17+
package org.sonar.plugins.javascript.bridge;
18+
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.mockito.ArgumentMatchers.any;
21+
import static org.mockito.ArgumentMatchers.anyLong;
22+
import static org.mockito.Mockito.mock;
23+
import static org.mockito.Mockito.verify;
24+
import static org.mockito.Mockito.when;
25+
26+
import java.nio.charset.StandardCharsets;
27+
import java.nio.file.Files;
28+
import java.nio.file.Path;
29+
import org.junit.jupiter.api.Test;
30+
import org.junit.jupiter.api.io.TempDir;
31+
import org.sonar.plugins.javascript.nodejs.ProcessWrapper;
32+
33+
class EmbeddedNodeCleanupTest {
34+
35+
@TempDir
36+
Path tempDir;
37+
38+
@Test
39+
void should_cleanup_deployed_runtime_when_node_validation_fails() throws Exception {
40+
var processWrapper = mock(ProcessWrapper.class);
41+
when(processWrapper.startProcess(any(), any(), any(), any())).thenReturn(mock(Process.class));
42+
when(processWrapper.waitFor(any(), anyLong(), any())).thenReturn(true);
43+
when(processWrapper.exitValue(any())).thenReturn(1);
44+
45+
var env = mock(Environment.class);
46+
when(env.getOsName()).thenReturn("Linux");
47+
when(env.getOsArch()).thenReturn("amd64");
48+
when(env.isAlpine()).thenReturn(false);
49+
when(env.getSonarUserHome()).thenReturn(tempDir);
50+
51+
var embeddedNode = new EmbeddedNode(processWrapper, env);
52+
var runtimeDir = tempDir.resolve("js").resolve("node-runtime");
53+
var runtimeBinary = runtimeDir.resolve("node");
54+
var runtimeVersion = runtimeDir.resolve(EmbeddedNode.VERSION_FILENAME);
55+
Files.createDirectories(runtimeDir);
56+
Files.writeString(runtimeBinary, "broken");
57+
try (var versionInput = getClass().getResourceAsStream("/linux-x64/version.txt")) {
58+
assertThat(versionInput).isNotNull();
59+
Files.writeString(
60+
runtimeVersion,
61+
new String(versionInput.readAllBytes(), StandardCharsets.UTF_8)
62+
);
63+
}
64+
65+
embeddedNode.deploy();
66+
67+
assertThat(embeddedNode.isAvailable()).isFalse();
68+
assertThat(Files.exists(runtimeBinary)).isFalse();
69+
assertThat(Files.exists(runtimeVersion)).isFalse();
70+
verify(processWrapper).startProcess(any(), any(), any(), any());
71+
}
72+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
placeholder
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test-version

0 commit comments

Comments
 (0)