Skip to content

Commit caf25ef

Browse files
authored
Merge pull request #82 from Alipsa/codex/updater-script-tests
[codex] Testa updaterloggning
2 parents d8ca88d + 3acdc78 commit caf25ef

2 files changed

Lines changed: 167 additions & 1 deletion

File tree

app/src/main/groovy/se/alipsa/accounting/service/UpdateService.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ final class UpdateService {
249249
}
250250
}
251251

252-
private Path writeUpdaterScript(Path stagingDir, Path extractedDir, Path installDir, Path updaterLog) {
252+
Path writeUpdaterScript(Path stagingDir, Path extractedDir, Path installDir, Path updaterLog) {
253253
String osName = System.getProperty('os.name', '').toLowerCase(Locale.ROOT)
254254
boolean isWindows = osName.contains('win')
255255
Path launcher = launcherPath()
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
package se.alipsa.accounting.service
2+
3+
import static org.junit.jupiter.api.Assertions.*
4+
import static org.junit.jupiter.api.Assumptions.assumeTrue
5+
6+
import org.junit.jupiter.api.AfterEach
7+
import org.junit.jupiter.api.BeforeEach
8+
import org.junit.jupiter.api.Test
9+
import org.junit.jupiter.api.io.TempDir
10+
import org.junit.jupiter.params.ParameterizedTest
11+
import org.junit.jupiter.params.provider.ValueSource
12+
13+
import java.nio.file.Files
14+
import java.nio.file.Path
15+
import java.util.concurrent.TimeUnit
16+
17+
final class UpdateServiceUpdaterScriptTest {
18+
19+
@TempDir
20+
Path tempDir
21+
22+
private String previousOsName
23+
24+
@BeforeEach
25+
void captureSystemProperties() {
26+
previousOsName = System.getProperty('os.name')
27+
}
28+
29+
@AfterEach
30+
void restoreSystemProperties() {
31+
restoreProperty('os.name', previousOsName)
32+
}
33+
34+
@ParameterizedTest
35+
@ValueSource(strings = ['Linux', 'Mac OS X'])
36+
void generatedUnixUpdaterScriptWritesPersistentLog(String osName) {
37+
ScriptFixture fixture = createFixture()
38+
System.setProperty('os.name', osName)
39+
40+
Path script = new UpdateService().writeUpdaterScript(
41+
fixture.stagingDir, fixture.extractedDir, fixture.installDir, fixture.updaterLog)
42+
String content = Files.readString(script)
43+
44+
assertEquals('updater.sh', script.fileName.toString())
45+
if (File.separatorChar == (char) '/') {
46+
assertTrue(Files.isExecutable(script))
47+
}
48+
assertTrue(content.contains("LOG_FILE=\"${fixture.updaterLog}\""))
49+
assertTrue(content.contains('exec >> "$LOG_FILE" 2>&1'))
50+
assertTrue(content.contains('log "Starting update."'))
51+
assertTrue(content.contains('log "Backing up current JAR files."'))
52+
assertTrue(content.contains('log "Copying updated JAR files."'))
53+
assertTrue(content.contains('log "Update failed while copying files, restoring backup..."'))
54+
assertTrue(content.contains('log "Updating launcher configuration."'))
55+
assertTrue(content.contains('log "Launching application."'))
56+
assertTrue(content.contains('app-1.4.0.jar'))
57+
}
58+
59+
@Test
60+
void generatedWindowsUpdaterScriptWritesPersistentLog() {
61+
ScriptFixture fixture = createFixture()
62+
System.setProperty('os.name', 'Windows 11')
63+
64+
Path script = new UpdateService().writeUpdaterScript(
65+
fixture.stagingDir, fixture.extractedDir, fixture.installDir, fixture.updaterLog)
66+
String content = Files.readString(script)
67+
68+
assertEquals('updater.bat', script.fileName.toString())
69+
assertTrue(content.contains("set \"LOG_FILE=${fixture.updaterLog}\""))
70+
assertTrue(content.contains('call :main >> "%LOG_FILE%" 2>&1'))
71+
assertTrue(content.contains('echo [%DATE% %TIME%] Starting update.'))
72+
assertTrue(content.contains('echo [%DATE% %TIME%] Backing up current JAR files.'))
73+
assertTrue(content.contains('echo [%DATE% %TIME%] Copying updated JAR files.'))
74+
assertTrue(content.contains('Update failed while copying files, restoring backup'))
75+
assertTrue(content.contains('echo [%DATE% %TIME%] Updating launcher configuration.'))
76+
assertTrue(content.contains('echo [%DATE% %TIME%] Launching application.'))
77+
assertTrue(content.contains('app-1.4.0.jar'))
78+
}
79+
80+
@Test
81+
void unixUpdaterScriptUpdatesFakeInstallDirectoryAndLogsProgress() {
82+
assumeTrue(File.separatorChar == (char) '/', 'Unix updater execution is only verified on Unix-like hosts.')
83+
assumeTrue(commandAvailable('bash'), 'bash is required to execute the generated updater script.')
84+
85+
ScriptFixture fixture = createFixture()
86+
System.setProperty('os.name', 'Linux')
87+
Path script = new UpdateService().writeUpdaterScript(
88+
fixture.stagingDir, fixture.extractedDir, fixture.installDir, fixture.updaterLog)
89+
restoreProperty('os.name', previousOsName)
90+
91+
Process process = new ProcessBuilder('bash', script.toString())
92+
.directory(fixture.stagingDir.toFile())
93+
.start()
94+
boolean finished = process.waitFor(10, TimeUnit.SECONDS)
95+
if (!finished) {
96+
process.destroyForcibly()
97+
}
98+
99+
assertTrue(finished, 'Updater script did not finish within the timeout.')
100+
assertEquals(0, process.exitValue())
101+
assertFalse(Files.exists(fixture.installDir.resolve('app-1.2.0.jar')))
102+
assertTrue(Files.isRegularFile(fixture.installDir.resolve('app-1.4.0.jar')))
103+
assertFalse(Files.exists(script))
104+
105+
String cfg = Files.readString(fixture.installDir.resolve('app.cfg'))
106+
assertTrue(cfg.contains('app.classpath=$APPDIR/app-1.4.0.jar'))
107+
assertTrue(cfg.contains('java-options=-Djpackage.app-version=1.4.0'))
108+
109+
String log = Files.readString(fixture.updaterLog)
110+
assertTrue(log.contains('Starting update.'))
111+
assertTrue(log.contains('Backing up current JAR files.'))
112+
assertTrue(log.contains('Copying updated JAR files.'))
113+
assertTrue(log.contains('Updating launcher configuration.'))
114+
assertTrue(log.contains('Update script finished.'))
115+
}
116+
117+
private ScriptFixture createFixture() {
118+
Path stagingDir = tempDir.resolve('staging')
119+
Path extractedDir = stagingDir.resolve('extracted')
120+
Path installDir = tempDir.resolve('install').resolve('lib').resolve('app')
121+
Path updaterLog = tempDir.resolve('logs').resolve('updater.log')
122+
123+
Files.createDirectories(extractedDir)
124+
Files.createDirectories(installDir)
125+
Files.createDirectories(updaterLog.parent)
126+
Files.writeString(extractedDir.resolve('app-1.4.0.jar'), 'new jar')
127+
Files.writeString(installDir.resolve('app-1.2.0.jar'), 'old jar')
128+
Files.writeString(installDir.resolve('app.cfg'),
129+
'app.classpath=$APPDIR/app-1.2.0.jar\njava-options=-Djpackage.app-version=1.2.0\n')
130+
131+
new ScriptFixture(stagingDir, extractedDir, installDir, updaterLog)
132+
}
133+
134+
private static boolean commandAvailable(String command) {
135+
try {
136+
Process process = new ProcessBuilder(command, '--version').start()
137+
boolean finished = process.waitFor(5, TimeUnit.SECONDS)
138+
return finished && process.exitValue() == 0
139+
} catch (IOException ignored) {
140+
return false
141+
}
142+
}
143+
144+
private static void restoreProperty(String name, String value) {
145+
if (value == null) {
146+
System.clearProperty(name)
147+
return
148+
}
149+
System.setProperty(name, value)
150+
}
151+
152+
private static final class ScriptFixture {
153+
154+
final Path stagingDir
155+
final Path extractedDir
156+
final Path installDir
157+
final Path updaterLog
158+
159+
private ScriptFixture(Path stagingDir, Path extractedDir, Path installDir, Path updaterLog) {
160+
this.stagingDir = stagingDir
161+
this.extractedDir = extractedDir
162+
this.installDir = installDir
163+
this.updaterLog = updaterLog
164+
}
165+
}
166+
}

0 commit comments

Comments
 (0)