Skip to content

Commit 8cb2732

Browse files
jimonthebarnyusufugurozbek
authored andcommitted
Move responsibilities for DataSourceUrl Creation and Matching to DataSourceUrl
*
1 parent 90f4279 commit 8cb2732

File tree

4 files changed

+129
-51
lines changed

4 files changed

+129
-51
lines changed

src/main/kotlin/com/github/yusufugurozbek/testcontainers/port/updater/DataSourceUrl.kt

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,48 @@
11
package com.github.yusufugurozbek.testcontainers.port.updater
22

3+
import com.github.yusufugurozbek.testcontainers.port.updater.settings.MatchMode
4+
import com.github.yusufugurozbek.testcontainers.port.updater.settings.MatchMode.*
5+
import com.intellij.database.dataSource.LocalDataSource
6+
import com.intellij.database.util.common.isNotNullOrEmpty
7+
38
data class DataSourceUrl(val beforePort: String, val port: String, val afterPort: String?) {
9+
10+
11+
companion object {
12+
private var dataSourceUrlExtractor: DataSourceUrlExtractor = DataSourceUrlExtractor()
13+
14+
fun from(dataSource: LocalDataSource): DataSourceUrl? = from(dataSource.url)
15+
16+
fun from(url: String?): DataSourceUrl? {
17+
return url?.takeIf { it.isNotNullOrEmpty }
18+
?.let { dataSourceUrlExtractor.extract(it)?.let(::toDataSourceUrl) }
19+
}
20+
21+
private fun toDataSourceUrl(matchResult: MatchResult?): DataSourceUrl? {
22+
val groups = matchResult?.groups
23+
val beforePort = groups?.get("beforePort")?.value
24+
val port = groups?.get("port")?.value
25+
val afterPort = groups?.get("afterPort")?.value
26+
27+
return if (beforePort != null && port != null) {
28+
DataSourceUrl(beforePort, port, afterPort)
29+
} else {
30+
null
31+
}
32+
}
33+
}
34+
35+
fun matches(other: DataSourceUrl, matchMode: MatchMode): Boolean =
36+
when (matchMode) {
37+
EXACT -> this.equalsIgnoringPort(other)
38+
EVERYTHING -> this.beforePort == other.beforePort
39+
WITH_TESTCONTAINERS_PARAMETER ->
40+
this.toString().contains("testcontainers=true") and
41+
(this.beforePort == other.beforePort)
42+
}
43+
44+
private fun equalsIgnoringPort(other: DataSourceUrl): Boolean =
45+
(this.beforePort == other.beforePort) and (this.afterPort == other.afterPort)
46+
447
override fun toString(): String = "$beforePort:$port$afterPort"
548
}
6-
7-
fun DataSourceUrl.equalsIgnoringPort(other: DataSourceUrl): Boolean =
8-
(this.beforePort == other.beforePort) and (this.afterPort == other.afterPort)
Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,11 @@
11
package com.github.yusufugurozbek.testcontainers.port.updater
22

3-
import com.intellij.database.dataSource.LocalDataSource
4-
53
class DataSourceUrlExtractor {
64

75
companion object {
86
private val regex: Regex = "\\s*(?<beforePort>.*):(?<port>\\d{1,5})(?<afterPort>.*;\\S*|\\S*)".toRegex()
97
}
108

11-
internal fun extract(from: String): DataSourceUrl? {
12-
val matchResult = regex.find(from)
13-
return toDataSourceUrl(matchResult)
14-
}
15-
16-
internal fun toDataSourceUrl(from: LocalDataSource): DataSourceUrl? {
17-
if (from.url.isNullOrEmpty()) {
18-
return null
19-
}
20-
val matchResult = regex.find(from.url!!)
21-
return toDataSourceUrl(matchResult)
22-
}
23-
24-
private fun toDataSourceUrl(matchResult: MatchResult?): DataSourceUrl? {
25-
if (matchResult == null) {
26-
return null
27-
}
9+
fun extract(from: String?): MatchResult? = from?.let { regex.find(from) }
2810

29-
val beforePort = matchResult.groups["beforePort"]
30-
val port = matchResult.groups["port"]
31-
32-
if (beforePort == null || port == null) {
33-
return null
34-
}
35-
36-
val beforePortValue = beforePort.value
37-
val portValue = port.value
38-
val afterPortValue = matchResult.groups["afterPort"]?.value
39-
40-
return DataSourceUrl(beforePortValue, portValue, afterPortValue)
41-
}
4211
}

