-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Implement Clickhouse containers for JDBC (mysql/Yandex) and Mysql-binary-access #4038
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
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's okay and more consistent with other modern modules to leave out the generic type here.
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.
Will do :)
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.
Also, removing extends JdbcDatabaseContainer is a breaking change - please revert
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is not necessary anymore if the class does not extend JdbcContainer anymore. Maybe we deprecate it in this PR or remove it?
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.
Removed 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why aren't those uppercase?
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.
Because I have been doing Go for too long ... geez, how stuff like that seeps into daily coding.
Will change.
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.
Fixed.
|
|
||
| import java.time.Duration; | ||
|
|
||
| public class ClickHouseInit { |
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
I think #4038 (comment) will make it obsolete
| new HttpWaitStrategy() | ||
| .forStatusCode(200) | ||
| .forPort(HTTP_PORT) | ||
| .forResponsePredicate(responseBody -> "Ok.".equals(responseBody)) |
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.
Is this response important if we already get 200 status code?
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you remove the try-with-resource? We use this to close the container after the test.
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.
Fixed
|
|
||
| ResultSet resultSet = performQuery(clickhouse, "SELECT 1"); | ||
| MySQLConnectOptions connectOptions = new MySQLConnectOptions() | ||
| .setPort(clickHouseContainer.getMappedPort(ClickHouseInit.MYSQL_PORT)) |
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.
I feel like having the constant in ClickHousInit makes it a bit harder to discover for users.
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we don't do this in Java =P
| public static void Init(GenericContainer<?> container) { | |
| public static void init(GenericContainer<?> container) { |
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.
Fixed.
|
|
||
| import org.testcontainers.utility.DockerImageName; | ||
|
|
||
| public abstract class AbstractClickHouseContainerJdbc extends JdbcDatabaseContainer { |
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.
| public abstract class AbstractClickHouseContainerJdbc extends JdbcDatabaseContainer { | |
| abstract class AbstractClickHouseContainerJdbc extends JdbcDatabaseContainer { |
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.
Fixed.
|
|
||
| @Override | ||
| public AbstractClickHouseContainerJdbc withUrlParam(String paramName, String paramValue) { | ||
| throw new UnsupportedOperationException("The ClickHouse does not support this"); |
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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: