From d44a7c602b02c57281670e0999c8c2eb9f3fd7bc Mon Sep 17 00:00:00 2001 From: Valery Yatsynovich Date: Sat, 29 Jun 2024 00:52:52 +0300 Subject: [PATCH] Load latest SauceConnect version lazily (#271) --- .../sauceconnect/SauceConnectFourManager.java | 22 ++++++++++--- .../SauceConnectFourManagerTest.java | 32 +++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/saucelabs/ci/sauceconnect/SauceConnectFourManager.java b/src/main/java/com/saucelabs/ci/sauceconnect/SauceConnectFourManager.java index cd45bc0..a84a2fb 100755 --- a/src/main/java/com/saucelabs/ci/sauceconnect/SauceConnectFourManager.java +++ b/src/main/java/com/saucelabs/ci/sauceconnect/SauceConnectFourManager.java @@ -6,6 +6,9 @@ import org.apache.commons.compress.archivers.ArchiveStreamFactory; import org.apache.commons.compress.compressors.CompressorException; import org.apache.commons.compress.compressors.CompressorStreamFactory; +import org.apache.commons.lang3.concurrent.ConcurrentException; +import org.apache.commons.lang3.concurrent.LazyInitializer; +import org.apache.commons.lang3.concurrent.LazyInitializer.Builder; import org.json.JSONObject; import java.io.BufferedInputStream; @@ -133,7 +136,9 @@ public String getDefaultSauceConnectLogDirectory() { "Sauce Connect is up, you may start your tests"; public static final String CURRENT_SC_VERSION = "4.9.1"; - public static final String LATEST_SC_VERSION = getLatestSauceConnectVersion(); + public static final LazyInitializer LATEST_SC_VERSION = new Builder, String>() + .setInitializer(SauceConnectFourManager::getLatestSauceConnectVersion) + .get(); private static final String SAUCE_CONNECT = "sc-"; public static final String SAUCE_CONNECT_4 = SAUCE_CONNECT + CURRENT_SC_VERSION; @@ -379,9 +384,18 @@ protected String getCurrentVersion() { } private static String getVersion(boolean useLatestSauceConnect) { - return useLatestSauceConnect && LATEST_SC_VERSION != null - ? LATEST_SC_VERSION - : CURRENT_SC_VERSION; + if (useLatestSauceConnect) { + try { + String latestVersion = LATEST_SC_VERSION.get(); + if (latestVersion != null) { + return latestVersion; + } + } + catch (ConcurrentException e) { + // Never happens + } + } + return CURRENT_SC_VERSION; } /** diff --git a/src/test/java/com/saucelabs/ci/sauceconnect/SauceConnectFourManagerTest.java b/src/test/java/com/saucelabs/ci/sauceconnect/SauceConnectFourManagerTest.java index 4242529..d4a20eb 100755 --- a/src/test/java/com/saucelabs/ci/sauceconnect/SauceConnectFourManagerTest.java +++ b/src/test/java/com/saucelabs/ci/sauceconnect/SauceConnectFourManagerTest.java @@ -13,7 +13,9 @@ import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.ValueSource; import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatcher; import org.mockito.Mock; +import org.mockito.MockedStatic; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; @@ -22,6 +24,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; +import java.net.http.HttpClient; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandler; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.Locale; @@ -35,8 +40,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -212,4 +220,28 @@ void testSauceConnectSecretsWithSpecialCharactersCoveredWithStars() { args = new String[] {"-w", "super-user:passwd"}; assertEquals("[-w, super-user:****]", manager.hideSauceConnectCommandlineSecrets(args)); } + + @Test + void shouldInitLatestVersionLazilyAndOnce() throws IOException, InterruptedException { + try (MockedStatic httpClientStaticMock = mockStatic(HttpClient.class)) { + HttpClient httpClient = mock(); + HttpResponse httpResponse = mock(); + String version = "4.99.99"; + when(httpResponse.body()).thenReturn("{\"Sauce Connect\": {\"version\": \"" + version + "\"}}"); + when(httpClient.send(any(), argThat((ArgumentMatcher>) argument -> true))).thenReturn( + httpResponse); + httpClientStaticMock.when(HttpClient::newHttpClient).thenReturn(httpClient); + + SauceConnectFourManager sauceConnectFourManager = new SauceConnectFourManager(); + sauceConnectFourManager.setUseLatestSauceConnect(true); + + String currentVersion = sauceConnectFourManager.getCurrentVersion(); + assertEquals(version, currentVersion); + httpClientStaticMock.verify(HttpClient::newHttpClient); + + currentVersion = sauceConnectFourManager.getCurrentVersion(); + assertEquals(version, currentVersion); + httpClientStaticMock.verifyNoMoreInteractions(); + } + } }