Implement Clickhouse containers for JDBC (mysql/Yandex) and Mysql-binary-access#4038
Implement Clickhouse containers for JDBC (mysql/Yandex) and Mysql-binary-access#4038codepitbull wants to merge 9 commits intotestcontainers:mainfrom
Conversation
…Mysql-binary-access
|
|
||
| public static final Integer HTTP_PORT = 8123; | ||
| public static final Integer NATIVE_PORT = 9000; | ||
| public class ClickHouseContainer<SELF extends ClickHouseContainer<SELF>> extends GenericContainer<SELF> { |
There was a problem hiding this comment.
It's okay and more consistent with other modern modules to leave out the generic type here.
There was a problem hiding this comment.
Also, removing extends JdbcDatabaseContainer is a breaking change - please revert
There was a problem hiding this comment.
This is probably a naming messup on my side.
There are now 3 containers:
ClickHouseContainerJdbcMysql (extends JdbcDatabaseContainer) => Requires the mysql-driver to work
ClickHouseContainerJdbcYandex (extends JdbcDatabaseContainer) => Requires the yandex-driver to work
ClickHouseContainer => Not a JDBC container since it is used to test via the raw wire protocl (mysql) and the http api, this shouldn't rely on having a JDBC driver on the path.
What would you suggest naming wise?
There was a problem hiding this comment.
The naming is okay, just we can't drop the parent class like that - not everyone starts containers with the JDBC URL integration, some may have used it as var ch = new ClickHouseContainer(); ch.start(); ch.getJdbcUrl()
kiview
left a comment
There was a problem hiding this comment.
Hey @codepitbull, sorry for taking our time with this PR.
PR looks pretty good, just having some general remarks.
I was wondering if the 3 different classes like this are really necessary, or if we couldn't just use a single class and its type configurable (with the type just resulting in a different value for driverClassName after all). But maybe I am missing something, I have no experience with Clickhouse and look at it purely from the Testcontainers perspective.
| @Override | ||
| public Set<Integer> getLivenessCheckPortNumbers() { | ||
| return Sets.newHashSet(HTTP_PORT); | ||
| return Sets.newHashSet(ClickHouseInit.HTTP_PORT); |
There was a problem hiding this comment.
| return Sets.newHashSet(ClickHouseInit.HTTP_PORT); | |
| return Collections.singleton(ClickHouseInit.HTTP_PORT); |
| public String getTestQueryString() { | ||
| return TEST_QUERY; | ||
| return ClickHouseInit.TEST_QUERY; | ||
| } |
There was a problem hiding this comment.
This method is not necessary anymore if the class does not extend JdbcContainer anymore. Maybe we deprecate it in this PR or remove it?
| public static final String databaseName = "default"; | ||
| public static final String username = "default"; | ||
| public static final String password = ""; |
There was a problem hiding this comment.
Because I have been doing Go for too long ... geez, how stuff like that seeps into daily coding.
Will change.
|
|
||
| import java.time.Duration; | ||
|
|
||
| public class ClickHouseInit { |
There was a problem hiding this comment.
In this class, we should only make the constants public that need to be public and keep the rest package-protected. The class itself can also be package-protected, or?
There was a problem hiding this comment.
Main reason this class isn't package-protected is that I was trying to follow the package layout you picked which moves the junit-tests into a dedicated folder.
From there I can't access the class to get the constants for testing.
If you are ok with merging the packages I can make it protected.
| new HttpWaitStrategy() | ||
| .forStatusCode(200) | ||
| .forPort(HTTP_PORT) | ||
| .forResponsePredicate(responseBody -> "Ok.".equals(responseBody)) |
There was a problem hiding this comment.
Is this response important if we already get 200 status code?
There was a problem hiding this comment.
I prefer to be strict with these (bad experiences with APIs returning 200 but with a failure message).
In our own driver we check for the "Ok." reply since it is explicitly mentioned in the clickhouse docs as the return value that indicates success.
There was a problem hiding this comment.
I am not sure I share the preference :) It seems to be a free text value, not even some structured response (e.g. JSON).
I would rely on ClickHouse devs being the good folks who understand the meaning of 200 and would never return 200 in case of an error :)
| @Override | ||
| public boolean supports(String databaseType) { | ||
| return databaseType.equals(ClickHouseContainer.NAME); | ||
| return databaseType.equals(ClickHouseInit.JDBC_NAME_YANDEX) || databaseType.equals(ClickHouseInit.JDBC_NAME_MYSQL); |
There was a problem hiding this comment.
Wouldn't this collide with the normal mysql JDBC URL if someone has both modules on the classpath? In this case, they would get either container.
There was a problem hiding this comment.
It would be interesting to see what happens in this case, but I think it's a good point. I wonder if we should:
(a) make the ContainerDatabaseDriver fail fast in this scenario, or
(b) require a different string to be used, e.g. tc:clickhousemysql. This seems less nice though, as it breaks an implicit contract about use of tc: in URLs.
There was a problem hiding this comment.
While (a) sounds reasonable (and I wonder why we decided to return any matching container in case of collision) how would a user that has both dependencies on their classpath (for a valid reason) deal with this? Our tests would also fail, or?
| clickhouse.start(); | ||
| public void testRawMysql() throws Throwable { | ||
| ClickHouseContainer clickHouseContainer = new ClickHouseContainer(); | ||
| clickHouseContainer.start(); |
There was a problem hiding this comment.
Why did you remove the try-with-resource? We use this to close the container after the test.
|
|
||
| ResultSet resultSet = performQuery(clickhouse, "SELECT 1"); | ||
| MySQLConnectOptions connectOptions = new MySQLConnectOptions() | ||
| .setPort(clickHouseContainer.getMappedPort(ClickHouseInit.MYSQL_PORT)) |
There was a problem hiding this comment.
I feel like having the constant in ClickHousInit makes it a bit harder to discover for users.
There was a problem hiding this comment.
The constants are shared between all three.
What do you think about adding this to ClickHouseContainer?
public Integer getHttpPort() {
return getMappedPort(ClickHouseInit.HTTP_PORT);
}
public Integer getNativePort() {
return getMappedPort(ClickHouseInit.NATIVE_PORT);
}
public Integer getMysqlPort() {
return getMappedPort(ClickHouseInit.MYSQL_PORT);
}
|
|
||
| public static final String DEFAULT_TAG = "21.3.8.76"; | ||
|
|
||
| public static void Init(GenericContainer<?> container) { |
There was a problem hiding this comment.
we don't do this in Java =P
| public static void Init(GenericContainer<?> container) { | |
| public static void init(GenericContainer<?> container) { |
|
|
||
| import org.testcontainers.utility.DockerImageName; | ||
|
|
||
| public abstract class AbstractClickHouseContainerJdbc extends JdbcDatabaseContainer { |
There was a problem hiding this comment.
| public abstract class AbstractClickHouseContainerJdbc extends JdbcDatabaseContainer { | |
| abstract class AbstractClickHouseContainerJdbc extends JdbcDatabaseContainer { |
|
|
||
| @Override | ||
| public AbstractClickHouseContainerJdbc withUrlParam(String paramName, String paramValue) { | ||
| throw new UnsupportedOperationException("The ClickHouse does not support this"); |
There was a problem hiding this comment.
I think it does support a couple of parameters, btw :D Perhaps this PR is a nice opportunity to fix this 👍
There was a problem hiding this comment.
Ahh, yes, good point.
|
@codepitbull after reviewing the PR, I got a feeling that it can be done in a much easier way. We could keep the original The This way we can dramatically reduce the size of this PR, avoid breaking changes and keep it simple (eg no need for |
@kiview see my answer in the other thread: |
Should be possible, but it will take a while until I get to this. |
|
Closing due to there is no progress on this. |
Why ?
The current implementation of the Clickhouse-Container only supports the Yandex-JDBC-driver and enforces it to be on the classpath.
It also doesn't export trhe MYSQL-port available in Clickhouse.
The base image includedd is also relying on an old version of Clickhouse that was missing some compatibility fixes for the MySQL-JDBC-driver.
Since I also wanted to test the Vert.x MySQL-driver against Clickhouse I needed to fix these things.
What ?
This PR provides the following things: