From c94143d7d2d33b0bd1fc4a46ec9fc2abf4da65db Mon Sep 17 00:00:00 2001 From: Alexis Tual Date: Fri, 17 Nov 2023 16:26:42 +0100 Subject: [PATCH 1/4] Run acceptance tests with Chrome for testing And do not run acceptance tests on jenkins.io where neither firefox, chrome, firefox-container and chrome-container are currently working for us. --- acceptance-tests/build.gradle.kts | 7 +- .../config/GradleAcceptanceTestsModule.java | 3 + .../gradle/ath/config/WebDriverProvider.java | 97 +++++++++++++++++++ build.gradle.kts | 1 + 4 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/WebDriverProvider.java diff --git a/acceptance-tests/build.gradle.kts b/acceptance-tests/build.gradle.kts index 2d67312c..3320c315 100644 --- a/acceptance-tests/build.gradle.kts +++ b/acceptance-tests/build.gradle.kts @@ -79,8 +79,11 @@ jenkinsVersions .withNormalizer(ClasspathNormalizer::class) onlyIf { + // Do not run on Jenkins since acceptance tests don't work there for some reason, one of them: + // https://github.com/jenkinsci/acceptance-test-harness/issues/1170 + // // Do not run on Windows as written here: https://github.com/jenkinsci/acceptance-test-harness/blob/master/docs/EXTERNAL.md - !OperatingSystem.current().isWindows + !ciJenkinsBuild && !OperatingSystem.current().isWindows } javaLauncher.set(javaToolchains.launcherFor { @@ -98,7 +101,7 @@ jenkinsVersions mapOf( "JENKINS_WAR" to downloadJenkinsTask.get().outputs.files.singleFile, "LOCAL_JARS" to gradlePlugin.singleFile, - "BROWSER" to if (ciJenkinsBuild) "firefox-container" else "chrome" + "BROWSER" to "chrome" ) ) } diff --git a/acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/GradleAcceptanceTestsModule.java b/acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/GradleAcceptanceTestsModule.java index d8f4d738..b5d297e1 100644 --- a/acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/GradleAcceptanceTestsModule.java +++ b/acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/GradleAcceptanceTestsModule.java @@ -8,8 +8,10 @@ import hudson.plugin.gradle.ath.updatecenter.VersionOverridesDecorator; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; +import org.jenkinsci.test.acceptance.guice.TestScope; import org.jenkinsci.test.acceptance.update_center.UpdateCenterMetadata; import org.jenkinsci.test.acceptance.update_center.UpdateCenterMetadataProvider; +import org.openqa.selenium.WebDriver; import java.io.File; import java.util.function.Consumer; @@ -31,6 +33,7 @@ protected void configure() { Matchers.returns(Matchers.subclassesOf(UpdateCenterMetadata.class)), new ResultDecoratingAdapter<>(new VersionOverridesDecorator()) ); + bind(WebDriver.class).toProvider(WebDriverProvider.class).in(TestScope.class); } private static class ResultDecoratingAdapter implements MethodInterceptor { diff --git a/acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/WebDriverProvider.java b/acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/WebDriverProvider.java new file mode 100644 index 00000000..782a97c9 --- /dev/null +++ b/acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/WebDriverProvider.java @@ -0,0 +1,97 @@ +package hudson.plugin.gradle.ath.config; + +import com.google.common.collect.ImmutableMap; +import com.google.inject.Inject; +import com.google.inject.Provider; +import org.jenkinsci.test.acceptance.FallbackConfig; +import org.jenkinsci.test.acceptance.guice.TestCleaner; +import org.jenkinsci.test.acceptance.guice.TestName; +import org.jenkinsci.test.acceptance.selenium.Scroller; +import org.jenkinsci.test.acceptance.utils.ElasticTime; +import org.junit.runners.model.Statement; +import org.openqa.selenium.Dimension; +import org.openqa.selenium.UnsupportedCommandException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeOptions; +import org.openqa.selenium.support.events.EventFiringWebDriver; + +import java.io.IOException; +import java.time.Duration; +import java.util.Locale; +import java.util.logging.Logger; + +class WebDriverProvider implements Provider { + + private static final Logger LOGGER = Logger.getLogger(FallbackConfig.class.getName()); + private final TestCleaner testCleaner; + private final FallbackConfig fallbackConfig; + private final TestName testName; + private final ElasticTime time; + + @Inject + public WebDriverProvider( + TestCleaner testCleaner, + FallbackConfig fallbackConfig, + TestName testName, + ElasticTime time) { + this.testCleaner = testCleaner; + this.fallbackConfig = fallbackConfig; + this.testName = testName; + this.time = time; + } + + private String getBrowser() { + String browser = System.getenv("BROWSER"); + if (browser == null) browser = "chrome-container"; + browser = browser.toLowerCase(Locale.ENGLISH); + return browser; + } + + @Override + public WebDriver get() { + if ("chrome".equals(getBrowser())) { + return createChromeWebDriver(); + } + try { + return fallbackConfig.createWebDriver(testCleaner, testName, time); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private WebDriver createChromeWebDriver() { + ChromeOptions chromeOptions = new ChromeOptions(); + chromeOptions.setBinary("/usr/bin/google-chrome-for-testing"); + chromeOptions.addArguments("--window-position=0,0"); + chromeOptions.addArguments("--window-size=1280,720"); + chromeOptions.addArguments("--lang=en_US"); + chromeOptions.setExperimentalOption("prefs", ImmutableMap.of("intl.accept_languages", "en_US")); + ChromeDriver d = new ChromeDriver(chromeOptions); + Dimension oldSize = d.manage().window().getSize(); + if (oldSize.height < 1050 || oldSize.width < 1680) { + d.manage().window().setSize(new Dimension(1680, 1050)); + } + final EventFiringWebDriver driver = new EventFiringWebDriver(d); + driver.register(new Scroller()); + try { + driver.manage().timeouts().pageLoadTimeout(Duration.ofMillis(time.seconds(FallbackConfig.PAGE_LOAD_TIMEOUT))); + driver.manage().timeouts().implicitlyWait(Duration.ofMillis(time.seconds(FallbackConfig.IMPLICIT_WAIT_TIMEOUT))); + } catch (UnsupportedCommandException e) { + // sauce labs RemoteWebDriver doesn't support this + LOGGER.info(d + " doesn't support page load timeout"); + } + testCleaner.addTask(new Statement() { + @Override + public void evaluate() { + driver.quit(); + } + + @Override + public String toString() { + return "Close WebDriver after test"; + } + }); + return driver; + } +} diff --git a/build.gradle.kts b/build.gradle.kts index 19638285..20b77f8c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -198,6 +198,7 @@ tasks.test { maxRetries.set(2) maxFailures.set(5) } + failOnPassedAfterRetry.set(false) } useJUnitPlatform() } From af8830a6ce5a2ae69f02103136dd0fdb7b0e3418 Mon Sep 17 00:00:00 2001 From: Alexis Tual Date: Tue, 21 Nov 2023 15:25:04 +0100 Subject: [PATCH 2/4] Fix test label --- .../plugins/gradle/BuildScanLogScannerTest.groovy | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/groovy/hudson/plugins/gradle/BuildScanLogScannerTest.groovy b/src/test/groovy/hudson/plugins/gradle/BuildScanLogScannerTest.groovy index 60b1d8c9..8ee74ff4 100644 --- a/src/test/groovy/hudson/plugins/gradle/BuildScanLogScannerTest.groovy +++ b/src/test/groovy/hudson/plugins/gradle/BuildScanLogScannerTest.groovy @@ -8,7 +8,7 @@ import spock.lang.Unroll @Subject(BuildScanLogScanner) class BuildScanLogScannerTest extends Specification { - def 'properly captures build scan url given #log'(List log, List expectedUrls) { + def 'properly captures build scan url given #label'(String label, List log, List expectedUrls) { given: def listener = new SimpleBuildScanPublishedListener() def scanner = new BuildScanLogScanner(listener) @@ -20,12 +20,12 @@ class BuildScanLogScannerTest extends Specification { listener.buildScans == expectedUrls where: - log || expectedUrls - logWithBuildScans(["https://scans.gradle.com/s/bzb4vn64kx3bc"]) || ["https://scans.gradle.com/s/bzb4vn64kx3bc"] - logWithBuildScans(["https://scans.gradle.com/s/bzb4vn64kx3bc", "https://scans.gradle.com/s/asc9wm73ly1do"]) || ["https://scans.gradle.com/s/bzb4vn64kx3bc", "https://scans.gradle.com/s/asc9wm73ly1do"] - logWithBuildScans(["https://scans.gradle.com/bzb4vn64kx3bc"]) || [] - logWithBuildScans(["https://scans.gradle.com/s/bzb4vn64kx3bc"], 1010) || [] - logWithBuildScans(["https://scans.gradle.com/s/bzb4vn64kx3bc"], 900) || ["https://scans.gradle.com/s/bzb4vn64kx3bc"] + label | log || expectedUrls + 'One build scan URL' | logWithBuildScans(["https://scans.gradle.com/s/bzb4vn64kx3bc"]) || ["https://scans.gradle.com/s/bzb4vn64kx3bc"] + 'Two build scan URLs' | logWithBuildScans(["https://scans.gradle.com/s/bzb4vn64kx3bc", "https://scans.gradle.com/s/asc9wm73ly1do"]) || ["https://scans.gradle.com/s/bzb4vn64kx3bc", "https://scans.gradle.com/s/asc9wm73ly1do"] + 'Non build scan URL' | logWithBuildScans(["https://scans.gradle.com/bzb4vn64kx3bc"]) || [] + 'Too many lines before build scan URL' | logWithBuildScans(["https://scans.gradle.com/s/bzb4vn64kx3bc"], 1010) || [] + 'Lot of lines before build scan URL' | logWithBuildScans(["https://scans.gradle.com/s/bzb4vn64kx3bc"], 900) || ["https://scans.gradle.com/s/bzb4vn64kx3bc"] } static List logWithBuildScans(List scanLinks, linesBetween = 10) { From f7834b9669e9ed3adf7a08077fb3bd4143e88584 Mon Sep 17 00:00:00 2001 From: Alexis Tual Date: Wed, 22 Nov 2023 15:22:50 +0100 Subject: [PATCH 3/4] Try a random path for chrome binary --- .../java/hudson/plugin/gradle/ath/config/WebDriverProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/WebDriverProvider.java b/acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/WebDriverProvider.java index 782a97c9..25927efb 100644 --- a/acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/WebDriverProvider.java +++ b/acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/WebDriverProvider.java @@ -62,7 +62,7 @@ public WebDriver get() { private WebDriver createChromeWebDriver() { ChromeOptions chromeOptions = new ChromeOptions(); - chromeOptions.setBinary("/usr/bin/google-chrome-for-testing"); + chromeOptions.setBinary("foo"); chromeOptions.addArguments("--window-position=0,0"); chromeOptions.addArguments("--window-size=1280,720"); chromeOptions.addArguments("--lang=en_US"); From 0571bb8aa37dd7e80f66d5f7fc655946ffe2fd9b Mon Sep 17 00:00:00 2001 From: Alexis Tual Date: Wed, 22 Nov 2023 16:29:04 +0100 Subject: [PATCH 4/4] Try to rely on Selenium managing the Chrome driver infra --- acceptance-tests/build.gradle.kts | 1 - .../gradle/ath/config/WebDriverProvider.java | 2 +- .../kotlin/buildlogic.chromedriver.gradle.kts | 73 ------------------- 3 files changed, 1 insertion(+), 75 deletions(-) delete mode 100644 build-logic/src/main/kotlin/buildlogic.chromedriver.gradle.kts diff --git a/acceptance-tests/build.gradle.kts b/acceptance-tests/build.gradle.kts index 3320c315..943bb372 100644 --- a/acceptance-tests/build.gradle.kts +++ b/acceptance-tests/build.gradle.kts @@ -5,7 +5,6 @@ import java.net.URL plugins { java - id("buildlogic.chromedriver") id("de.undercouch.download") version "5.5.0" } diff --git a/acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/WebDriverProvider.java b/acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/WebDriverProvider.java index 25927efb..e87b146a 100644 --- a/acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/WebDriverProvider.java +++ b/acceptance-tests/src/main/java/hudson/plugin/gradle/ath/config/WebDriverProvider.java @@ -62,7 +62,7 @@ public WebDriver get() { private WebDriver createChromeWebDriver() { ChromeOptions chromeOptions = new ChromeOptions(); - chromeOptions.setBinary("foo"); + chromeOptions.setBrowserVersion("stable"); chromeOptions.addArguments("--window-position=0,0"); chromeOptions.addArguments("--window-size=1280,720"); chromeOptions.addArguments("--lang=en_US"); diff --git a/build-logic/src/main/kotlin/buildlogic.chromedriver.gradle.kts b/build-logic/src/main/kotlin/buildlogic.chromedriver.gradle.kts deleted file mode 100644 index 0efb1253..00000000 --- a/build-logic/src/main/kotlin/buildlogic.chromedriver.gradle.kts +++ /dev/null @@ -1,73 +0,0 @@ -import org.gradle.api.internal.artifacts.transform.UnzipTransform -import org.gradle.internal.os.OperatingSystem - -val chromeDriverVersion = "119.0.6045.105" -val ciTeamCityBuild: Boolean by (gradle as ExtensionAware).extra - -val os: OperatingSystem = OperatingSystem.current() -val driverOsFilenamePart = when { - os.isWindows -> "win32" - os.isMacOsX && os.nativePrefix.contains("aarch64") -> "mac_arm64" - os.isMacOsX -> "mac64" - os.isLinux && os.nativePrefix.contains("64") -> "linux64" - else -> "linux32" -} - -repositories { - exclusiveContent { - forRepository { - ivy { - url = uri("https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/") - patternLayout { - artifact("[revision]/[classifier]/[artifact]-[classifier].[ext]") - } - metadataSources { - artifact() - } - } - } - filter { - includeModule("chromedriver", "chromedriver") - } - } -} - -val chromedriver: Configuration by configurations.creating { - isCanBeResolved = true - isCanBeConsumed = false - attributes.attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, ArtifactTypeDefinition.DIRECTORY_TYPE) -} - -dependencies { - registerTransform(UnzipTransform::class) { - from.attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, ArtifactTypeDefinition.ZIP_TYPE) - to.attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, ArtifactTypeDefinition.DIRECTORY_TYPE) - } - chromedriver("chromedriver:chromedriver:${chromeDriverVersion}:${driverOsFilenamePart}@zip") -} - -// We do not run acceptance-tests on Windows -if (ciTeamCityBuild && !os.isWindows) { - val killRunningChromedriverInstances by tasks.registering(Exec::class) { - val echoOption = if (os.isLinux) "e" else "l" - commandLine("bash", "-c", "pkill -9 -${echoOption} chrome") - isIgnoreExitValue = true - } - - tasks.withType(Test::class).configureEach { - inputs.files(chromedriver) - jvmArgumentProviders += ChromeDriverProvider(chromedriver) - - finalizedBy(killRunningChromedriverInstances) - } -} - -class ChromeDriverProvider(@Internal val chromedriverDirectory: FileCollection) : CommandLineArgumentProvider { - - override fun asArguments(): Iterable { - val chromedriver = chromedriverDirectory.asFileTree.files.first { it.name == "chromedriver" } - // UnzipTransform does not preserve file permissions, so we're restoring it here - chromedriver.setExecutable(true) - return listOf("-Dwebdriver.chrome.driver=$chromedriver") - } -}