From 358d17baf19138230cbc3b02bef1f433cc9d354a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Varga?= Date: Mon, 5 Aug 2024 15:16:23 +0200 Subject: [PATCH 1/4] build: Setup concurrent tests --- robolectric-extension/build.gradle | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/robolectric-extension/build.gradle b/robolectric-extension/build.gradle index a86c3cd..ba030c3 100644 --- a/robolectric-extension/build.gradle +++ b/robolectric-extension/build.gradle @@ -34,12 +34,27 @@ test { systemProperty 'junit.jupiter.execution.parallel.enabled', 'true' systemProperty 'junit.jupiter.execution.parallel.mode.default', 'same_thread' systemProperty 'junit.jupiter.execution.parallel.mode.classes.default', 'same_thread' - systemProperty 'java.util.logging.config.file', - "${projectDir}/src/test/resources/logging.properties" + systemProperty 'java.util.logging.config.file', "${projectDir}/src/test/resources/logging.properties" systemProperty 'robolectric.usePreinstrumentedJars', 'true' } -tasks.test { +task concurrentTest(type: Test) { + testLogging { + showStandardStreams = true + showExceptions = true + showCauses = true + showStackTraces = true + } + systemProperty 'junit.jupiter.execution.parallel.enabled', 'true' + systemProperty 'junit.jupiter.execution.parallel.mode.default', 'same_thread' + systemProperty 'junit.jupiter.execution.parallel.mode.classes.default', 'concurrent' + systemProperty 'java.util.logging.config.file', "${projectDir}/src/test/resources/logging.properties" + systemProperty 'robolectric.usePreinstrumentedJars', 'true' +} + +check.dependsOn(concurrentTest) + +tasks.withType(Test.class).configureEach { javaLauncher.set( javaToolchains.launcherFor { languageVersion.set(JavaLanguageVersion.of(libs.versions.jvmToolchain.get().toInteger())) From 792087ab1d7449e268041839555133e0307e639f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Varga?= Date: Wed, 14 Aug 2024 10:56:00 +0200 Subject: [PATCH 2/4] fix: OverlappingFileLockException --- .../internal/JUnit5MavenDependencyResolver.kt | 47 +++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/robolectric-extension/src/main/kotlin/tech/apter/junit/jupiter/robolectric/internal/JUnit5MavenDependencyResolver.kt b/robolectric-extension/src/main/kotlin/tech/apter/junit/jupiter/robolectric/internal/JUnit5MavenDependencyResolver.kt index 47784e3..ce04c52 100644 --- a/robolectric-extension/src/main/kotlin/tech/apter/junit/jupiter/robolectric/internal/JUnit5MavenDependencyResolver.kt +++ b/robolectric-extension/src/main/kotlin/tech/apter/junit/jupiter/robolectric/internal/JUnit5MavenDependencyResolver.kt @@ -5,13 +5,17 @@ import org.robolectric.internal.dependency.DependencyJar import org.robolectric.internal.dependency.MavenArtifactFetcher import org.robolectric.internal.dependency.MavenDependencyResolver import org.robolectric.internal.dependency.MavenJarArtifact +import tech.apter.junit.jupiter.robolectric.internal.extensions.createLogger import java.io.File import java.io.IOException import java.io.RandomAccessFile import java.net.MalformedURLException import java.net.URL +import java.nio.channels.FileLock +import java.nio.channels.OverlappingFileLockException import java.util.concurrent.ExecutorService + internal class JUnit5MavenDependencyResolver private constructor( repositoryUrl: String, repositoryId: String, @@ -44,9 +48,12 @@ internal class JUnit5MavenDependencyResolver private constructor( val artifacts: List> = dependencies.map { it to MavenJarArtifact(it) } for ((dependencyJar, artifact) in artifacts) { - if (!File(localRepositoryDir, artifact.jarPath()).exists()) { + val artifactJarFile = File(localRepositoryDir, artifact.jarPath()) + if (!artifactJarFile.exists()) { whileLocked(dependencyJar) { - mavenArtifactFetcher.fetchArtifact(artifact) + if (!artifactJarFile.exists()) { + mavenArtifactFetcher.fetchArtifact(artifact) + } } } } @@ -73,9 +80,17 @@ internal class JUnit5MavenDependencyResolver private constructor( try { RandomAccessFile(lockFile, "rw").use { raf -> raf.channel.use { channel -> - channel.lock().use { - runnable.run() + var lock: FileLock? = null + while (lock == null) { + try { + lock = channel.tryLock() + } catch (e: OverlappingFileLockException) { + // Sleep for a while before retrying + Thread.sleep(100) + } } + runnable.run() + lock.release() } } } catch (e: IOException) { @@ -85,6 +100,30 @@ internal class JUnit5MavenDependencyResolver private constructor( } } + private fun whileLocked(runnable: Runnable) { + val lockFile = createLockFile() + try { + RandomAccessFile(lockFile, "rw").use { raf -> + raf.channel.use { channel -> + var lock: FileLock? = null + while (lock == null) { + try { + lock = channel.tryLock() + } catch (e: OverlappingFileLockException) { + // Sleep for a while before retrying + Thread.sleep(100) + } + } + } + } + } catch (e: IOException) { + throw java.lang.IllegalStateException("Couldn't create lock file $lockFile", e) + } finally { + lockFile.delete() + } + } + + private companion object { private const val SPECIAL_CHARACTERS_IN_FILE_NAME_REGEX = """[<>:"\\/|\?\*]""" } From 695ddf236f9f7741130f8ff70e02a7d7112ab03f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Varga?= Date: Wed, 14 Aug 2024 11:23:42 +0200 Subject: [PATCH 3/4] fix: OverlappingFileLockException --- .../internal/JUnit5MavenDependencyResolver.kt | 26 +------------------ 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/robolectric-extension/src/main/kotlin/tech/apter/junit/jupiter/robolectric/internal/JUnit5MavenDependencyResolver.kt b/robolectric-extension/src/main/kotlin/tech/apter/junit/jupiter/robolectric/internal/JUnit5MavenDependencyResolver.kt index ce04c52..fce3b7b 100644 --- a/robolectric-extension/src/main/kotlin/tech/apter/junit/jupiter/robolectric/internal/JUnit5MavenDependencyResolver.kt +++ b/robolectric-extension/src/main/kotlin/tech/apter/junit/jupiter/robolectric/internal/JUnit5MavenDependencyResolver.kt @@ -5,7 +5,6 @@ import org.robolectric.internal.dependency.DependencyJar import org.robolectric.internal.dependency.MavenArtifactFetcher import org.robolectric.internal.dependency.MavenDependencyResolver import org.robolectric.internal.dependency.MavenJarArtifact -import tech.apter.junit.jupiter.robolectric.internal.extensions.createLogger import java.io.File import java.io.IOException import java.io.RandomAccessFile @@ -24,6 +23,7 @@ internal class JUnit5MavenDependencyResolver private constructor( proxyHost: String?, proxyPort: Int, ) : MavenDependencyResolver(repositoryUrl, repositoryId, repositoryUserName, repositoryPassword, proxyHost, proxyPort) { + @Suppress("unused") constructor() : this( MavenRoboSettings.getMavenRepositoryUrl(), MavenRoboSettings.getMavenRepositoryId(), @@ -100,30 +100,6 @@ internal class JUnit5MavenDependencyResolver private constructor( } } - private fun whileLocked(runnable: Runnable) { - val lockFile = createLockFile() - try { - RandomAccessFile(lockFile, "rw").use { raf -> - raf.channel.use { channel -> - var lock: FileLock? = null - while (lock == null) { - try { - lock = channel.tryLock() - } catch (e: OverlappingFileLockException) { - // Sleep for a while before retrying - Thread.sleep(100) - } - } - } - } - } catch (e: IOException) { - throw java.lang.IllegalStateException("Couldn't create lock file $lockFile", e) - } finally { - lockFile.delete() - } - } - - private companion object { private const val SPECIAL_CHARACTERS_IN_FILE_NAME_REGEX = """[<>:"\\/|\?\*]""" } From c6c5baa3ecd0901466f2c98c2af11d55890fc03d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Varga?= Date: Wed, 14 Aug 2024 11:37:18 +0200 Subject: [PATCH 4/4] fix: OverlappingFileLockException --- .../robolectric/internal/JUnit5MavenDependencyResolver.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/robolectric-extension/src/main/kotlin/tech/apter/junit/jupiter/robolectric/internal/JUnit5MavenDependencyResolver.kt b/robolectric-extension/src/main/kotlin/tech/apter/junit/jupiter/robolectric/internal/JUnit5MavenDependencyResolver.kt index fce3b7b..747c92a 100644 --- a/robolectric-extension/src/main/kotlin/tech/apter/junit/jupiter/robolectric/internal/JUnit5MavenDependencyResolver.kt +++ b/robolectric-extension/src/main/kotlin/tech/apter/junit/jupiter/robolectric/internal/JUnit5MavenDependencyResolver.kt @@ -14,7 +14,6 @@ import java.nio.channels.FileLock import java.nio.channels.OverlappingFileLockException import java.util.concurrent.ExecutorService - internal class JUnit5MavenDependencyResolver private constructor( repositoryUrl: String, repositoryId: String, @@ -82,11 +81,12 @@ internal class JUnit5MavenDependencyResolver private constructor( raf.channel.use { channel -> var lock: FileLock? = null while (lock == null) { + @Suppress("SwallowedException") try { lock = channel.tryLock() } catch (e: OverlappingFileLockException) { // Sleep for a while before retrying - Thread.sleep(100) + Thread.sleep(WAIT_MS_UNTIL_LOCK_FILE_RELEASED) } } runnable.run() @@ -101,6 +101,7 @@ internal class JUnit5MavenDependencyResolver private constructor( } private companion object { + private const val WAIT_MS_UNTIL_LOCK_FILE_RELEASED = 100L private const val SPECIAL_CHARACTERS_IN_FILE_NAME_REGEX = """[<>:"\\/|\?\*]""" } }