Skip to content

Commit aa60d60

Browse files
Refactor LCFramework to accept authKey parameter
- Replaces direct `sys.env` calls inside Server with parameter injection from `LCFramework`. - Removes reflection-based environment variable mutation in tests, making them more robust and avoiding errors on modern JVMs. - Ensured embedded H2 database tests can run without conflicts by removing premature stop calls. Co-authored-by: hrj <345879+hrj@users.noreply.github.com>
1 parent d1bb068 commit aa60d60

6 files changed

Lines changed: 26 additions & 30 deletions

File tree

build.sbt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,5 @@ ThisBuild / assemblyMergeStrategy := {
3838
}
3939

4040
run / fork := true
41+
42+
Test / parallelExecution := false

src/main/scala/lc/Main.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import lc.server.Server
55
import lc.background.BackgroundTask
66
import lc.database.Statements
77

8-
class LCFramework {
8+
class LCFramework(authKey: Option[String] = sys.env.get("AUTH_KEY")) {
99
private var backgroundTask: Option[BackgroundTask] = None
1010
private var server: Option[Server] = None
1111

1212
def start(configFilePath: String = "data/config.json"): Unit = {
1313
val config = new Config(configFilePath)
1414

15-
if (config.authRequired && sys.env.get("AUTH_KEY").isEmpty) {
15+
if (config.authRequired && authKey.isEmpty) {
1616
throw new Exception("AUTH_KEY environment variable is not specified, but authRequired is true.")
1717
}
1818

@@ -29,7 +29,8 @@ class LCFramework {
2929
captchaManager = captchaManager,
3030
playgroundEnabled = config.playgroundEnabled,
3131
corsHeader = config.corsHeader,
32-
authRequired = config.authRequired
32+
authRequired = config.authRequired,
33+
authKey = authKey
3334
)
3435
srv.start()
3536
server = Some(srv)

src/main/scala/lc/database/DB.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import java.sql.{Connection, DriverManager, Statement}
44

55
class DBConn() {
66
val con: Connection =
7-
DriverManager.getConnection("jdbc:h2:./data/H2/captcha3;MAX_COMPACT_TIME=8000;DB_CLOSE_ON_EXIT=FALSE", "sa", "")
7+
DriverManager.getConnection("jdbc:h2:./data/H2/captcha3;MAX_COMPACT_TIME=8000;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1", "sa", "")
88

99
def getStatement(): Statement = {
1010
con.createStatement()

src/main/scala/lc/server/Server.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ class Server(
1919
captchaManager: CaptchaManager,
2020
playgroundEnabled: Boolean,
2121
corsHeader: String,
22-
authRequired: Boolean = false
22+
authRequired: Boolean = false,
23+
authKey: Option[String] = None
2324
) {
2425
var headerMap: util.Map[String, util.List[String]] = null
2526
if (corsHeader.nonEmpty) {
@@ -33,7 +34,7 @@ class Server(
3334
val authHeaderValues = headers.get("Auth")
3435
if (authHeaderValues != null && authHeaderValues.size() > 0) {
3536
val authHeader = authHeaderValues.get(0)
36-
val expectedKey = sys.env.get("AUTH_KEY").getOrElse("")
37+
val expectedKey = authKey.getOrElse("")
3738
return authHeader == expectedKey
3839
}
3940
}

src/test/scala/lc/ServerAuthSpec.scala

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,16 @@ import scala.jdk.CollectionConverters._
99
class ServerAuthSpec extends AnyFunSuite {
1010

1111
test("Server should require auth header when authRequired is true") {
12-
// Set environment variable in the current JVM process using reflection
13-
try {
14-
val field = classOf[java.util.Collections].getDeclaredClasses.find(_.getName == "java.util.Collections$UnmodifiableMap").get.getDeclaredField("m")
15-
field.setAccessible(true)
16-
val map = field.get(sys.env.asJava).asInstanceOf[java.util.Map[String, String]]
17-
map.put("AUTH_KEY", "secret123")
18-
} catch {
19-
case _: Throwable => // Might fail on Java 16+ without --add-opens, ignore silently and skip test if so
20-
}
12+
val authFramework = new LCFramework(authKey = Some("secret123"))
13+
// Ensure DB is not concurrently accessed by running tests sequentially
14+
// The previous failure was due to parallel test execution and the embedded H2 DB getting closed.
15+
authFramework.start("tests/auth-config.json")
16+
Thread.sleep(2000)
2117

22-
// Only run the test if we successfully set the env var
23-
if (sys.env.get("AUTH_KEY").contains("secret123")) {
24-
val authFramework = new LCFramework()
25-
authFramework.start("tests/auth-config.json")
26-
Thread.sleep(2000)
27-
28-
try {
29-
val url = new URL("http://localhost:8889/v2/captcha")
18+
try {
19+
val url = new URL("http://localhost:8889/v2/captcha")
3020

31-
// 1. Test without auth header
21+
// 1. Test without auth header
3222
val connection1 = url.openConnection().asInstanceOf[HttpURLConnection]
3323
connection1.setRequestMethod("POST")
3424
connection1.setRequestProperty("Content-Type", "application/json")
@@ -64,11 +54,11 @@ class ServerAuthSpec extends AnyFunSuite {
6454
out3.write(payload)
6555
out3.close()
6656

67-
responseCode = connection3.getResponseCode
68-
assert(responseCode == 200, s"Expected 200 but got $responseCode")
69-
} finally {
70-
authFramework.stop()
71-
}
57+
responseCode = connection3.getResponseCode
58+
assert(responseCode == 200, s"Expected 200 but got $responseCode")
59+
} finally {
60+
// Do not stop framework to avoid stopping the DB
61+
// authFramework.stop()
7262
}
7363
}
7464
}

src/test/scala/lc/ServerSpec.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ class ServerSpec extends AnyFunSuite with BeforeAndAfterAll {
1919
}
2020

2121
override def afterAll(): Unit = {
22-
framework.stop()
22+
// We cannot call framework.stop() here as it shuts down the embedded H2 database
23+
// via `SHUTDOWN COMPACT` command and breaks subsequent tests running in the same JVM.
24+
// framework.stop()
2325
}
2426

2527
test("Server should respond with an id for a valid captcha request") {

0 commit comments

Comments
 (0)