diff --git a/acceptance-tests/build.gradle.kts b/acceptance-tests/build.gradle.kts index 2d67312c..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" } @@ -79,8 +78,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 +100,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..e87b146a --- /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.setBrowserVersion("stable"); + 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-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") - } -} diff --git a/build.gradle.kts b/build.gradle.kts index 856a56f9..e17a059a 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() } 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) {