Skip to content
This repository was archived by the owner on Dec 10, 2025. It is now read-only.

Commit f574cd3

Browse files
committed
feat: update dependencies and add extensive test coverage
- Upgraded Spring Boot, Ktor, and Kotlin Wrappers dependencies to newer versions for improved stability and features. - Introduced comprehensive unit tests for `ServerAddress`, `FairPriorityQueue`, `QueueTimeoutService`, and `FastFairPriorityQueue`. - Added `HelpCommand` implementation for better command-line usage guidance. - Refactored standalone build script to streamline library handling and remove outdated comments/code.
1 parent 6968a82 commit f574cd3

File tree

9 files changed

+341
-17
lines changed

9 files changed

+341
-17
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ allprojects {
4040

4141
implementation(platform(project(":surf-cloud-bom")))
4242

43-
compileOnly("org.springframework.boot:spring-boot-configuration-processor:3.5.4")
43+
compileOnly("org.springframework.boot:spring-boot-configuration-processor:3.5.6")
4444
// "kapt"("org.springframework.boot:spring-boot-configuration-processor:3.4.3")
4545

4646
testImplementation(kotlin("test"))

buildSrc/src/main/kotlin/core-convention.gradle.kts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ repositories {
1212
}
1313

1414
dependencies {
15-
implementation(platform("org.springframework.boot:spring-boot-dependencies:3.5.4"))
16-
implementation(platform("io.ktor:ktor-bom:3.2.1"))
17-
implementation(platform("org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom:2025.7.8"))
15+
implementation(platform("org.springframework.boot:spring-boot-dependencies:3.5.6"))
16+
implementation(platform("io.ktor:ktor-bom:3.3.0"))
17+
implementation(platform("org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom:2025.9.8"))
1818

1919

20-
compileOnly("org.springframework.boot:spring-boot-configuration-processor:3.5.3")
20+
compileOnly("org.springframework.boot:spring-boot-configuration-processor:3.5.6")
2121
// "kapt"("org.springframework.boot:spring-boot-configuration-processor:3.4.3")
2222
}

surf-cloud-bom/build.gradle.kts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ javaPlatform {
1010
}
1111

1212
dependencies {
13-
api(platform("org.springframework.boot:spring-boot-dependencies:3.5.4"))
14-
api(platform("io.ktor:ktor-bom:3.2.3"))
15-
api(platform("org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom:2025.8.10"))
13+
api(platform("org.springframework.boot:spring-boot-dependencies:3.5.6"))
14+
api(platform("io.ktor:ktor-bom:3.3.0"))
15+
api(platform("org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom:2025.9.8"))
1616
}
1717

1818
configurations.all {
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package dev.slne.surf.cloud.core.common.util
2+
3+
import org.junit.jupiter.api.Assertions.assertEquals
4+
import org.junit.jupiter.api.Assertions.assertThrows
5+
import org.junit.jupiter.api.Test
6+
import java.net.InetSocketAddress
7+
8+
class ServerAddressTest {
9+
10+
@Test
11+
fun `parses host and port from string`() {
12+
val serverAddress = "example.com:1234".toServerAddress()
13+
14+
assertEquals("example.com", serverAddress.host)
15+
assertEquals(1234, serverAddress.port)
16+
}
17+
18+
@Test
19+
fun `uses default port when not provided`() {
20+
val serverAddress = "example.com".toServerAddress()
21+
22+
assertEquals("example.com", serverAddress.host)
23+
assertEquals(25566, serverAddress.port)
24+
}
25+
26+
@Test
27+
fun `converts unicode host to ascii`() {
28+
val serverAddress = "☃.com:4040".toServerAddress()
29+
30+
assertEquals("xn--n3h.com", serverAddress.host)
31+
assertEquals(4040, serverAddress.port)
32+
}
33+
34+
@Test
35+
fun `throws when parsing invalid server address`() {
36+
val exception = assertThrows(IllegalArgumentException::class.java) {
37+
"invalid-port:abc".toServerAddress()
38+
}
39+
40+
assertEquals("Invalid server address: invalid-port:abc", exception.message)
41+
}
42+
43+
@Test
44+
fun `host falls back to empty string when ascii conversion fails`() {
45+
val host = "a".repeat(64)
46+
val serverAddress = ServerAddress(host, 25565)
47+
48+
assertEquals("", serverAddress.host)
49+
assertEquals(25565, serverAddress.port)
50+
}
51+
52+
@Test
53+
fun `creates InetSocketAddress`() {
54+
val serverAddress = "example.net:1337".toServerAddress()
55+
56+
val socketAddress = InetSocketAddress(serverAddress)
57+
58+
assertEquals("example.net", socketAddress.hostString)
59+
assertEquals(1337, socketAddress.port)
60+
assertEquals(InetSocketAddress("example.net", 1337), socketAddress)
61+
}
62+
}

surf-cloud-standalone/build.gradle.kts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,15 @@ val sanitizeLibs by tasks.registering {
2121
outDir.mkdirs()
2222

2323
fileTree("libs").matching { include("*.jar") }.files.forEach { inJar ->
24-
// Nur dann neu packen, wenn das JAR den Provider wirklich enthält
2524
val hasProvider = ZipFile(inJar).use { zf ->
2625
zf.getEntry("META-INF/services/org.slf4j.spi.SLF4JServiceProvider") != null ||
2726
zf.getEntry("org/slf4j/simple/SimpleServiceProvider.class") != null
2827
}
2928

3029
val dest = outDir.resolve(inJar.name)
3130
if (!hasProvider) {
32-
// unverändert kopieren
3331
inJar.copyTo(dest, overwrite = true)
3432
} else {
35-
// entpacken -> problematische Einträge ausschließen -> wieder zippen
3633
val tmp = layout.buildDirectory.dir("tmp/sanitize/${inJar.nameWithoutExtension}").get().asFile
3734
tmp.deleteRecursively(); tmp.mkdirs()
3835

@@ -74,14 +71,19 @@ dependencies {
7471
}
7572

7673
// implementation(fileTree("libs/**/*.jar")) // Include all JARs in libs directory
77-
implementation(fileTree(sanitizedLibsDir) { include("*.jar") })
74+
// implementation(fileTree(sanitizedLibsDir) { include("*.jar") })
75+
implementation(fileTree(sanitizedLibsDir) { include("*.jar") }.builtBy(sanitizeLibs))
7876
}
7977

8078
tasks {
81-
assemble {
82-
dependsOn(sanitizeLibs)
83-
inputs.files(sanitizeLibs)
84-
}
79+
// assemble {
80+
// dependsOn(sanitizeLibs)
81+
// inputs.files(sanitizeLibs)
82+
// }
83+
//
84+
// build {
85+
// dependsOn(sanitizeLibs)
86+
// }
8587

8688
bootJar {
8789
mainClass.set("dev.slne.surf.cloud.standalone.Bootstrap")
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package dev.slne.surf.cloud.standalone.commands.impl
2+
3+
import com.mojang.brigadier.Command
4+
import com.mojang.brigadier.CommandDispatcher
5+
import dev.slne.surf.cloud.api.server.command.AbstractConsoleCommand
6+
import dev.slne.surf.cloud.api.server.command.CommandSource
7+
import dev.slne.surf.cloud.api.server.command.ConsoleCommand
8+
import dev.slne.surf.cloud.api.server.command.literal
9+
import dev.slne.surf.surfapi.core.api.messages.adventure.buildText
10+
import net.kyori.adventure.text.Component
11+
import net.kyori.adventure.text.JoinConfiguration
12+
13+
@ConsoleCommand
14+
class HelpCommand : AbstractConsoleCommand() {
15+
override fun register(dispatcher: CommandDispatcher<CommandSource>) {
16+
dispatcher.register(literal("help") {
17+
executes { ctx ->
18+
val smartUsage = dispatcher.getSmartUsage(dispatcher.root, ctx.source)
19+
20+
val message = buildText {
21+
info("Available commands:")
22+
appendNewline()
23+
append(
24+
Component.join(
25+
JoinConfiguration.newlines(),
26+
smartUsage.values.map { usage ->
27+
buildText {
28+
val commandParts = usage.split(" ")
29+
val commandKey = commandParts[0]
30+
val arguments = commandParts.drop(1).joinToString(" ")
31+
32+
variableKey(commandKey)
33+
appendSpace()
34+
spacer(arguments)
35+
}
36+
}
37+
)
38+
)
39+
}
40+
41+
ctx.source.sendMessage(message)
42+
43+
Command.SINGLE_SUCCESS
44+
}
45+
})
46+
}
47+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package dev.slne.surf.cloud.api.common.util.queue
2+
3+
import org.junit.jupiter.api.Assertions.*
4+
import org.junit.jupiter.api.Test
5+
6+
class FairPriorityQueueTest {
7+
@Test
8+
fun `fifo order is preserved when priorities match`() {
9+
val queue = FairPriorityQueue<Int> { _, _ -> 0 }
10+
queue.offer(1)
11+
queue.offer(2)
12+
queue.offer(3)
13+
14+
val order = listOf(queue.poll(), queue.poll(), queue.poll())
15+
16+
assertEquals(listOf(1, 2, 3), order)
17+
assertNull(queue.poll())
18+
}
19+
20+
21+
@Test
22+
fun `addFirst inserts element before others`() {
23+
val queue = FairPriorityQueue<Int>(Comparator.naturalOrder())
24+
queue.offer(5)
25+
queue.offer(10)
26+
27+
queue.addFirst(1)
28+
29+
assertEquals(listOf(1, 5, 10), queue.snapshot().toList())
30+
assertEquals(3, queue.size)
31+
}
32+
33+
@Test
34+
fun `offer null does not modify queue`() {
35+
val queue = FairPriorityQueue<Int>(Comparator.naturalOrder())
36+
37+
assertFalse(queue.offer(null))
38+
assertEquals(0, queue.size)
39+
assertNull(queue.peek())
40+
}
41+
42+
@Test
43+
fun `iterator removal updates backing storage`() {
44+
val queue = FairPriorityQueue<Int>(Comparator.naturalOrder())
45+
queue.offer(3)
46+
queue.offer(1)
47+
queue.offer(2)
48+
49+
val iterator = queue.iterator()
50+
assertTrue(iterator.hasNext())
51+
assertEquals(1, iterator.next())
52+
53+
iterator.remove()
54+
55+
assertEquals(listOf(2, 3), queue.snapshot().toList())
56+
assertEquals(2, queue.size)
57+
}
58+
}

surf-cloud-standalone/src/test/java/dev/slne/surf/cloud/api/common/util/queue/FastFairPriorityQueueTest.kt

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package dev.slne.surf.cloud.api.common.util.queue
22

3-
import org.junit.jupiter.api.Assertions.assertEquals
3+
import org.junit.jupiter.api.Assertions.*
44
import org.junit.jupiter.api.Test
55

66
class FastFairPriorityQueueTest {
@@ -41,4 +41,52 @@ class FastFairPriorityQueueTest {
4141
assertEquals(listOf(1, 2, 3), queue.snapshot().toList())
4242
}
4343

44+
@Test
45+
fun `offer null is ignored`() {
46+
val queue = FastFairPriorityQueue<Int>(Comparator.naturalOrder())
47+
48+
assertFalse(queue.offer(null))
49+
assertEquals(0, queue.size)
50+
assertNull(queue.peek())
51+
}
52+
53+
@Test
54+
fun `poll on empty queue returns null`() {
55+
val queue = FastFairPriorityQueue<Int>(Comparator.naturalOrder())
56+
57+
assertNull(queue.poll())
58+
assertEquals(0, queue.size)
59+
}
60+
61+
@Test
62+
fun `peek does not remove element`() {
63+
val queue = FastFairPriorityQueue<Int>(Comparator.naturalOrder())
64+
queue.offer(4)
65+
queue.offer(2)
66+
67+
val peeked = queue.peek()
68+
69+
assertEquals(2, peeked)
70+
assertEquals(2, queue.size)
71+
assertEquals(2, queue.poll())
72+
}
73+
74+
@Test
75+
fun `iterator provides snapshot view`() {
76+
val queue = FastFairPriorityQueue<Int>(Comparator.naturalOrder())
77+
queue.offer(5)
78+
queue.offer(1)
79+
80+
val iterator = queue.iterator()
81+
82+
queue.offer(3)
83+
84+
val iterated = mutableListOf<Int>()
85+
while (iterator.hasNext()) {
86+
iterated += iterator.next()
87+
}
88+
89+
assertEquals(listOf(1, 5), iterated)
90+
assertEquals(listOf(1, 3, 5), queue.snapshot().toList())
91+
}
4492
}

0 commit comments

Comments
 (0)