@@ -32,23 +32,34 @@ import kotlin.test.assertNotEquals
32
32
import kotlin.test.assertTrue
33
33
34
34
internal class CoderCLIManagerTest {
35
- private fun mkbin (version : String ):String {
36
- return listOf (" #!/bin/sh" ,""" echo '{"version": "$version "}'""" )
37
- .joinToString(" \n " )
35
+ /* *
36
+ * Return the contents of a script that contains the string.
37
+ */
38
+ private fun mkbin (str : String ):String {
39
+ return if (getOS()== OS .WINDOWS ) {
40
+ // Must use a .bat extension for this to work.
41
+ listOf (" @echo off" , str)
42
+ }else {
43
+ listOf (" #!/bin/sh" , str)
44
+ }.joinToString(System .lineSeparator())
45
+ }
46
+
47
+ /* *
48
+ * Return the contents of a script that outputs JSON containing the version.
49
+ */
50
+ private fun mkbinVersion (version : String ):String {
51
+ return mkbin(echo(""" {"version": "$version "}""" ))
38
52
}
39
53
40
54
private fun mockServer (errorCode : Int = 0,version : String? = null):Pair <HttpServer ,URL > {
41
55
val srv= HttpServer .create(InetSocketAddress (0 ),0 )
42
56
srv.createContext(" /" ) {exchange->
43
57
var code= HttpURLConnection .HTTP_OK
44
- // TODO: Is there some simple way to create an executable file on
45
- // Windows without having to execute something to generate said
46
- // executable or having to commit one to the repo?
47
- var response= mkbin(version? : " ${srv.address.port} .0.0" )
58
+ var response= mkbinVersion(version? : " ${srv.address.port} .0.0" )
48
59
val eTags= exchange.requestHeaders[" If-None-Match" ]
49
60
if (exchange.requestURI.path== " /bin/override" ) {
50
61
code= HttpURLConnection .HTTP_OK
51
- response= mkbin (" 0.0.0" )
62
+ response= mkbinVersion (" 0.0.0" )
52
63
}else if (! exchange.requestURI.path.startsWith(" /bin/coder-" )) {
53
64
code= HttpURLConnection .HTTP_NOT_FOUND
54
65
response= " not found"
@@ -159,22 +170,15 @@ internal class CoderCLIManagerTest {
159
170
160
171
assertEquals(true , ccm.download())
161
172
162
- // The mock does not serve a binary that works on Windows so do not
163
- // actually execute. Checking the contents works just as well as proof
164
- // that the binary was correctly downloaded anyway.
165
- assertContains(ccm.localBinaryPath.toFile().readText(), url.port.toString())
166
- if (getOS()!= OS .WINDOWS ) {
167
- assertEquals(SemVer (url.port.toLong(),0 ,0 ), ccm.version())
168
- }
173
+ assertEquals(SemVer (url.port.toLong(),0 ,0 ), ccm.version())
169
174
170
175
// It should skip the second attempt.
171
176
assertEquals(false , ccm.download())
172
177
173
178
// Should use the source override.
174
179
ccm= CoderCLIManager (url,CoderSettings (CoderSettingsState (
175
180
binarySource= " /bin/override" ,
176
- dataDirectory= tmpdir.resolve(" mock-cli" ).toString()))
177
- )
181
+ dataDirectory= tmpdir.resolve(" mock-cli" ).toString())))
178
182
179
183
assertEquals(true , ccm.download())
180
184
assertContains(ccm.localBinaryPath.toFile().readText()," 0.0.0" )
@@ -354,32 +358,52 @@ internal class CoderCLIManagerTest {
354
358
}
355
359
}
356
360
357
- @Test
358
- fun testFailVersionParse () {
359
- if (getOS()== OS .WINDOWS ) {
360
- return // Cannot execute mock binaries on Windows.
361
+ /* *
362
+ * Return an echo command for the OS.
363
+ */
364
+ private fun echo (str : String ):String {
365
+ return if (getOS()== OS .WINDOWS ) {
366
+ " echo$str "
367
+ }else {
368
+ " echo '$str '"
361
369
}
370
+ }
362
371
372
+ /* *
373
+ * Return an exit command for the OS.
374
+ */
375
+ private fun exit (code : Number ):String {
376
+ return if (getOS()== OS .WINDOWS ) {
377
+ " exit /b$code "
378
+ }else {
379
+ " exit$code "
380
+ }
381
+ }
382
+
383
+ @Test
384
+ fun testFailVersionParse () {
363
385
val tests= mapOf (
364
- null toProcessInitException ::class ,
365
- """ echo ' {"foo": true, "baz": 1}' """ toMissingVersionException ::class ,
366
- """ echo ' {"version:' """ toJsonSyntaxException ::class ,
367
- """ echo ' {"version": "invalid"}' """ toInvalidVersionException ::class ,
368
- " exit 0 " toMissingVersionException ::class ,
369
- " exit 1 " toInvalidExitValueException ::class ,
386
+ null toProcessInitException ::class ,
387
+ echo( """ {"foo": true, "baz": 1}""" ) toMissingVersionException ::class ,
388
+ echo( """ {"version:""" ) toJsonSyntaxException ::class ,
389
+ echo( """ {"version": "invalid"}""" ) toInvalidVersionException ::class ,
390
+ exit( 0 ) toMissingVersionException ::class ,
391
+ exit( 1 ) toInvalidExitValueException ::class ,
370
392
)
371
393
372
394
val ccm= CoderCLIManager (URL (" https://test.coder.parse-fail.invalid" ),CoderSettings (CoderSettingsState (
373
- binaryDirectory= tmpdir.resolve(" bad-version" ).toString()))
374
- )
395
+ binaryDirectory= tmpdir.resolve(" bad-version" ).toString()),
396
+ binaryName = " coder.bat " ) )
375
397
ccm.localBinaryPath.parent.toFile().mkdirs()
376
398
377
399
tests.forEach {
378
400
if (it.key== null ) {
379
401
ccm.localBinaryPath.toFile().deleteRecursively()
380
402
}else {
381
- ccm.localBinaryPath.toFile().writeText(" #!/bin/sh\n ${it.key} " )
382
- ccm.localBinaryPath.toFile().setExecutable(true )
403
+ ccm.localBinaryPath.toFile().writeText(mkbin(it.key!! ))
404
+ if (getOS()!= OS .WINDOWS ) {
405
+ ccm.localBinaryPath.toFile().setExecutable(true )
406
+ }
383
407
}
384
408
assertFailsWith(
385
409
exceptionClass= it.value,
@@ -389,39 +413,37 @@ internal class CoderCLIManagerTest {
389
413
390
414
@Test
391
415
fun testMatchesVersion () {
392
- if (getOS()== OS .WINDOWS ) {
393
- return
394
- }
395
-
396
416
val test= listOf (
397
417
Triple (null ," v1.0.0" ,null ),
398
- Triple (""" echo ' {"version": "v1.0.0"}' """ ," v1.0.0" ,true ),
399
- Triple (""" echo ' {"version": "v1.0.0"}' """ ," v1.0.0-devel+b5b5b5b5" ,true ),
400
- Triple (""" echo ' {"version": "v1.0.0-devel+b5b5b5b5"}' """ ," v1.0.0-devel+b5b5b5b5" ,true ),
401
- Triple (""" echo ' {"version": "v1.0.0-devel+b5b5b5b5"}' """ ," v1.0.0" ,true ),
402
- Triple (""" echo ' {"version": "v1.0.0-devel+b5b5b5b5"}' """ ," v1.0.0-devel+c6c6c6c6" ,true ),
403
- Triple (""" echo ' {"version": "v1.0.0-prod+b5b5b5b5"}' """ ," v1.0.0-devel+b5b5b5b5" ,true ),
404
- Triple (""" echo ' {"version": "v1.0.0"}' """ ," v1.0.1" ,false ),
405
- Triple (""" echo ' {"version": "v1.0.0"}' """ ," v1.1.0" ,false ),
406
- Triple (""" echo ' {"version": "v1.0.0"}' """ ," v2.0.0" ,false ),
407
- Triple (""" echo ' {"version": "v1.0.0"}' """ ," v0.0.0" ,false ),
408
- Triple (""" echo ' {"version": ""}' """ ," v1.0.0" ,null ),
409
- Triple (""" echo ' {"version": "v1.0.0"}' """ ," " ,null ),
410
- Triple (""" echo ' {"version' """ ," v1.0.0" ,null ),
411
- Triple (""" exit 0 """ ," v1.0.0" ,null ),
412
- Triple (""" exit 1 """ ," v1.0.0" ,null ))
418
+ Triple (echo( """ {"version": "v1.0.0"}""" ) ," v1.0.0" ,true ),
419
+ Triple (echo( """ {"version": "v1.0.0"}""" ) ," v1.0.0-devel+b5b5b5b5" ,true ),
420
+ Triple (echo( """ {"version": "v1.0.0-devel+b5b5b5b5"}""" ) ," v1.0.0-devel+b5b5b5b5" ,true ),
421
+ Triple (echo( """ {"version": "v1.0.0-devel+b5b5b5b5"}""" ) ," v1.0.0" ,true ),
422
+ Triple (echo( """ {"version": "v1.0.0-devel+b5b5b5b5"}""" ) ," v1.0.0-devel+c6c6c6c6" ,true ),
423
+ Triple (echo( """ {"version": "v1.0.0-prod+b5b5b5b5"}""" ) ," v1.0.0-devel+b5b5b5b5" ,true ),
424
+ Triple (echo( """ {"version": "v1.0.0"}""" ) ," v1.0.1" ,false ),
425
+ Triple (echo( """ {"version": "v1.0.0"}""" ) ," v1.1.0" ,false ),
426
+ Triple (echo( """ {"version": "v1.0.0"}""" ) ," v2.0.0" ,false ),
427
+ Triple (echo( """ {"version": "v1.0.0"}""" ) ," v0.0.0" ,false ),
428
+ Triple (echo( """ {"version": ""}""" ) ," v1.0.0" ,null ),
429
+ Triple (echo( """ {"version": "v1.0.0"}""" ) ," " ,null ),
430
+ Triple (echo( """ {"version""" ) ," v1.0.0" ,null ),
431
+ Triple (exit( 0 ) ," v1.0.0" ,null ),
432
+ Triple (exit( 1 ) ," v1.0.0" ,null ))
413
433
414
434
val ccm= CoderCLIManager (URL (" https://test.coder.matches-version.invalid" ),CoderSettings (CoderSettingsState (
415
- binaryDirectory= tmpdir.resolve(" matches-version" ).toString()))
416
- )
435
+ binaryDirectory= tmpdir.resolve(" matches-version" ).toString()),
436
+ binaryName = " coder.bat " ) )
417
437
ccm.localBinaryPath.parent.toFile().mkdirs()
418
438
419
439
test.forEach {
420
440
if (it.first== null ) {
421
441
ccm.localBinaryPath.toFile().deleteRecursively()
422
442
}else {
423
- ccm.localBinaryPath.toFile().writeText(" #!/bin/sh\n ${it.first} " )
424
- ccm.localBinaryPath.toFile().setExecutable(true )
443
+ ccm.localBinaryPath.toFile().writeText(mkbin(it.first!! ))
444
+ if (getOS()!= OS .WINDOWS ) {
445
+ ccm.localBinaryPath.toFile().setExecutable(true )
446
+ }
425
447
}
426
448
427
449
assertEquals(it.third, ccm.matchesVersion(it.second), it.first)
@@ -446,7 +468,9 @@ internal class CoderCLIManagerTest {
446
468
@Test
447
469
fun testEnsureCLI () {
448
470
if (getOS()== OS .WINDOWS ) {
449
- return // Cannot execute mock binaries on Windows and setWritable() works differently.
471
+ // TODO: setWritable() does not work the same way on Windows but we
472
+ // should test what we can.
473
+ return
450
474
}
451
475
452
476
val tests= listOf (
@@ -490,7 +514,7 @@ internal class CoderCLIManagerTest {
490
514
// Create a binary in the regular location.
491
515
if (it.version!= null ) {
492
516
settings.binPath(url).parent.toFile().mkdirs()
493
- settings.binPath(url).toFile().writeText(mkbin (it.version))
517
+ settings.binPath(url).toFile().writeText(mkbinVersion (it.version))
494
518
settings.binPath(url).toFile().setExecutable(true )
495
519
}
496
520
@@ -503,7 +527,7 @@ internal class CoderCLIManagerTest {
503
527
// Create a binary in the fallback location.
504
528
if (it.fallbackVersion!= null ) {
505
529
settings.binPath(url,true ).parent.toFile().mkdirs()
506
- settings.binPath(url,true ).toFile().writeText(mkbin (it.fallbackVersion))
530
+ settings.binPath(url,true ).toFile().writeText(mkbinVersion (it.fallbackVersion))
507
531
settings.binPath(url,true ).toFile().setExecutable(true )
508
532
}
509
533
@@ -553,10 +577,6 @@ internal class CoderCLIManagerTest {
553
577
554
578
@Test
555
579
fun testFeatures () {
556
- if (getOS()== OS .WINDOWS ) {
557
- return // Cannot execute mock binaries on Windows.
558
- }
559
-
560
580
val tests= listOf (
561
581
Pair (" 2.5.0" ,Features (true )),
562
582
Pair (" 4.9.0" ,Features (true )),
@@ -567,8 +587,8 @@ internal class CoderCLIManagerTest {
567
587
tests.forEach {
568
588
val (srv, url)= mockServer(version= it.first)
569
589
val ccm= CoderCLIManager (url,CoderSettings (CoderSettingsState (
570
- dataDirectory= tmpdir.resolve(" features" ).toString()))
571
- )
590
+ dataDirectory= tmpdir.resolve(" features" ).toString()),
591
+ binaryName = " coder.bat " ) )
572
592
assertEquals(true , ccm.download())
573
593
assertEquals(it.second, ccm.features," version:${it.first} " )
574
594