Skip to content

Commit 83502b1

Browse files
committed
Coverage
1 parent cf12f0d commit 83502b1

File tree

2 files changed

+42
-17
lines changed

2 files changed

+42
-17
lines changed

src/main/kotlin/io/github/tobi/laa/spring/boot/embedded/redis/ports/PortProvider.kt

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import java.util.concurrent.ConcurrentSkipListSet
77
/**
88
* The default port used by Redis Sentinel.
99
*/
10-
private const val DEFAULT_SENTINEL_PORT: Int = 26379
10+
internal const val DEFAULT_SENTINEL_PORT: Int = 26379
1111

1212
/**
1313
* This offset is used to calculate the port for the Redis cluster bus.
1414
*/
15-
private const val BUS_PORT_OFFSET: Int = 10000
15+
internal const val BUS_PORT_OFFSET: Int = 10000
1616

1717
/**
1818
* Is used for providing free ports for Redis instances.
@@ -26,25 +26,19 @@ internal class PortProvider {
2626
* @param sentinel If `true`, the next free port for a Redis Sentinel instance is provided.
2727
*/
2828
fun next(sentinel: Boolean = false): Int {
29-
return if (sentinel) {
30-
next(DEFAULT_SENTINEL_PORT..REDIS_CLUSTER_MAX_PORT_EXCLUSIVE)
31-
} else {
32-
next(DEFAULT_REDIS_PORT..REDIS_CLUSTER_MAX_PORT_EXCLUSIVE)
33-
}
34-
}
35-
36-
private fun next(candidates: IntRange): Int {
37-
for (candidate in candidates) {
38-
if (portCanBeHandedOut(candidate) && handedOutPorts.add(candidate)) {
29+
val minPort = if (sentinel) DEFAULT_SENTINEL_PORT else DEFAULT_REDIS_PORT
30+
for (candidate in minPort until REDIS_CLUSTER_MAX_PORT_EXCLUSIVE + 1) {
31+
val candidateBusPort = candidate + BUS_PORT_OFFSET
32+
if (portCanBeHandedOut(candidate) && portCanBeHandedOut(candidateBusPort)) {
33+
handedOutPorts.add(candidate)
34+
handedOutPorts.add(candidateBusPort)
3935
return candidate
4036
}
4137
}
4238
throw IllegalStateException("Could not find an available TCP port")
4339
}
4440

4541
private fun portCanBeHandedOut(port: Int): Boolean {
46-
val busPort = port + BUS_PORT_OFFSET
47-
return !handedOutPorts.contains(port) && !handedOutPorts.contains(busPort) &&
48-
PortChecker.available(port) && PortChecker.available(busPort)
42+
return !handedOutPorts.contains(port) && PortChecker.available(port)
4943
}
5044
}

src/test/kotlin/io/github/tobi/laa/spring/boot/embedded/redis/ports/PortProviderTest.kt

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import io.mockk.mockkObject
66
import io.mockk.unmockkObject
77
import org.assertj.core.api.AbstractIntegerAssert
88
import org.assertj.core.api.Assertions.*
9+
import org.assertj.core.api.ListAssert
910
import org.assertj.core.api.ThrowableAssert
1011
import org.junit.jupiter.api.*
1112
import org.junit.jupiter.api.extension.ExtendWith
1213
import org.junit.jupiter.params.ParameterizedTest
1314
import org.junit.jupiter.params.provider.ValueSource
15+
import redis.embedded.Redis.DEFAULT_REDIS_PORT
1416
import java.util.stream.IntStream.range
1517

1618
@ExtendWith(MockKExtension::class)
@@ -77,13 +79,31 @@ internal class PortProviderTest {
7779

7880
@DisplayName("Multiple valid ports should be returned if all ports are free")
7981
@ParameterizedTest(name = "{0} valid ports should be returned")
80-
@ValueSource(ints = [5, 10, 100, 10000])
82+
@ValueSource(ints = [5, 10, 100])
8183
fun freePorts_requestingPorts_returnsValidPorts(nOfPorts: Int) {
8284
givenFreePorts()
8385
whenNextPortsAreRequested(nOfPorts)
8486
thenValidPortsAreReturned(nOfPorts)
8587
}
8688

89+
@Test
90+
@DisplayName("If port 16379 (bus port) is taken, port 6379 should not be handed out")
91+
fun defaultBusPortTaken_requestingPort_skipDefaultPort() {
92+
givenFreePorts()
93+
givenFirstBusPortTaken()
94+
whenNextPortIsRequested()
95+
thenValidPortIsReturned().isNotEqualTo(DEFAULT_REDIS_PORT)
96+
}
97+
98+
@Test
99+
@DisplayName("If a bus port has been handed out, the corresponding Redis port should not be handed out")
100+
fun busPortHandedOut_requestingPort_skipPortWithHandedOutBusPort() {
101+
givenFreePorts()
102+
givenSentinelPortPreviouslyRequested()
103+
whenNextPortsAreRequested(10000)
104+
thenValidPortsAreReturned(10000).doesNotContain(DEFAULT_REDIS_PORT + BUS_PORT_OFFSET)
105+
}
106+
87107
private fun givenSentinel() {
88108
givenSentinel = true
89109
}
@@ -99,6 +119,16 @@ internal class PortProviderTest {
99119
every { PortChecker.available(any()) } returns false
100120
}
101121

122+
private fun givenFirstBusPortTaken() {
123+
val firstBusPort = DEFAULT_REDIS_PORT + BUS_PORT_OFFSET
124+
every { PortChecker.available(eq(firstBusPort)) } returns false
125+
every { PortChecker.available(neq(firstBusPort)) } returns true
126+
}
127+
128+
private fun givenSentinelPortPreviouslyRequested() {
129+
portProvider.next(true)
130+
}
131+
102132
private fun whenNextPortIsRequested() = whenNextPortsAreRequested(1)
103133

104134
private fun whenNextPortsAreRequested(nOfPorts: Int) {
@@ -118,7 +148,7 @@ internal class PortProviderTest {
118148
return assertThat(actualPorts.first())
119149
}
120150

121-
private fun thenValidPortsAreReturned(nOfPorts: Int) {
151+
private fun thenValidPortsAreReturned(nOfPorts: Int): ListAssert<Int> {
122152
assertThatCode(requestPorts!!).doesNotThrowAnyException()
123153
assertThat(actualPorts).hasSize(nOfPorts)
124154
assertThat(actualPorts).isNotEmpty.doesNotHaveDuplicates()
@@ -129,5 +159,6 @@ internal class PortProviderTest {
129159
}
130160
// bus port should have been left free
131161
assertThat(actualPorts).allSatisfy { assertThat(actualPorts).doesNotContain(it + 10000) }
162+
return assertThat(actualPorts)
132163
}
133164
}

0 commit comments

Comments
 (0)