Skip to content

Commit c7af603

Browse files
committed
chore: fix UTs related to CLI downloading
For one thing some method signature changed, some methods are now suspending functions that will have to run in a coroutine in the tests. The second big issue is that now the download function requests user's input via a dialog
1 parent 345371f commit c7af603

File tree

2 files changed

+94
-28
lines changed

2 files changed

+94
-28
lines changed

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ dependencies {
5656
testImplementation(kotlin("test"))
5757
// required by the unit tests
5858
testImplementation(kotlin("test-junit5"))
59+
testImplementation("io.mockk:mockk:1.13.12")
5960
// required by IntelliJ test framework
6061
testImplementation("junit:junit:4.13.2")
6162

src/test/kotlin/com/coder/gateway/cli/CoderCLIManagerTest.kt

Lines changed: 93 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import com.coder.gateway.settings.CODER_SSH_CONFIG_OPTIONS
1010
import com.coder.gateway.settings.CoderSettings
1111
import com.coder.gateway.settings.CoderSettingsState
1212
import com.coder.gateway.settings.Environment
13+
import com.coder.gateway.util.DialogUi
1314
import com.coder.gateway.util.InvalidVersionException
1415
import com.coder.gateway.util.OS
1516
import com.coder.gateway.util.SemVer
@@ -19,6 +20,9 @@ import com.coder.gateway.util.sha1
1920
import com.coder.gateway.util.toURL
2021
import com.squareup.moshi.JsonEncodingException
2122
import com.sun.net.httpserver.HttpServer
23+
import io.mockk.every
24+
import io.mockk.mockkConstructor
25+
import kotlinx.coroutines.runBlocking
2226
import org.junit.jupiter.api.BeforeAll
2327
import org.junit.jupiter.api.assertDoesNotThrow
2428
import org.zeroturnaround.exec.InvalidExitValueException
@@ -28,7 +32,8 @@ import java.net.InetSocketAddress
2832
import java.net.URL
2933
import java.nio.file.AccessDeniedException
3034
import java.nio.file.Path
31-
import java.util.*
35+
import java.util.UUID
36+
import kotlin.test.BeforeTest
3237
import kotlin.test.Test
3338
import kotlin.test.assertContains
3439
import kotlin.test.assertEquals
@@ -37,6 +42,9 @@ import kotlin.test.assertFalse
3742
import kotlin.test.assertNotEquals
3843
import kotlin.test.assertTrue
3944

45+
private const val VERSION_FOR_PROGRESS_REPORTING = "v2.13.1-devel+de07351b8"
46+
private val noOpTextProgress: (String) -> Unit = { _ -> }
47+
4048
internal class CoderCLIManagerTest {
4149
/**
4250
* Return the contents of a script that contains the string.
@@ -65,6 +73,9 @@ internal class CoderCLIManagerTest {
6573
if (exchange.requestURI.path == "/bin/override") {
6674
code = HttpURLConnection.HTTP_OK
6775
response = mkbinVersion("0.0.0")
76+
} else if (exchange.requestURI.path.contains(".asc")) {
77+
code = HttpURLConnection.HTTP_NOT_FOUND
78+
response = "not found"
6879
} else if (!exchange.requestURI.path.startsWith("/bin/coder-")) {
6980
code = HttpURLConnection.HTTP_NOT_FOUND
7081
response = "not found"
@@ -85,6 +96,13 @@ internal class CoderCLIManagerTest {
8596
return Pair(srv, URL("http://localhost:" + srv.address.port))
8697
}
8798

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+
88106
@Test
89107
fun testServerInternalError() {
90108
val (srv, url) = mockServer(HttpURLConnection.HTTP_INTERNAL_ERROR)
@@ -93,7 +111,7 @@ internal class CoderCLIManagerTest {
93111
val ex =
94112
assertFailsWith(
95113
exceptionClass = ResponseException::class,
96-
block = { ccm.download() },
114+
block = { runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING, noOpTextProgress) } }
97115
)
98116
assertEquals(HttpURLConnection.HTTP_INTERNAL_ERROR, ex.code)
99117

@@ -145,7 +163,7 @@ internal class CoderCLIManagerTest {
145163

146164
assertFailsWith(
147165
exceptionClass = AccessDeniedException::class,
148-
block = { ccm.download() },
166+
block = { runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING, noOpTextProgress) } },
149167
)
150168

151169
srv.stop(0)
@@ -168,15 +186,16 @@ internal class CoderCLIManagerTest {
168186
CoderSettings(
169187
CoderSettingsState(
170188
dataDirectory = tmpdir.resolve("real-cli").toString(),
189+
fallbackOnCoderForSignatures = true
171190
),
172191
),
173192
)
174193

175-
assertTrue(ccm.download())
194+
assertTrue(runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING, noOpTextProgress) })
176195
assertDoesNotThrow { ccm.version() }
177196

178197
// It should skip the second attempt.
179-
assertFalse(ccm.download())
198+
assertFalse(runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING, noOpTextProgress) })
180199

181200
// Make sure login failures propagate.
182201
assertFailsWith(
@@ -194,16 +213,17 @@ internal class CoderCLIManagerTest {
194213
CoderSettings(
195214
CoderSettingsState(
196215
dataDirectory = tmpdir.resolve("mock-cli").toString(),
216+
fallbackOnCoderForSignatures = true
197217
),
198218
binaryName = "coder.bat",
199219
),
200220
)
201221

202-
assertEquals(true, ccm.download())
222+
assertEquals(true, runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING, noOpTextProgress) })
203223
assertEquals(SemVer(url.port.toLong(), 0, 0), ccm.version())
204224

205225
// It should skip the second attempt.
206-
assertEquals(false, ccm.download())
226+
assertEquals(false, runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING, noOpTextProgress) })
207227

208228
// Should use the source override.
209229
ccm =
@@ -213,11 +233,12 @@ internal class CoderCLIManagerTest {
213233
CoderSettingsState(
214234
binarySource = "/bin/override",
215235
dataDirectory = tmpdir.resolve("mock-cli").toString(),
236+
fallbackOnCoderForSignatures = true
216237
),
217238
),
218239
)
219240

220-
assertEquals(true, ccm.download())
241+
assertEquals(true, runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING, noOpTextProgress) })
221242
assertContains(ccm.localBinaryPath.toFile().readText(), "0.0.0")
222243

223244
srv.stop(0)
@@ -242,14 +263,15 @@ internal class CoderCLIManagerTest {
242263
}
243264

244265
@Test
245-
fun testOverwitesWrongVersion() {
266+
fun testOverwritesWrongVersion() {
246267
val (srv, url) = mockServer()
247268
val ccm =
248269
CoderCLIManager(
249270
url,
250271
CoderSettings(
251272
CoderSettingsState(
252273
dataDirectory = tmpdir.resolve("overwrite-cli").toString(),
274+
fallbackOnCoderForSignatures = true
253275
),
254276
),
255277
)
@@ -261,7 +283,7 @@ internal class CoderCLIManagerTest {
261283
assertEquals("cli", ccm.localBinaryPath.toFile().readText())
262284
assertEquals(0, ccm.localBinaryPath.toFile().lastModified())
263285

264-
assertTrue(ccm.download())
286+
assertTrue(runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING, noOpTextProgress) })
265287

266288
assertNotEquals("cli", ccm.localBinaryPath.toFile().readText())
267289
assertNotEquals(0, ccm.localBinaryPath.toFile().lastModified())
@@ -279,14 +301,15 @@ internal class CoderCLIManagerTest {
279301
CoderSettings(
280302
CoderSettingsState(
281303
dataDirectory = tmpdir.resolve("clobber-cli").toString(),
304+
fallbackOnCoderForSignatures = true
282305
),
283306
)
284307

285308
val ccm1 = CoderCLIManager(url1, settings)
286309
val ccm2 = CoderCLIManager(url2, settings)
287310

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) })
290313

291314
srv1.stop(0)
292315
srv2.stop(0)
@@ -314,8 +337,12 @@ internal class CoderCLIManagerTest {
314337
fun testConfigureSSH() {
315338
val workspace = workspace("foo", agents = mapOf("agent1" to UUID.randomUUID().toString()))
316339
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+
)
319346

320347
val extraConfig =
321348
listOf(
@@ -331,7 +358,12 @@ internal class CoderCLIManagerTest {
331358
SSHTest(listOf(workspace), "existing-end", "replace-end", "no-blocks"),
332359
SSHTest(listOf(workspace), "existing-end-no-newline", "replace-end-no-newline", "no-blocks"),
333360
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+
),
335367
SSHTest(listOf(workspace), "existing-only", "replace-only", "blank"),
336368
SSHTest(listOf(workspace), "existing-start", "replace-start", "no-blocks"),
337369
SSHTest(listOf(workspace), "no-blocks", "append-no-blocks", "no-blocks"),
@@ -463,7 +495,10 @@ internal class CoderCLIManagerTest {
463495
Path.of("src/test/fixtures/outputs/").resolve(it.output + ".conf").toFile().readText()
464496
.replace(newlineRe, System.lineSeparator())
465497
.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+
)
467502
.let { conf ->
468503
if (it.sshLogDirectory != null) {
469504
conf.replace("/tmp/coder-gateway/test.coder.invalid/logs", it.sshLogDirectory.toString())
@@ -476,7 +511,10 @@ internal class CoderCLIManagerTest {
476511
Path.of("src/test/fixtures/inputs/").resolve(it.remove + ".conf").toFile().readText()
477512
.replace(newlineRe, System.lineSeparator())
478513
.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+
)
480518
.let { conf ->
481519
if (it.sshLogDirectory != null) {
482520
conf.replace("/tmp/coder-gateway/test.coder.invalid/logs", it.sshLogDirectory.toString())
@@ -552,7 +590,10 @@ internal class CoderCLIManagerTest {
552590
"new\nline",
553591
)
554592

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+
)
556597
val withAgents = workspace.latestBuild.resources.filter { it.agents != null }.flatMap { it.agents!! }.map {
557598
workspace to it
558599
}
@@ -730,8 +771,24 @@ internal class CoderCLIManagerTest {
730771
EnsureCLITest(null, null, "1.0.0", false, true, true, Result.DL_DATA), // Download to fallback.
731772
EnsureCLITest(null, null, "1.0.0", false, false, true, Result.NONE), // No download, error when used.
732773
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.
735792
EnsureCLITest("1.0.0", null, "1.0.0", false, false, true, Result.USE_BIN), // Use existing.
736793
EnsureCLITest("1.0.1", "1.0.0", "1.0.0", false, false, true, Result.USE_DATA), // Use existing fallback.
737794
)
@@ -746,6 +803,7 @@ internal class CoderCLIManagerTest {
746803
enableBinaryDirectoryFallback = it.enableFallback,
747804
dataDirectory = tmpdir.resolve("ensure-data-dir").toString(),
748805
binaryDirectory = tmpdir.resolve("ensure-bin-dir").toString(),
806+
fallbackOnCoderForSignatures = true
749807
),
750808
)
751809

@@ -777,34 +835,39 @@ internal class CoderCLIManagerTest {
777835
Result.ERROR -> {
778836
assertFailsWith(
779837
exceptionClass = AccessDeniedException::class,
780-
block = { ensureCLI(url, it.buildVersion, settings) },
838+
block = { runBlocking { ensureCLI(url, it.buildVersion, settings, noOpTextProgress) } }
781839
)
782840
}
841+
783842
Result.NONE -> {
784-
val ccm = ensureCLI(url, it.buildVersion, settings)
843+
val ccm = runBlocking { ensureCLI(url, it.buildVersion, settings, noOpTextProgress) }
785844
assertEquals(settings.binPath(url), ccm.localBinaryPath)
786845
assertFailsWith(
787846
exceptionClass = ProcessInitException::class,
788847
block = { ccm.version() },
789848
)
790849
}
850+
791851
Result.DL_BIN -> {
792-
val ccm = ensureCLI(url, it.buildVersion, settings)
852+
val ccm = runBlocking { ensureCLI(url, it.buildVersion, settings, noOpTextProgress) }
793853
assertEquals(settings.binPath(url), ccm.localBinaryPath)
794854
assertEquals(SemVer(url.port.toLong(), 0, 0), ccm.version())
795855
}
856+
796857
Result.DL_DATA -> {
797-
val ccm = ensureCLI(url, it.buildVersion, settings)
858+
val ccm = runBlocking { ensureCLI(url, it.buildVersion, settings, noOpTextProgress) }
798859
assertEquals(settings.binPath(url, true), ccm.localBinaryPath)
799860
assertEquals(SemVer(url.port.toLong(), 0, 0), ccm.version())
800861
}
862+
801863
Result.USE_BIN -> {
802-
val ccm = ensureCLI(url, it.buildVersion, settings)
864+
val ccm = runBlocking { ensureCLI(url, it.buildVersion, settings, noOpTextProgress) }
803865
assertEquals(settings.binPath(url), ccm.localBinaryPath)
804866
assertEquals(SemVer.parse(it.version ?: ""), ccm.version())
805867
}
868+
806869
Result.USE_DATA -> {
807-
val ccm = ensureCLI(url, it.buildVersion, settings)
870+
val ccm = runBlocking { ensureCLI(url, it.buildVersion, settings, noOpTextProgress) }
808871
assertEquals(settings.binPath(url, true), ccm.localBinaryPath)
809872
assertEquals(SemVer.parse(it.fallbackVersion ?: ""), ccm.version())
810873
}
@@ -838,19 +901,21 @@ internal class CoderCLIManagerTest {
838901
CoderSettings(
839902
CoderSettingsState(
840903
dataDirectory = tmpdir.resolve("features").toString(),
904+
fallbackOnCoderForSignatures = true
841905
),
842906
binaryName = "coder.bat",
843907
),
844908
)
845-
assertEquals(true, ccm.download())
909+
assertEquals(true, runBlocking { ccm.download(VERSION_FOR_PROGRESS_REPORTING, noOpTextProgress) })
846910
assertEquals(it.second, ccm.features, "version: ${it.first}")
847911

848912
srv.stop(0)
849913
}
850914
}
851915

852916
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")
854919

855920
@JvmStatic
856921
@BeforeAll

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy