|
1 | 1 | package com.openai |
2 | 2 |
|
3 | 3 | import java.lang.RuntimeException |
| 4 | +import java.lang.reflect.Method |
4 | 5 | import java.net.URL |
| 6 | +import java.nio.channels.FileChannel |
| 7 | +import java.nio.file.Paths |
| 8 | +import java.nio.file.StandardOpenOption.CREATE |
| 9 | +import java.nio.file.StandardOpenOption.WRITE |
| 10 | +import java.util.UUID |
| 11 | +import java.util.concurrent.locks.ReentrantLock |
| 12 | +import kotlin.concurrent.withLock |
5 | 13 | import org.junit.jupiter.api.extension.BeforeAllCallback |
6 | 14 | import org.junit.jupiter.api.extension.ConditionEvaluationResult |
7 | 15 | import org.junit.jupiter.api.extension.ExecutionCondition |
8 | 16 | import org.junit.jupiter.api.extension.ExtensionContext |
| 17 | +import org.junit.jupiter.api.extension.InvocationInterceptor |
| 18 | +import org.junit.jupiter.api.extension.ReflectiveInvocationContext |
9 | 19 |
|
10 | | -class TestServerExtension : BeforeAllCallback, ExecutionCondition { |
| 20 | +class TestServerExtension : BeforeAllCallback, ExecutionCondition, InvocationInterceptor { |
11 | 21 |
|
12 | 22 | override fun beforeAll(context: ExtensionContext?) { |
13 | 23 | try { |
@@ -40,10 +50,31 @@ class TestServerExtension : BeforeAllCallback, ExecutionCondition { |
40 | 50 | } |
41 | 51 | } |
42 | 52 |
|
| 53 | + override fun interceptTestMethod( |
| 54 | + invocation: InvocationInterceptor.Invocation<Void>, |
| 55 | + invocationContext: ReflectiveInvocationContext<Method>, |
| 56 | + extensionContext: ExtensionContext, |
| 57 | + ) { |
| 58 | + PROCESS_LOCK.withLock { |
| 59 | + FileChannel.open(LOCK_FILE, CREATE, WRITE).use { channel -> |
| 60 | + channel.lock().use { invocation.proceed() } |
| 61 | + } |
| 62 | + } |
| 63 | + } |
| 64 | + |
43 | 65 | companion object { |
44 | 66 |
|
45 | 67 | val BASE_URL = System.getenv("TEST_API_BASE_URL") ?: "http://localhost:4010" |
46 | 68 |
|
47 | 69 | const val SKIP_TESTS_ENV: String = "SKIP_MOCK_TESTS" |
| 70 | + |
| 71 | + // JUnit resource locks do not coordinate separate Gradle test-worker JVMs. Use both a |
| 72 | + // process-local lock and an OS file lock so tests sharing one mock server cannot race. |
| 73 | + private val PROCESS_LOCK = ReentrantLock(true) |
| 74 | + private val LOCK_FILE = |
| 75 | + Paths.get( |
| 76 | + System.getProperty("java.io.tmpdir"), |
| 77 | + "openai-java-test-server-${UUID.nameUUIDFromBytes(BASE_URL.toByteArray())}.lock", |
| 78 | + ) |
48 | 79 | } |
49 | 80 | } |
0 commit comments