-
Notifications
You must be signed in to change notification settings - Fork 4
WiP: Improve matching of DataSourceUrl #260
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: next
Are you sure you want to change the base?
Changes from all commits
8cb2732
7231ad7
b0729a8
ece8105
f5ef42a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,72 @@ | ||
package com.github.yusufugurozbek.testcontainers.port.updater | ||
|
||
data class DataSourceUrl(val beforePort: String, val port: String, val afterPort: String?) { | ||
import com.github.yusufugurozbek.testcontainers.port.updater.settings.MatchMode | ||
import com.github.yusufugurozbek.testcontainers.port.updater.settings.MatchMode.* | ||
import com.intellij.database.dataSource.LocalDataSource | ||
import com.intellij.database.util.common.isNotNullOrEmpty | ||
|
||
data class DataSourceUrl(val beforePort: String, val port: String, val afterPort: String?, private val urlExtractor: DataSourceUrlExtractor) { | ||
|
||
constructor(beforePort: String, port: String, afterPort: String?) : this(beforePort, port, afterPort, DataSourceUrlExtractor()) | ||
|
||
init { | ||
setUrlExtractor(urlExtractor) | ||
} | ||
|
||
companion object { | ||
private lateinit var extractor: DataSourceUrlExtractor | ||
|
||
private fun setUrlExtractor(extractor: DataSourceUrlExtractor) { | ||
if (!::extractor.isInitialized) { | ||
this.extractor = extractor | ||
} | ||
} | ||
|
||
fun from(dataSource: LocalDataSource): DataSourceUrl? = from(dataSource.url) | ||
|
||
fun from(url: String?): DataSourceUrl? { | ||
return url?.takeIf { it.isNotNullOrEmpty } | ||
?.let { extractor.extract(it)?.let(::toDataSourceUrl) } | ||
} | ||
|
||
private fun toDataSourceUrl(matchResult: MatchResult?): DataSourceUrl? { | ||
val groups = matchResult?.groups | ||
val beforePort = groups?.get("beforePort")?.value | ||
val port = groups?.get("port")?.value | ||
val afterPort = groups?.get("afterPort")?.value | ||
|
||
return if (beforePort != null && port != null) { | ||
DataSourceUrl(beforePort, port, afterPort) | ||
} else { | ||
null | ||
} | ||
} | ||
} | ||
|
||
fun matches(other: DataSourceUrl, matchMode: MatchMode): Boolean = | ||
when (matchMode) { | ||
EXACT -> this.equalsIgnoringPort(other) | ||
EVERYTHING -> this.beforePort == other.beforePort | ||
WITH_TESTCONTAINERS_PARAMETER -> | ||
this.toString().contains("testcontainers=true") and | ||
(this.beforePort == other.beforePort) | ||
} | ||
|
||
private fun equalsIgnoringPort(other: DataSourceUrl): Boolean = | ||
(this.beforePort == other.beforePort) and (this.afterPort == other.afterPort) | ||
|
||
override fun equals(other: Any?): Boolean { | ||
if (this === other) return true | ||
if (other !is DataSourceUrl) return false | ||
|
||
return beforePort == other.beforePort && | ||
port == other.port && | ||
afterPort == other.afterPort | ||
} | ||
|
||
override fun hashCode(): Int { | ||
return 31 * beforePort.hashCode() + port.hashCode() + (afterPort?.hashCode() ?: 0) | ||
} | ||
|
||
override fun toString(): String = "$beforePort:$port$afterPort" | ||
} | ||
|
||
fun DataSourceUrl.equalsIgnoringPort(other: DataSourceUrl): Boolean = | ||
(this.beforePort == other.beforePort) and (this.afterPort == other.afterPort) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,11 @@ | ||
package com.github.yusufugurozbek.testcontainers.port.updater | ||
|
||
import com.intellij.database.dataSource.LocalDataSource | ||
|
||
class DataSourceUrlExtractor { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @yusufugurozbek |
||
|
||
companion object { | ||
private val regex: Regex = "\\s*(?<beforePort>.*):(?<port>\\d{1,5})(?<afterPort>.*;\\S*|\\S*)".toRegex() | ||
} | ||
|
||
internal fun extract(from: String): DataSourceUrl? { | ||
val matchResult = regex.find(from) | ||
return toDataSourceUrl(matchResult) | ||
} | ||
|
||
internal fun toDataSourceUrl(from: LocalDataSource): DataSourceUrl? { | ||
if (from.url.isNullOrEmpty()) { | ||
return null | ||
} | ||
val matchResult = regex.find(from.url!!) | ||
return toDataSourceUrl(matchResult) | ||
} | ||
|
||
private fun toDataSourceUrl(matchResult: MatchResult?): DataSourceUrl? { | ||
if (matchResult == null) { | ||
return null | ||
} | ||
fun extract(from: String?): MatchResult? = from?.let { regex.find(from) } | ||
|
||
val beforePort = matchResult.groups["beforePort"] | ||
val port = matchResult.groups["port"] | ||
|
||
if (beforePort == null || port == null) { | ||
return null | ||
} | ||
|
||
val beforePortValue = beforePort.value | ||
val portValue = port.value | ||
val afterPortValue = matchResult.groups["afterPort"]?.value | ||
|
||
return DataSourceUrl(beforePortValue, portValue, afterPortValue) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.github.yusufugurozbek.testcontainers.port.updater | ||
|
||
import com.github.yusufugurozbek.testcontainers.port.updater.settings.MatchMode | ||
import com.intellij.testFramework.UsefulTestCase | ||
import junit.framework.TestCase | ||
import junit.framework.TestCase.* | ||
|
||
internal class DataSourceUrlExtractorTest : UsefulTestCase() { | ||
|
||
private val sut = DataSourceUrlExtractor() | ||
|
||
fun `test parts can be successfully extracted from well formed input`() { | ||
val result = sut.extract("jdbc:postgresql://localhost:11111/test") | ||
|
||
assertEquals("jdbc:postgresql://localhost:11111/test", result?.groups?.get(0)?.value) | ||
assertEquals("jdbc:postgresql://localhost", result?.groups?.get(1)?.value) | ||
assertEquals("11111", result?.groups?.get(2)?.value) | ||
assertEquals("/test", result?.groups?.get(3)?.value) | ||
} | ||
|
||
fun `test extraction of null value returns null`() { | ||
assertNull(sut.extract(null)) | ||
} | ||
|
||
fun `test extraction of empty value returns null`() { | ||
assertNull(sut.extract("")) | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
package com.github.yusufugurozbek.testcontainers.port.updater | ||
|
||
import com.github.yusufugurozbek.testcontainers.port.updater.settings.MatchMode | ||
import com.intellij.testFramework.UsefulTestCase | ||
|
||
internal class DataSourceUrlTest : UsefulTestCase() { | ||
|
@@ -21,6 +22,82 @@ internal class DataSourceUrlTest : UsefulTestCase() { | |
fun `test DataSourceUrl toString successfully returns full URL`() { | ||
val dataSourceUrl = DataSourceUrl("beforePort", "port", "?afterPort") | ||
|
||
assertEquals(dataSourceUrl.toString(), "beforePort:port?afterPort") | ||
assertEquals("beforePort:port?afterPort", dataSourceUrl.toString()) | ||
} | ||
|
||
fun `test datasource from string successfully returns result`() { | ||
val result = DataSourceUrl.from("jdbc:postgresql://localhost:11111/test")!! | ||
|
||
assertEquals("jdbc:postgresql://localhost", result.beforePort) | ||
assertEquals("11111", result.port) | ||
assertEquals("/test", result.afterPort) | ||
} | ||
|
||
fun `test datasource from string returns null on null input`() { | ||
val result = DataSourceUrl.from(null) | ||
|
||
assertNull(result) | ||
} | ||
|
||
fun `test datasource from string returns null on empty input`() { | ||
val result = DataSourceUrl.from("") | ||
|
||
assertNull(result) | ||
} | ||
|
||
fun `test matchMode EXACT successfully returns true for matching urls`() { | ||
val dataSourceUrlA = DataSourceUrl("beforePort", "port", "afterPort") | ||
val dataSourceUrlB = DataSourceUrl("beforePort", "port", "afterPort") | ||
|
||
assertTrue(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.EXACT)) | ||
} | ||
|
||
fun `test matchMode EXACT returns false for not matching beforePort`() { | ||
val dataSourceUrlA = DataSourceUrl("beforePort", "port", "afterPort") | ||
val dataSourceUrlB = DataSourceUrl("beforePortNoMatch", "port", "afterPort") | ||
|
||
assertFalse(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.EXACT)) | ||
} | ||
|
||
fun `test matchMode EXACT returns true if everything but port matches`() { | ||
val dataSourceUrlA = DataSourceUrl("beforePort", "port", "afterPort") | ||
val dataSourceUrlB = DataSourceUrl("beforePort", "portNoMatch", "afterPort") | ||
|
||
assertTrue(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.EXACT)) | ||
} | ||
|
||
fun `test matchMode EXACT returns false for not matching afterPort`() { | ||
val dataSourceUrlA = DataSourceUrl("beforePort", "port", "afterPort") | ||
val dataSourceUrlB = DataSourceUrl("beforePort", "port", "afterPortNoMatch") | ||
|
||
assertFalse(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.EXACT)) | ||
} | ||
|
||
fun `test matchMode EVERYTHING successfully returns true if beforePort matches`() { | ||
val dataSourceUrlA = DataSourceUrl("beforePort", "portA", "afterPortA") | ||
val dataSourceUrlB = DataSourceUrl("beforePort", "portB", "afterPortB") | ||
|
||
assertTrue(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.EVERYTHING)) | ||
} | ||
|
||
fun `test matchMode EVERYTHING returns false for not matching beforePort`() { | ||
val dataSourceUrlA = DataSourceUrl("beforePort", "port", "afterPort") | ||
val dataSourceUrlB = DataSourceUrl("beforePortNoMatch", "port", "afterPort") | ||
|
||
assertFalse(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.EVERYTHING)) | ||
} | ||
|
||
fun `test matchMode WITH_TESTCONTAINERS_PARAMETER successfully returns true for matching beforePort and afterPort containing testcontainers=true`() { | ||
val dataSourceUrlA = DataSourceUrl("beforePort", "dontCareA", "testcontainers=true") | ||
val dataSourceUrlB = DataSourceUrl("beforePort", "dontCareB", "dontCareC") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @yusufugurozbek There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you please check this issue before we discuss it further? |
||
|
||
assertTrue(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.WITH_TESTCONTAINERS_PARAMETER)) | ||
} | ||
|
||
fun `test matchMode WITH_TESTCONTAINERS_PARAMETER returns false for missing afterPort containing testcontainers=true`() { | ||
val dataSourceUrlA = DataSourceUrl("beforePort", "port", "afterPort") | ||
val dataSourceUrlB = DataSourceUrl("beforePort", "port", "afterPort") | ||
|
||
assertFalse(dataSourceUrlA.matches(dataSourceUrlB, MatchMode.WITH_TESTCONTAINERS_PARAMETER)) | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yusufugurozbek
This seems a little convoluted here. The issue I was trying to solve is that for whatever reason the test classes could not find the constructor anymore if i define it it with a default value for the extractor like such: