@@ -10,6 +10,7 @@ import com.coder.gateway.settings.CODER_SSH_CONFIG_OPTIONS
10
10
import com.coder.gateway.settings.CoderSettings
11
11
import com.coder.gateway.settings.CoderSettingsState
12
12
import com.coder.gateway.settings.Environment
13
+ import com.coder.gateway.util.DialogUi
13
14
import com.coder.gateway.util.InvalidVersionException
14
15
import com.coder.gateway.util.OS
15
16
import com.coder.gateway.util.SemVer
@@ -19,6 +20,9 @@ import com.coder.gateway.util.sha1
19
20
import com.coder.gateway.util.toURL
20
21
import com.squareup.moshi.JsonEncodingException
21
22
import com.sun.net.httpserver.HttpServer
23
+ import io.mockk.every
24
+ import io.mockk.mockkConstructor
25
+ import kotlinx.coroutines.runBlocking
22
26
import org.junit.jupiter.api.BeforeAll
23
27
import org.junit.jupiter.api.assertDoesNotThrow
24
28
import org.zeroturnaround.exec.InvalidExitValueException
@@ -28,7 +32,8 @@ import java.net.InetSocketAddress
28
32
import java.net.URL
29
33
import java.nio.file.AccessDeniedException
30
34
import java.nio.file.Path
31
- import java.util.*
35
+ import java.util.UUID
36
+ import kotlin.test.BeforeTest
32
37
import kotlin.test.Test
33
38
import kotlin.test.assertContains
34
39
import kotlin.test.assertEquals
@@ -37,6 +42,9 @@ import kotlin.test.assertFalse
37
42
import kotlin.test.assertNotEquals
38
43
import kotlin.test.assertTrue
39
44
45
+ private const val VERSION_FOR_PROGRESS_REPORTING = " v2.13.1-devel+de07351b8"
46
+ private val noOpTextProgress: (String ) -> Unit = { _ -> }
47
+
40
48
internal class CoderCLIManagerTest {
41
49
/* *
42
50
* Return the contents of a script that contains the string.
@@ -65,6 +73,9 @@ internal class CoderCLIManagerTest {
65
73
if (exchange.requestURI.path == " /bin/override" ) {
66
74
code = HttpURLConnection .HTTP_OK
67
75
response = mkbinVersion(" 0.0.0" )
76
+ } else if (exchange.requestURI.path.contains(" .asc" )) {
77
+ code = HttpURLConnection .HTTP_NOT_FOUND
78
+ response = " not found"
68
79
} else if (! exchange.requestURI.path.startsWith(" /bin/coder-" )) {
69
80
code = HttpURLConnection .HTTP_NOT_FOUND
70
81
response = " not found"
@@ -85,6 +96,13 @@ internal class CoderCLIManagerTest {
85
96
return Pair (srv, URL (" http://localhost:" + srv.address.port))
86
97
}
87
98
99
+ @BeforeTest
100
+ fun setup () {
101
+ // Mock the DialogUi constructor
102
+ mockkConstructor(DialogUi ::class )
103
+ every { anyConstructed<DialogUi >().confirm(any(), any()) } returns true
104
+ }
105
+
88
106
@Test
89
107
fun testServerInternalError () {
90
108
val (srv, url) = mockServer(HttpURLConnection .HTTP_INTERNAL_ERROR )
@@ -93,7 +111,7 @@ internal class CoderCLIManagerTest {
93
111
val ex =
94
112
assertFailsWith(
95
113
exceptionClass = ResponseException ::class ,
96
- block = { ccm.download() },
114
+ block = { runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING , noOpTextProgress ) } }
97
115
)
98
116
assertEquals(HttpURLConnection .HTTP_INTERNAL_ERROR , ex.code)
99
117
@@ -145,7 +163,7 @@ internal class CoderCLIManagerTest {
145
163
146
164
assertFailsWith(
147
165
exceptionClass = AccessDeniedException ::class ,
148
- block = { ccm.download() },
166
+ block = { runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING , noOpTextProgress) } },
149
167
)
150
168
151
169
srv.stop(0 )
@@ -168,15 +186,16 @@ internal class CoderCLIManagerTest {
168
186
CoderSettings (
169
187
CoderSettingsState (
170
188
dataDirectory = tmpdir.resolve(" real-cli" ).toString(),
189
+ fallbackOnCoderForSignatures = true
171
190
),
172
191
),
173
192
)
174
193
175
- assertTrue(ccm.download() )
194
+ assertTrue(runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING , noOpTextProgress) } )
176
195
assertDoesNotThrow { ccm.version() }
177
196
178
197
// It should skip the second attempt.
179
- assertFalse(ccm.download() )
198
+ assertFalse(runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING , noOpTextProgress) } )
180
199
181
200
// Make sure login failures propagate.
182
201
assertFailsWith(
@@ -194,16 +213,17 @@ internal class CoderCLIManagerTest {
194
213
CoderSettings (
195
214
CoderSettingsState (
196
215
dataDirectory = tmpdir.resolve(" mock-cli" ).toString(),
216
+ fallbackOnCoderForSignatures = true
197
217
),
198
218
binaryName = " coder.bat" ,
199
219
),
200
220
)
201
221
202
- assertEquals(true , ccm.download() )
222
+ assertEquals(true , runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING , noOpTextProgress) } )
203
223
assertEquals(SemVer (url.port.toLong(), 0 , 0 ), ccm.version())
204
224
205
225
// It should skip the second attempt.
206
- assertEquals(false , ccm.download() )
226
+ assertEquals(false , runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING , noOpTextProgress) } )
207
227
208
228
// Should use the source override.
209
229
ccm =
@@ -213,11 +233,12 @@ internal class CoderCLIManagerTest {
213
233
CoderSettingsState (
214
234
binarySource = " /bin/override" ,
215
235
dataDirectory = tmpdir.resolve(" mock-cli" ).toString(),
236
+ fallbackOnCoderForSignatures = true
216
237
),
217
238
),
218
239
)
219
240
220
- assertEquals(true , ccm.download() )
241
+ assertEquals(true , runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING , noOpTextProgress) } )
221
242
assertContains(ccm.localBinaryPath.toFile().readText(), " 0.0.0" )
222
243
223
244
srv.stop(0 )
@@ -242,14 +263,15 @@ internal class CoderCLIManagerTest {
242
263
}
243
264
244
265
@Test
245
- fun testOverwitesWrongVersion () {
266
+ fun testOverwritesWrongVersion () {
246
267
val (srv, url) = mockServer()
247
268
val ccm =
248
269
CoderCLIManager (
249
270
url,
250
271
CoderSettings (
251
272
CoderSettingsState (
252
273
dataDirectory = tmpdir.resolve(" overwrite-cli" ).toString(),
274
+ fallbackOnCoderForSignatures = true
253
275
),
254
276
),
255
277
)
@@ -261,7 +283,7 @@ internal class CoderCLIManagerTest {
261
283
assertEquals(" cli" , ccm.localBinaryPath.toFile().readText())
262
284
assertEquals(0 , ccm.localBinaryPath.toFile().lastModified())
263
285
264
- assertTrue(ccm.download() )
286
+ assertTrue(runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING , noOpTextProgress) } )
265
287
266
288
assertNotEquals(" cli" , ccm.localBinaryPath.toFile().readText())
267
289
assertNotEquals(0 , ccm.localBinaryPath.toFile().lastModified())
@@ -279,14 +301,15 @@ internal class CoderCLIManagerTest {
279
301
CoderSettings (
280
302
CoderSettingsState (
281
303
dataDirectory = tmpdir.resolve(" clobber-cli" ).toString(),
304
+ fallbackOnCoderForSignatures = true
282
305
),
283
306
)
284
307
285
308
val ccm1 = CoderCLIManager (url1, settings)
286
309
val ccm2 = CoderCLIManager (url2, settings)
287
310
288
- assertTrue(ccm1.download() )
289
- assertTrue(ccm2.download() )
311
+ assertTrue(runBlocking { ccm1.download(VERSION_FOR_PROGRESS_REPORTING , noOpTextProgress) } )
312
+ assertTrue(runBlocking { ccm2.download(VERSION_FOR_PROGRESS_REPORTING , noOpTextProgress) } )
290
313
291
314
srv1.stop(0 )
292
315
srv2.stop(0 )
@@ -314,8 +337,12 @@ internal class CoderCLIManagerTest {
314
337
fun testConfigureSSH () {
315
338
val workspace = workspace(" foo" , agents = mapOf (" agent1" to UUID .randomUUID().toString()))
316
339
val workspace2 = workspace(" bar" , agents = mapOf (" agent1" to UUID .randomUUID().toString()))
317
- val betterWorkspace = workspace(" foo" , agents = mapOf (" agent1" to UUID .randomUUID().toString()), ownerName = " bettertester" )
318
- val workspaceWithMultipleAgents = workspace(" foo" , agents = mapOf (" agent1" to UUID .randomUUID().toString(), " agent2" to UUID .randomUUID().toString()))
340
+ val betterWorkspace =
341
+ workspace(" foo" , agents = mapOf (" agent1" to UUID .randomUUID().toString()), ownerName = " bettertester" )
342
+ val workspaceWithMultipleAgents = workspace(
343
+ " foo" ,
344
+ agents = mapOf (" agent1" to UUID .randomUUID().toString(), " agent2" to UUID .randomUUID().toString())
345
+ )
319
346
320
347
val extraConfig =
321
348
listOf (
@@ -331,7 +358,12 @@ internal class CoderCLIManagerTest {
331
358
SSHTest (listOf (workspace), " existing-end" , " replace-end" , " no-blocks" ),
332
359
SSHTest (listOf (workspace), " existing-end-no-newline" , " replace-end-no-newline" , " no-blocks" ),
333
360
SSHTest (listOf (workspace), " existing-middle" , " replace-middle" , " no-blocks" ),
334
- SSHTest (listOf (workspace), " existing-middle-and-unrelated" , " replace-middle-ignore-unrelated" , " no-related-blocks" ),
361
+ SSHTest (
362
+ listOf (workspace),
363
+ " existing-middle-and-unrelated" ,
364
+ " replace-middle-ignore-unrelated" ,
365
+ " no-related-blocks"
366
+ ),
335
367
SSHTest (listOf (workspace), " existing-only" , " replace-only" , " blank" ),
336
368
SSHTest (listOf (workspace), " existing-start" , " replace-start" , " no-blocks" ),
337
369
SSHTest (listOf (workspace), " no-blocks" , " append-no-blocks" , " no-blocks" ),
@@ -463,7 +495,10 @@ internal class CoderCLIManagerTest {
463
495
Path .of(" src/test/fixtures/outputs/" ).resolve(it.output + " .conf" ).toFile().readText()
464
496
.replace(newlineRe, System .lineSeparator())
465
497
.replace(" /tmp/coder-gateway/test.coder.invalid/config" , escape(coderConfigPath.toString()))
466
- .replace(" /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" , escape(ccm.localBinaryPath.toString()))
498
+ .replace(
499
+ " /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" ,
500
+ escape(ccm.localBinaryPath.toString())
501
+ )
467
502
.let { conf ->
468
503
if (it.sshLogDirectory != null ) {
469
504
conf.replace(" /tmp/coder-gateway/test.coder.invalid/logs" , it.sshLogDirectory.toString())
@@ -476,7 +511,10 @@ internal class CoderCLIManagerTest {
476
511
Path .of(" src/test/fixtures/inputs/" ).resolve(it.remove + " .conf" ).toFile().readText()
477
512
.replace(newlineRe, System .lineSeparator())
478
513
.replace(" /tmp/coder-gateway/test.coder.invalid/config" , escape(coderConfigPath.toString()))
479
- .replace(" /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" , escape(ccm.localBinaryPath.toString()))
514
+ .replace(
515
+ " /tmp/coder-gateway/test.coder.invalid/coder-linux-amd64" ,
516
+ escape(ccm.localBinaryPath.toString())
517
+ )
480
518
.let { conf ->
481
519
if (it.sshLogDirectory != null ) {
482
520
conf.replace(" /tmp/coder-gateway/test.coder.invalid/logs" , it.sshLogDirectory.toString())
@@ -552,7 +590,10 @@ internal class CoderCLIManagerTest {
552
590
" new\n line" ,
553
591
)
554
592
555
- val workspace = workspace(" foo" , agents = mapOf (" agentid1" to UUID .randomUUID().toString(), " agentid2" to UUID .randomUUID().toString()))
593
+ val workspace = workspace(
594
+ " foo" ,
595
+ agents = mapOf (" agentid1" to UUID .randomUUID().toString(), " agentid2" to UUID .randomUUID().toString())
596
+ )
556
597
val withAgents = workspace.latestBuild.resources.filter { it.agents != null }.flatMap { it.agents!! }.map {
557
598
workspace to it
558
599
}
@@ -730,8 +771,24 @@ internal class CoderCLIManagerTest {
730
771
EnsureCLITest (null , null , " 1.0.0" , false , true , true , Result .DL_DATA ), // Download to fallback.
731
772
EnsureCLITest (null , null , " 1.0.0" , false , false , true , Result .NONE ), // No download, error when used.
732
773
EnsureCLITest (" 1.0.1" , " 1.0.1" , " 1.0.0" , false , true , true , Result .DL_DATA ), // Update fallback.
733
- EnsureCLITest (" 1.0.1" , " 1.0.2" , " 1.0.0" , false , false , true , Result .USE_BIN ), // No update, use outdated.
734
- EnsureCLITest (null , " 1.0.2" , " 1.0.0" , false , false , true , Result .USE_DATA ), // No update, use outdated fallback.
774
+ EnsureCLITest (
775
+ " 1.0.1" ,
776
+ " 1.0.2" ,
777
+ " 1.0.0" ,
778
+ false ,
779
+ false ,
780
+ true ,
781
+ Result .USE_BIN
782
+ ), // No update, use outdated.
783
+ EnsureCLITest (
784
+ null ,
785
+ " 1.0.2" ,
786
+ " 1.0.0" ,
787
+ false ,
788
+ false ,
789
+ true ,
790
+ Result .USE_DATA
791
+ ), // No update, use outdated fallback.
735
792
EnsureCLITest (" 1.0.0" , null , " 1.0.0" , false , false , true , Result .USE_BIN ), // Use existing.
736
793
EnsureCLITest (" 1.0.1" , " 1.0.0" , " 1.0.0" , false , false , true , Result .USE_DATA ), // Use existing fallback.
737
794
)
@@ -746,6 +803,7 @@ internal class CoderCLIManagerTest {
746
803
enableBinaryDirectoryFallback = it.enableFallback,
747
804
dataDirectory = tmpdir.resolve(" ensure-data-dir" ).toString(),
748
805
binaryDirectory = tmpdir.resolve(" ensure-bin-dir" ).toString(),
806
+ fallbackOnCoderForSignatures = true
749
807
),
750
808
)
751
809
@@ -777,34 +835,39 @@ internal class CoderCLIManagerTest {
777
835
Result .ERROR -> {
778
836
assertFailsWith(
779
837
exceptionClass = AccessDeniedException ::class ,
780
- block = { ensureCLI(url, it.buildVersion, settings) },
838
+ block = { runBlocking { ensureCLI(url, it.buildVersion, settings, noOpTextProgress ) } }
781
839
)
782
840
}
841
+
783
842
Result .NONE -> {
784
- val ccm = ensureCLI(url, it.buildVersion, settings)
843
+ val ccm = runBlocking { ensureCLI(url, it.buildVersion, settings, noOpTextProgress) }
785
844
assertEquals(settings.binPath(url), ccm.localBinaryPath)
786
845
assertFailsWith(
787
846
exceptionClass = ProcessInitException ::class ,
788
847
block = { ccm.version() },
789
848
)
790
849
}
850
+
791
851
Result .DL_BIN -> {
792
- val ccm = ensureCLI(url, it.buildVersion, settings)
852
+ val ccm = runBlocking { ensureCLI(url, it.buildVersion, settings, noOpTextProgress) }
793
853
assertEquals(settings.binPath(url), ccm.localBinaryPath)
794
854
assertEquals(SemVer (url.port.toLong(), 0 , 0 ), ccm.version())
795
855
}
856
+
796
857
Result .DL_DATA -> {
797
- val ccm = ensureCLI(url, it.buildVersion, settings)
858
+ val ccm = runBlocking { ensureCLI(url, it.buildVersion, settings, noOpTextProgress) }
798
859
assertEquals(settings.binPath(url, true ), ccm.localBinaryPath)
799
860
assertEquals(SemVer (url.port.toLong(), 0 , 0 ), ccm.version())
800
861
}
862
+
801
863
Result .USE_BIN -> {
802
- val ccm = ensureCLI(url, it.buildVersion, settings)
864
+ val ccm = runBlocking { ensureCLI(url, it.buildVersion, settings, noOpTextProgress) }
803
865
assertEquals(settings.binPath(url), ccm.localBinaryPath)
804
866
assertEquals(SemVer .parse(it.version ? : " " ), ccm.version())
805
867
}
868
+
806
869
Result .USE_DATA -> {
807
- val ccm = ensureCLI(url, it.buildVersion, settings)
870
+ val ccm = runBlocking { ensureCLI(url, it.buildVersion, settings, noOpTextProgress) }
808
871
assertEquals(settings.binPath(url, true ), ccm.localBinaryPath)
809
872
assertEquals(SemVer .parse(it.fallbackVersion ? : " " ), ccm.version())
810
873
}
@@ -838,19 +901,21 @@ internal class CoderCLIManagerTest {
838
901
CoderSettings (
839
902
CoderSettingsState (
840
903
dataDirectory = tmpdir.resolve(" features" ).toString(),
904
+ fallbackOnCoderForSignatures = true
841
905
),
842
906
binaryName = " coder.bat" ,
843
907
),
844
908
)
845
- assertEquals(true , ccm.download() )
909
+ assertEquals(true , runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING , noOpTextProgress) } )
846
910
assertEquals(it.second, ccm.features, " version: ${it.first} " )
847
911
848
912
srv.stop(0 )
849
913
}
850
914
}
851
915
852
916
companion object {
853
- private val tmpdir: Path = Path .of(System .getProperty(" java.io.tmpdir" )).resolve(" coder-gateway-test/cli-manager" )
917
+ private val tmpdir: Path =
918
+ Path .of(System .getProperty(" java.io.tmpdir" )).resolve(" coder-gateway-test/cli-manager" )
854
919
855
920
@JvmStatic
856
921
@BeforeAll
0 commit comments