src/main/kotlin/com/github/yusufugurozbek/testcontainers/port/updater/impl/DataSourceUpdaterImpl.kt

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
package com.github.yusufugurozbek.testcontainers.port.updater.impl
22

33
import com.github.yusufugurozbek.testcontainers.port.updater.DataSourceUrl
4-
import com.github.yusufugurozbek.testcontainers.port.updater.DataSourceUrlExtractor
54
import com.github.yusufugurozbek.testcontainers.port.updater.api.DataSourceUpdater
65
import com.github.yusufugurozbek.testcontainers.port.updater.common.TpuNotifier
7-
import com.github.yusufugurozbek.testcontainers.port.updater.equalsIgnoringPort
86
import com.github.yusufugurozbek.testcontainers.port.updater.settings.LoggingFormat
9-
import com.github.yusufugurozbek.testcontainers.port.updater.settings.MatchMode
107
import com.github.yusufugurozbek.testcontainers.port.updater.settings.TpuSettingsState
118
import com.intellij.database.dataSource.LocalDataSource
129
import com.intellij.openapi.components.service
@@ -18,15 +15,16 @@ import kotlinx.serialization.json.jsonPrimitive
1815

1916
class DataSourceUpdaterImpl(private var project: Project) : DataSourceUpdater {
2017

21-
private var urlExtractor: DataSourceUrlExtractor = DataSourceUrlExtractor()
18+
2219
private var settingsState: TpuSettingsState = project.service()
2320

2421
override fun update(localDataSources: List<LocalDataSource>, logEntryText: String) {
2522
val logEntry = getLogMessage(logEntryText)
2623

2724
val splitLogEntry = logEntry.split(settingsState.logEntryPrefix)
2825
if (splitLogEntry.size == 2) {
29-
urlExtractor.extract(splitLogEntry[1])?.let { logEntryDataSourceUrl ->
26+
val message = splitLogEntry[1]
27+
DataSourceUrl.from(message)?.let { logEntryDataSourceUrl ->
3028
localDataSources
3129
.filter { it.url != logEntryDataSourceUrl.toString() }
3230
.forEach { update(it, logEntryDataSourceUrl) }
@@ -46,22 +44,16 @@ class DataSourceUpdaterImpl(private var project: Project) : DataSourceUpdater {
4644
}
4745

4846
private fun update(localDataSource: LocalDataSource, logEntryDataSourceUrl: DataSourceUrl) {
49-
val localDataSourceUrl = urlExtractor.toDataSourceUrl(localDataSource) ?: return
47+
val dataSourceUrl = DataSourceUrl.from(localDataSource) ?: return
5048

51-
if (localDataSourceUrl.port == logEntryDataSourceUrl.port) {
49+
if (dataSourceUrl.port == logEntryDataSourceUrl.port) {
5250
return
5351
}
5452

55-
val isUpdatable = when (settingsState.matchMode) {
56-
MatchMode.EXACT -> localDataSourceUrl.equalsIgnoringPort(logEntryDataSourceUrl)
57-
MatchMode.EVERYTHING -> localDataSourceUrl.beforePort == logEntryDataSourceUrl.beforePort
58-
MatchMode.WITH_TESTCONTAINERS_PARAMETER ->
59-
localDataSourceUrl.toString().contains("testcontainers=true") and
60-
(localDataSourceUrl.beforePort == logEntryDataSourceUrl.beforePort)
61-
}
53+
val isUpdatable = dataSourceUrl.matches(logEntryDataSourceUrl, settingsState.matchMode)
6254

6355
if (isUpdatable) {
64-
val newUrl = localDataSourceUrl.toString().replace(localDataSourceUrl.port, logEntryDataSourceUrl.port)
56+
val newUrl = dataSourceUrl.toString().replace(dataSourceUrl.port, logEntryDataSourceUrl.port)
6557
localDataSource.url = newUrl
6658
if (settingsState.isNotificationsEnabled) {
6759
TpuNotifier.notify(project, "Updated data source URL: $newUrl")

src/test/kotlin/com/github/yusufugurozbek/testcontainers/port/updater/DataSourceUrlTest.kt

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.github.yusufugurozbek.testcontainers.port.updater
22

3+
import com.github.yusufugurozbek.testcontainers.port.updater.settings.MatchMode
34
import com.intellij.testFramework.UsefulTestCase
45

56
internal class DataSourceUrlTest : UsefulTestCase() {
@@ -21,6 +22,82 @@ internal class DataSourceUrlTest : UsefulTestCase() {
2122
fun `test DataSourceUrl toString successfully returns full URL`() {
2223
val dataSourceUrl = DataSourceUrl("beforePort", "port", "?afterPort")
2324

24-
assertEquals(dataSourceUrl.toString(), "beforePort:port?afterPort")
25+
assertEquals("beforePort:port?afterPort", dataSourceUrl.toString())
26+
}
27+
28+
fun `test datasource from string successfully returns result`() {
29+
val result = DataSourceUrl.from("jdbc:postgresql://localhost:11111/test")!!
30+
31+
assertEquals("jdbc:postgresql://localhost", result.beforePort)
32+
assertEquals("11111", result.port)
33+
assertEquals("/test", result.afterPort)
34+
}
35+
36+
fun `test datasource from string returns null on null input`() {
37+
val result = DataSourceUrl.from(null)
38+
39+
assertNull(result)
40+
}
41+
42+
fun `test datasource from string returns null on empty input`() {
43+
val result = DataSourceUrl.from("")
44+
45+
assertNull(result)
46+
}
47+
48+
fun `test matchMode EXACT successfully returns true for matching urls`() {
49+
val dataSourceUrlA = DataSourceUrl("beforePort", "port", "afterPort")
50+
val dataSourceUrlB = DataSourceUrl("beforePort", "port", "afterPort")
51+
52+
assertTrue(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.EXACT))
53+
}
54+
55+
fun `test matchMode EXACT returns false for not matching beforePort`() {
56+
val dataSourceUrlA = DataSourceUrl("beforePort", "port", "afterPort")
57+
val dataSourceUrlB = DataSourceUrl("beforePortNoMatch", "port", "afterPort")
58+
59+
assertFalse(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.EXACT))
60+
}
61+
62+
fun `test matchMode EXACT returns true if everything but port matches`() {
63+
val dataSourceUrlA = DataSourceUrl("beforePort", "port", "afterPort")
64+
val dataSourceUrlB = DataSourceUrl("beforePort", "portNoMatch", "afterPort")
65+
66+
assertTrue(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.EXACT))
67+
}
68+
69+
fun `test matchMode EXACT returns false for not matching afterPort`() {
70+
val dataSourceUrlA = DataSourceUrl("beforePort", "port", "afterPort")
71+
val dataSourceUrlB = DataSourceUrl("beforePort", "port", "afterPortNoMatch")
72+
73+
assertFalse(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.EXACT))
74+
}
75+
76+
fun `test matchMode EVERYTHING successfully returns true if beforePort matches`() {
77+
val dataSourceUrlA = DataSourceUrl("beforePort", "portA", "afterPortA")
78+
val dataSourceUrlB = DataSourceUrl("beforePort", "portB", "afterPortB")
79+
80+
assertTrue(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.EVERYTHING))
81+
}
82+
83+
fun `test matchMode EVERYTHING returns false for not matching beforePort`() {
84+
val dataSourceUrlA = DataSourceUrl("beforePort", "port", "afterPort")
85+
val dataSourceUrlB = DataSourceUrl("beforePortNoMatch", "port", "afterPort")
86+
87+
assertFalse(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.EVERYTHING))
88+
}
89+
90+
fun `test matchMode WITH_TESTCONTAINERS_PARAMETER successfully returns true for matching beforePort and afterPort containing testcontainers=true`() {
91+
val dataSourceUrlA = DataSourceUrl("beforePort", "dontCareA", "testcontainers=true")
92+
val dataSourceUrlB = DataSourceUrl("beforePort", "dontCareB", "dontCareC")
93+
94+
assertTrue(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.WITH_TESTCONTAINERS_PARAMETER))
95+
}
96+
97+
fun `test matchMode WITH_TESTCONTAINERS_PARAMETER returns false for missing afterPort containing testcontainers=true`() {
98+
val dataSourceUrlA = DataSourceUrl("beforePort", "port", "afterPort")
99+
val dataSourceUrlB = DataSourceUrl("beforePort", "port", "afterPort")
100+
101+
assertFalse(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.WITH_TESTCONTAINERS_PARAMETER))
25102
}
26103
}

0 commit comments

Comments
 (0)