diff --git a/src/main/bash/sdkman-init.sh b/src/main/bash/sdkman-init.sh
index 131aa704..4b67ffeb 100644
--- a/src/main/bash/sdkman-init.sh
+++ b/src/main/bash/sdkman-init.sh
@@ -98,25 +98,6 @@ fi
if [[ -z "$sdkman_curl_connect_timeout" ]]; then sdkman_curl_connect_timeout=7; fi
if [[ -z "$sdkman_curl_max_time" ]]; then sdkman_curl_max_time=10; fi
-# fabricate list of candidates
-SDKMAN_CANDIDATES_CACHE="${SDKMAN_DIR}/var/candidates"
-if [[ -f "$SDKMAN_CANDIDATES_CACHE" && -n "$(cat "$SDKMAN_CANDIDATES_CACHE")" && -z "$(find "$SDKMAN_CANDIDATES_CACHE" -mmin +$((60*24)))" ]]; then
- __sdkman_echo_debug "Using existing candidates cache: $SDKMAN_CANDIDATES_CACHE"
-else
- CANDIDATES_URI="${SDKMAN_CURRENT_API}/candidates/all"
- __sdkman_echo_debug "Using candidates endpoint: $CANDIDATES_URI"
- SDKMAN_FRESH_CANDIDATES_CSV=$(__sdkman_secure_curl_with_timeouts "$CANDIDATES_URI")
- __sdkman_echo_debug "Fetched candidates csv: $SDKMAN_FRESH_CANDIDATES_CSV"
- DETECT_HTML="$(echo "$SDKMAN_FRESH_CANDIDATES_CSV" | tr '[:upper:]' '[:lower:]' | grep 'html')"
- if [[ -n "$SDKMAN_FRESH_CANDIDATES_CSV" && -z "$DETECT_HTML" ]]; then
- __sdkman_echo_debug "Overwriting candidates cache with: $SDKMAN_FRESH_CANDIDATES_CSV"
- echo "$SDKMAN_FRESH_CANDIDATES_CSV" > "$SDKMAN_CANDIDATES_CACHE"
- fi
- unset CANDIDATES_URI SDKMAN_FRESH_CANDIDATES_CSV DETECT_HTML
-fi
-
-SDKMAN_CANDIDATES_CSV=$(cat "$SDKMAN_CANDIDATES_CACHE")
-
# determine if up to date
SDKMAN_VERSION_FILE="${SDKMAN_DIR}/var/version"
if [[ "$sdkman_beta_channel" != "true" && -f "$SDKMAN_VERSION_FILE" && -z "$(find "$SDKMAN_VERSION_FILE" -mmin +$((60*24)))" ]]; then
@@ -144,7 +125,10 @@ else
fi
fi
-# Set the candidate array
+# Read list of candidates and set array
+SDKMAN_CANDIDATES_CACHE="${SDKMAN_DIR}/var/candidates"
+SDKMAN_CANDIDATES_CSV=$(cat "$SDKMAN_CANDIDATES_CACHE")
+__sdkman_echo_debug "Setting candidates csv: $SDKMAN_CANDIDATES_CSV"
if [[ "$zsh_shell" == 'true' ]]; then
SDKMAN_CANDIDATES=( ${(s:,:)SDKMAN_CANDIDATES_CSV} )
else
diff --git a/src/main/bash/sdkman-main.sh b/src/main/bash/sdkman-main.sh
index 1b131fdb..452ad94a 100644
--- a/src/main/bash/sdkman-main.sh
+++ b/src/main/bash/sdkman-main.sh
@@ -53,7 +53,9 @@ function sdk {
#
# Various sanity checks and default settings
#
- mkdir -p "$SDKMAN_DIR"
+
+ # Check candidates cache
+ ___sdkman_check_candidates_cache "$SDKMAN_CANDIDATES_CACHE" || return 1
# Always presume internet availability
SDKMAN_AVAILABLE="true"
diff --git a/src/test/cucumber/upgrade_candidate.feature b/src/test/cucumber/upgrade_candidate.feature
index 1d85bfc5..0ad61993 100644
--- a/src/test/cucumber/upgrade_candidate.feature
+++ b/src/test/cucumber/upgrade_candidate.feature
@@ -2,6 +2,7 @@ Feature: Upgrade Candidate
Background:
Given the internet is reachable
+ And the candidates cache is initialised with "grails"
And an initialised environment
Scenario: Display upgradable candidate version in use when it is upgradable
diff --git a/src/test/groovy/sdkman/specs/BetaChannelBootstrapSpec.groovy b/src/test/groovy/sdkman/specs/BetaChannelBootstrapSpec.groovy
index 9637b18b..e7c05793 100644
--- a/src/test/groovy/sdkman/specs/BetaChannelBootstrapSpec.groovy
+++ b/src/test/groovy/sdkman/specs/BetaChannelBootstrapSpec.groovy
@@ -13,7 +13,7 @@ class BetaChannelBootstrapSpec extends SdkmanEnvSpecification {
def setup() {
versionCache = new File("${sdkmanDotDirectory}/var", "version")
- sdkmanBashEnvBuilder.withCandidatesCache(["groovy"])
+ sdkmanBashEnvBuilder.withCandidates(["groovy"])
}
void "should attempt immediate upgrade of stable to beta version if beta channel is first enabled"() {
diff --git a/src/test/groovy/sdkman/specs/CandidatesCacheBootstrapSpec.groovy b/src/test/groovy/sdkman/specs/CandidatesCacheBootstrapSpec.groovy
deleted file mode 100644
index 4f1f3a6c..00000000
--- a/src/test/groovy/sdkman/specs/CandidatesCacheBootstrapSpec.groovy
+++ /dev/null
@@ -1,176 +0,0 @@
-package sdkman.specs
-
-import sdkman.support.SdkmanEnvSpecification
-
-import static java.lang.System.currentTimeMillis
-
-class CandidatesCacheBootstrapSpec extends SdkmanEnvSpecification {
-
- static final MORE_THAN_A_DAY_IN_MILLIS = 24 * 61 * 60 * 1000
-
- static final LEGACY_API = "http://localhost:8080/1"
- static final LEGACY_VERSIONS_STABLE_ENDPOINT = "$LEGACY_API/candidates/app/stable"
- static final LEGACY_VERSIONS_BETA_ENDPOINT = "$LEGACY_API/candidates/app/beta"
-
- static final CURRENT_API = "http://localhost:8080/2"
- static final CURRENT_CANDIDATES_ENDPOINT = "$CURRENT_API/candidates/all"
-
- File candidatesCache
-
- def setup() {
- candidatesCache = new File("${sdkmanDotDirectory}/var", "candidates")
- curlStub.primeWith(LEGACY_VERSIONS_STABLE_ENDPOINT, "echo x.y.y")
- .primeWith(LEGACY_VERSIONS_BETA_ENDPOINT, "echo x.y.z")
- sdkmanBashEnvBuilder.withConfiguration("sdkman_debug_mode", "true")
- }
-
- void "should not query server if unexpired candidates cache is found"() {
- given:
- bash = sdkmanBashEnvBuilder
- .withCandidatesCache(['gradle', 'sbt'])
- .build()
-
- and:
- bash.start()
-
- when:
- bash.execute("source $bootstrapScript")
- bash.execute('echo $SDKMAN_CANDIDATES_CSV')
-
- then:
- candidatesCache.exists()
- candidatesCache.text.contains("gradle,sbt")
-
- and:
- bash.output.contains "gradle,sbt"
- }
-
- void "should fetch and store candidates in cache if cache is empty"() {
- given:
- curlStub.primeWith(CURRENT_CANDIDATES_ENDPOINT, "echo groovy,scala")
- bash = sdkmanBashEnvBuilder
- .withCandidatesCache([])
- .withLegacyService(LEGACY_API)
- .build()
-
- and:
- bash.start()
-
- when:
- bash.execute("source $bootstrapScript")
- bash.execute('echo $SDKMAN_CANDIDATES_CSV')
-
- then:
- candidatesCache.exists()
- candidatesCache.text.contains("groovy,scala")
-
- and:
- bash.output.contains("groovy,scala")
- }
-
- void "should fetch candidates and refresh cache if older than a day"() {
- given:
- curlStub.primeWith(CURRENT_CANDIDATES_ENDPOINT, "echo groovy,scala")
- bash = sdkmanBashEnvBuilder
- .withLegacyService(LEGACY_API)
- .withCandidatesCache(['groovy'])
- .build()
-
- and:
- candidatesCache.setLastModified(currentTimeMillis() - MORE_THAN_A_DAY_IN_MILLIS)
-
- and:
- bash.start()
-
- when:
- bash.execute("source $bootstrapScript")
- bash.execute('echo $SDKMAN_CANDIDATES_CSV')
-
- then:
- candidatesCache.exists()
- candidatesCache.text.contains('groovy,scala')
-
- and:
- bash.output.contains("groovy,scala")
- }
-
- void "should ignore candidates if api is offline"() {
- given:
- def candidates = ['groovy', 'scala']
- curlStub.primeWith(CURRENT_CANDIDATES_ENDPOINT, "echo ''")
- bash = sdkmanBashEnvBuilder
- .withLegacyService(LEGACY_API)
- .withCandidatesCache(candidates)
- .build()
-
- and:
- candidatesCache.setLastModified(currentTimeMillis() - MORE_THAN_A_DAY_IN_MILLIS)
-
- and:
- bash.start()
-
- when:
- bash.execute("source $bootstrapScript")
- bash.execute('echo $SDKMAN_CANDIDATES_CSV')
-
- then:
- candidatesCache.text.contains('groovy,scala')
-
- and:
- bash.output.contains("groovy,scala")
- }
-
- void "should ignore candidates if api returns garbage"() {
- given:
- def candidates = ['groovy', 'scala']
- curlStub.primeWith(CURRENT_CANDIDATES_ENDPOINT, "echo '
sorry'")
- bash = sdkmanBashEnvBuilder
- .withLegacyService(LEGACY_API)
- .withCandidatesCache(candidates)
- .build()
-
- and:
- candidatesCache.setLastModified(currentTimeMillis() - MORE_THAN_A_DAY_IN_MILLIS)
-
- and:
- bash.start()
-
- when:
- bash.execute("source $bootstrapScript")
- bash.execute('echo $SDKMAN_CANDIDATES_CSV')
-
- then:
- candidatesCache.text.contains('groovy,scala')
-
- and:
- bash.output.contains("groovy,scala")
- }
-
- void "should query api if not subscribed to beta channel"() {
- given:
- curlStub.primeWith(CURRENT_CANDIDATES_ENDPOINT, "echo groovy,scala")
- bash = sdkmanBashEnvBuilder
- .withLegacyService(LEGACY_API)
- .withCurrentService(CURRENT_API)
- .withConfiguration("sdkman_beta_channel", "false")
- .withCandidatesCache(['groovy'])
- .build()
-
- and:
- candidatesCache.setLastModified(currentTimeMillis() - MORE_THAN_A_DAY_IN_MILLIS)
-
- and:
- bash.start()
-
- when:
- bash.execute("source $bootstrapScript")
- bash.execute('echo $SDKMAN_CANDIDATES_CSV')
-
- then:
- candidatesCache.exists()
- candidatesCache.text.contains('groovy,scala')
-
- and:
- bash.output.contains("groovy,scala")
- }
-}
diff --git a/src/test/groovy/sdkman/specs/CandidatesCacheUpdateSpec.groovy b/src/test/groovy/sdkman/specs/CandidatesCacheUpdateSpec.groovy
new file mode 100644
index 00000000..1bba5277
--- /dev/null
+++ b/src/test/groovy/sdkman/specs/CandidatesCacheUpdateSpec.groovy
@@ -0,0 +1,91 @@
+package sdkman.specs
+
+import sdkman.support.SdkmanEnvSpecification
+
+class CandidatesCacheUpdateSpec extends SdkmanEnvSpecification {
+
+ static final LEGACY_API = "http://localhost:8080/1"
+ static final LEGACY_VERSIONS_STABLE_ENDPOINT = "$LEGACY_API/candidates/app/stable"
+ static final LEGACY_VERSIONS_BETA_ENDPOINT = "$LEGACY_API/candidates/app/beta"
+
+ static final CURRENT_API = "http://localhost:8080/2"
+ static final BROADCAST_API_LATEST_ID_ENDPOINT = "$CURRENT_API/broadcast/latest/id"
+
+ File candidatesCache
+
+ def setup() {
+ candidatesCache = new File("${sdkmanDotDirectory}/var", "candidates")
+ curlStub.primeWith(LEGACY_VERSIONS_STABLE_ENDPOINT, "echo x.y.y")
+ .primeWith(LEGACY_VERSIONS_BETA_ENDPOINT, "echo x.y.z")
+ .primeWith(BROADCAST_API_LATEST_ID_ENDPOINT, "echo dbfb025be9f97fda2052b5febcca0155")
+ sdkmanBashEnvBuilder.withConfiguration("sdkman_debug_mode", "true")
+ }
+
+ void "should issue a warning if cache is empty"() {
+ given:
+ bash = sdkmanBashEnvBuilder
+ .withCandidates([])
+ .withLegacyService(LEGACY_API)
+ .build()
+
+ and:
+ bash.start()
+
+ when:
+ bash.execute("source $bootstrapScript")
+ bash.execute("sdk version")
+
+ then:
+ bash.output.contains('Warning! Cache is corrupt. SDKMAN can not be used until updated.')
+ bash.output.contains('$ sdk update')
+
+ and:
+ !bash.output.contains("SDKMAN 5.0.0")
+ }
+
+ void "should issue a warning if cache is older than a month"() {
+ given:
+ bash = sdkmanBashEnvBuilder
+ .withLegacyService(LEGACY_API)
+ .withCandidates(['groovy'])
+ .build()
+
+ and:
+ candidatesCache.setLastModified(((new Date() - 31) as Date).time)
+
+ and:
+ bash.start()
+
+ when:
+ bash.execute("source $bootstrapScript")
+ bash.execute("sdk version")
+
+ then:
+ bash.output.contains('Warning! SDKMAN out-of-date and requires an update.')
+ bash.output.contains('$ sdk update')
+
+ and:
+ bash.output.contains('SDKMAN 5.0.0')
+ }
+
+ void "should log a success message in debug mode when no update needed"() {
+ given:
+ bash = sdkmanBashEnvBuilder
+ .withLegacyService(LEGACY_API)
+ .withCandidates(['groovy'])
+ .build()
+
+ and:
+ bash.start()
+
+ when:
+ bash.execute("source $bootstrapScript")
+ bash.execute("sdk version")
+
+ then:
+ bash.output.contains('No update needed. Using existing candidates cache')
+
+ and:
+ bash.output.contains('SDKMAN 5.0.0')
+ }
+}
diff --git a/src/test/groovy/sdkman/specs/CurrentCommandSpec.groovy b/src/test/groovy/sdkman/specs/CurrentCommandSpec.groovy
index e8612481..b701da64 100644
--- a/src/test/groovy/sdkman/specs/CurrentCommandSpec.groovy
+++ b/src/test/groovy/sdkman/specs/CurrentCommandSpec.groovy
@@ -8,6 +8,13 @@ import static java.nio.file.Files.createSymbolicLink
class CurrentCommandSpec extends SdkmanEnvSpecification {
+ static final CURRENT_API = "http://localhost:8080/2"
+ static final BROADCAST_API_LATEST_ID_ENDPOINT = "$CURRENT_API/broadcast/latest/id"
+
+ def setup() {
+ curlStub.primeWith(BROADCAST_API_LATEST_ID_ENDPOINT, "echo dbfb025be9f97fda2052b5febcca0155")
+ }
+
void "should display current version of all candidates installed"() {
given:
def installedCandidates = [
@@ -34,7 +41,7 @@ class CurrentCommandSpec extends SdkmanEnvSpecification {
bash = sdkmanBashEnvBuilder
.withOfflineMode(false)
- .withCandidatesCache(allCandidates)
+ .withVersionCache("5.0.0")
.withCandidates(installedCandidates.keySet().toList())
.build()
diff --git a/src/test/groovy/sdkman/specs/InitialisationSpec.groovy b/src/test/groovy/sdkman/specs/InitialisationSpec.groovy
index b71a4e8b..1f006902 100644
--- a/src/test/groovy/sdkman/specs/InitialisationSpec.groovy
+++ b/src/test/groovy/sdkman/specs/InitialisationSpec.groovy
@@ -12,7 +12,6 @@ class InitialisationSpec extends SdkmanEnvSpecification {
def setup() {
bash = sdkmanBashEnvBuilder
- .withCandidatesCache(allCandidates)
.withCandidates(allCandidates)
.withVersionCache("x.y.z")
.build()
diff --git a/src/test/groovy/sdkman/specs/SdkCompatibilitySpec.groovy b/src/test/groovy/sdkman/specs/SdkCompatibilitySpec.groovy
index 53fd42dc..86340f17 100644
--- a/src/test/groovy/sdkman/specs/SdkCompatibilitySpec.groovy
+++ b/src/test/groovy/sdkman/specs/SdkCompatibilitySpec.groovy
@@ -11,7 +11,6 @@ class SdkCompatibilitySpec extends SdkmanEnvSpecification {
def setup() {
bash = sdkmanBashEnvBuilder
- .withCandidatesCache(allCandidates)
.withCandidates(allCandidates)
.withVersionCache("x.y.z")
.build()
diff --git a/src/test/groovy/sdkman/steps/env.groovy b/src/test/groovy/sdkman/steps/env.groovy
index 79da16fe..344220d4 100644
--- a/src/test/groovy/sdkman/steps/env.groovy
+++ b/src/test/groovy/sdkman/steps/env.groovy
@@ -44,6 +44,8 @@ candidatesFile = new File(varDir, "candidates")
versionFile = new File(varDir, "version")
initScript = new File(binDir, "sdkman-init.sh")
+localCandidates = ['groovy', 'grails', 'java', 'kotlin', 'scala']
+
bash = null
if(!binding.hasVariable("wireMock")) {
diff --git a/src/test/groovy/sdkman/steps/initialisation_steps.groovy b/src/test/groovy/sdkman/steps/initialisation_steps.groovy
index 565f44f9..5a09a199 100644
--- a/src/test/groovy/sdkman/steps/initialisation_steps.groovy
+++ b/src/test/groovy/sdkman/steps/initialisation_steps.groovy
@@ -94,6 +94,7 @@ And(~'^an initialised environment$') {->
.withJdkHome(javaHome)
.withHttpProxy(HTTP_PROXY)
.withVersionCache(sdkmanVersion)
+ .withCandidates(localCandidates)
.withSdkmanVersion(sdkmanVersion)
.build()
}
@@ -133,4 +134,8 @@ And(~'^the system is bootstrapped again$') {->
And(~/^the sdkman version is "([^"]*)"$/) { String version ->
sdkmanVersion = version
+}
+
+And(~/^the candidates cache is initialised with "(.*)"$/) { String candidate ->
+ localCandidates << candidate
}
\ No newline at end of file
diff --git a/src/test/groovy/sdkman/steps/stub_steps.groovy b/src/test/groovy/sdkman/steps/stub_steps.groovy
index 296dc6b0..2f4822ae 100644
--- a/src/test/groovy/sdkman/steps/stub_steps.groovy
+++ b/src/test/groovy/sdkman/steps/stub_steps.groovy
@@ -1,5 +1,6 @@
package sdkman.steps
+import cucumber.api.DataTable
import sdkman.support.UnixUtils
import static cucumber.api.groovy.EN.And
@@ -100,3 +101,7 @@ And(~/^a download request was made for "(.*)" "(.*)" on "(.*)" with cookie "(.*)
And(~/^a cookie is required for installing "(.*)" "(.*)" on "(.*)"$/) { String candidate, String version, String platform ->
//handled by the hook in subsequent step
}
+
+And(~/^the following candidates are currently available from remote API:$/) { DataTable dt ->
+ primeEndpointWithString("/candidates/all", dt.asList(String).drop(1).join(","))
+}
\ No newline at end of file
diff --git a/src/test/groovy/sdkman/steps/update_steps.groovy b/src/test/groovy/sdkman/steps/update_steps.groovy
new file mode 100644
index 00000000..7ad48ff7
--- /dev/null
+++ b/src/test/groovy/sdkman/steps/update_steps.groovy
@@ -0,0 +1,13 @@
+package sdkman.steps
+
+import cucumber.api.DataTable
+
+import static cucumber.api.groovy.EN.*
+
+And(~/^the following candidates are available for installation in local cache:$/) { DataTable dt ->
+ localCandidates = dt.asList(String).drop(1)
+}
+
+And(~/^the Candidates cache should contain "(.*)"$/) { String candidates ->
+ assert candidatesFile.text.trim() == candidates
+}
\ No newline at end of file
diff --git a/src/test/groovy/sdkman/stubs/WebServiceStub.groovy b/src/test/groovy/sdkman/stubs/WebServiceStub.groovy
index 8c143e7b..60b8af83 100644
--- a/src/test/groovy/sdkman/stubs/WebServiceStub.groovy
+++ b/src/test/groovy/sdkman/stubs/WebServiceStub.groovy
@@ -1,7 +1,5 @@
package sdkman.stubs
-import sdkman.support.UnixUtils
-
import static com.github.tomakehurst.wiremock.client.WireMock.*
class WebServiceStub {