Skip to content
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

Update Cassandra driver to 4.x #2830

Merged
merged 11 commits into from Aug 4, 2022

Conversation

emerkle826
Copy link
Contributor

This PR updates the Cassandra driver to the newer 4.x version. It should address #2768.

@rnorth
Copy link
Member

rnorth commented Jul 4, 2020

I'm a bit uncomfortable with this causing a breaking change in our APIs and transitive dependencies, but I'm not sure I can see any other way around it (short of adding an entire new class that uses the Cassandra 4.x drivers).

Will post a suggestion as a comment, though.

Comment on lines 162 to 198
public static Cluster getCluster(ContainerState containerState, boolean enableJmxReporting) {
final Cluster.Builder builder = Cluster.builder()
.addContactPoint(containerState.getHost())
.withPort(containerState.getMappedPort(CQL_PORT));
if (!enableJmxReporting) {
builder.withoutJMXReporting();
}
public static CqlSession getSession(ContainerState containerState) {
final CqlSessionBuilder builder = CqlSession.builder()
.addContactPoint(new InetSocketAddress(containerState.getHost(), containerState.getMappedPort(CQL_PORT)))
.withLocalDatacenter(DATACENTER);
return builder.build();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning a third-party class from our convenience method is what's now given us this breaking change headache. It's a pattern we're trying to avoid with new modules for this exact reason.

Could we consider eliminating com.datastax.* types from the API of this class?

e.g.:

  • delete the old getCluster() method as you've done
  • do not add a getSession method
  • add a new getContactPoint() method that simply returns an InetSocketAddress, and a getDataCenter() method that returns the DATACENTER constant

It would be slightly more work for users, e.g. they would have to do:

final CqlSessionBuilder builder = CqlSession.builder()
            .addContactPoint(myCassandraContainer.getContactPoint())
            .withLocalDatacenter(myCassandraContainer.getDatacenter());
        return builder.build();

but our public API from this class would just consist of JDK types, and we'd never have to make breaking changes again should (for example) the cassandra driver change classes/package names in v5.

If we're going to have to have a breaking change here, why not do it in a way that avoids future breaking changes?

BTW you'll notice I'm suggesting this be instance methods, not static methods - I am really quite surprised that these were ever static methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rnorth Thank you for the review and the comments!
I see your point about Testcontainers concerns and I think you are right. I'm a bit tied up with a few other things at the moment, but I will revisit this as soon as I can and try to implement the changes you suggest. I'll also try to update the Cassandra Testcontainer documentation if necessary.

@rnorth rnorth added the type/breaking-api-change Public APIs are being changed label Jul 5, 2020
@emerkle826
Copy link
Contributor Author

I'm a bit uncomfortable with this causing a breaking change in our APIs and transitive dependencies, but I'm not sure I can see any other way around it (short of adding an entire new class that uses the Cassandra 4.x drivers).

Will post a suggestion as a comment, though.

@rnorth I've taken a second stab at this. Instead of removing the existing Driver 3.x API, I've chosen to deprecate the methods that return its Cluster object, while adding the new methods you suggested. This prevents introducing a breaking change for now, and provides a tiny convenience for using the container with Driver 4.x. I also updated the docs to demonstrate the new way of using it with the different driver versions.

However, I have left CassandraDatabaseDelegate and CassandraQueryWaitStrategy alone for now as I'm not sure the best solution to make either of those Driver agnostic. A solution could be to deprecate/remove the delegate and wait strategy, and maybe add more documentation of how to do it with each of the drivers. Or, I could duplicate everything you have currently and provide Driver 4 versions of the same classes. But I believe that is not really in the interests of Testcontainers, and probably creates more confusion that it does good.

cassandraContainer.start();
// Trying to build a CqlSession will fail if a Contact Point is specified,
// but Local Datacenter is omitted.
CqlSession.builder().addContactPoint(cassandraContainer.getContactPoint()).build();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe instead of @Test(expected = IllegalStateException.class), we could do a more detailed verification by catching an exception and validating that the exception message contains contact-points string? Or use AssertJ assertThatThrownBy

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* @return The configured local Datacenter name.
* @see #withLocalDatacenter(java.lang.String)
*/
public String getLocalDatacenter() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice that you added it, it was missing before.

@stale
Copy link

stale bot commented Jan 24, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you believe this is a mistake, please reply to this comment to keep it open. If there isn't one already, a PR to fix or at least reproduce the problem in a test case will always help us get back on track to tackle this.

@stale stale bot added the stale label Jan 24, 2021
@michaelyaakoby
Copy link

I'm using the changes from this pull-request for many months already so we can test using latest cassandra driver.
Unless testcontainers already added this support, it would be strange if this PR is closed.

Maybe I or others can help with this?

@stale stale bot removed the stale label Jan 24, 2021
@pluttrell
Copy link

@rnorth Soft ping. Wondering what it would take to get this to the finish line? I'd love to start using it.

private static final String CONTAINER_CONFIG_LOCATION = "/etc/cassandra";
private static final String USERNAME = "cassandra";
private static final String PASSWORD = "cassandra";

private String configLocation;
private String initScriptPath;
private boolean enableJmxReporting;
private String localDatacenter;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this variable seems to be write-only. It does not end up in container's configuration (e.g. environment variable). Let's either make it affect the container or remove.

@@ -29,13 +30,15 @@
public static final String IMAGE = "cassandra";

public static final Integer CQL_PORT = 9042;
public static final String DEFAULT_LOCAL_DATACENTER = "datacenter1";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public static final String DEFAULT_LOCAL_DATACENTER = "datacenter1";
private static final String DEFAULT_LOCAL_DATACENTER = "datacenter1";

@@ -166,14 +178,23 @@ public String getPassword() {
}

/**
* Get configured Cluster
* Get configured Session
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Suggested change
* Get configured Session
* Get configured Cluster

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no more Cluster vs Session distinction in driver4. Your only entry point is the session, now called CqlSession. The word "cluster" becomes meaningless.

Copy link
Member

@bsideup bsideup Feb 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this only applies to v4, while in v3 (the currently used types that we're deprecating) it remains Cluster.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops you are right, my bad.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, one of my first commits for this changed getCluster() to getSession(), but that was reverted. I just forgot to revert the comment change.

@@ -25,8 +25,7 @@
@Override
protected Session createNewConnection() {
try {
return CassandraContainer.getCluster(container)
.newSession();
return CassandraContainer.getCluster(container).newSession();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's revert this non-relevant change to reduce the changeset

@@ -23,11 +27,13 @@

private static final String TEST_CLUSTER_NAME_IN_CONF = "Test Cluster Integration Test";

private static final String BAISC_QUERY = "SELECT release_version FROM system.local";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo, BAISC_QUERY -> BASIC_QUERY

}

@Test
public void testMissingLocalDatacenter() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems to be testing the driver, not the container. Let's remove it

@eddumelendez eddumelendez added type/enhancement and removed type/breaking-api-change Public APIs are being changed labels Jul 14, 2022
@eddumelendez eddumelendez added this to the next milestone Jul 14, 2022
dependencies {
testImplementation 'org.testcontainers:cassandra'
testImplementation 'junit:junit:4.13.2'
// testRuntimeOnly 'com.datastax.cassandra:cassandra-driver-core:3.10.0'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// testRuntimeOnly 'com.datastax.cassandra:cassandra-driver-core:3.10.0'

Not needed, or?

eddumelendez and others added 2 commits July 28, 2022 10:16
@eddumelendez eddumelendez requested a review from kiview July 28, 2022 18:10
@eddumelendez eddumelendez mentioned this pull request Aug 1, 2022
16 tasks
@kiview kiview merged commit c38ba11 into testcontainers:master Aug 4, 2022
@kiview
Copy link
Member

kiview commented Aug 4, 2022

Merged, thank you @emerkle826 and everyone collaborating on this 🙂

@nikeee
Copy link

nikeee commented Aug 4, 2022

Thank you!

@kiview kiview removed the type/docs label Aug 19, 2022
@akhaku
Copy link
Contributor

akhaku commented Sep 7, 2022

Many thanks! Looking forward to picking this up after the next release

akhaku added a commit to akhaku/testcontainers-java that referenced this pull request Oct 14, 2022
With testcontainers#2830 we added support for 4.x of the Cassandra driver.
It was done in a way to allow a user to use either the 3.x
or 4.x driver while excluding the other one. However if
using 4.x and excluding 3.x, GenericContainer#canBeReused
throws an exception during reflection since the Cluster
class returned by CassandraContainer#getCluster is missing.

This PR works around that issue by catching and ignoring
the thrown NoClassDefFoundError.
akhaku added a commit to akhaku/testcontainers-java that referenced this pull request Oct 14, 2022
With testcontainers#2830 we added some environment variable setup to the
constructor in CassandraContainer. This causes problems in
scenarios where users customize the environment themselves
or customize the values in cassandra.yaml, so move this init
to a protected method to facilitate overriding.
eddumelendez pushed a commit that referenced this pull request Oct 14, 2022
…5990)

With #2830 we added support for 4.x of the Cassandra driver.
It was done in a way to allow a user to use either the 3.x
or 4.x driver while excluding the other one. However if
using 4.x and excluding 3.x, GenericContainer#canBeReused
throws an exception during reflection since the Cluster
class returned by CassandraContainer#getCluster is missing.

This PR works around that issue by catching and ignoring
the thrown NoClassDefFoundError.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet