Skip to content

Commit 9c44c72

Browse files
committed
JAVA-3065: PreparedStatementIT#should_fail_fast_if_id_changes_on_reprepare fails with recent C*/DSE versions
PreparedStatementIT.java - add multiple backend requirements to should_fail_fast_if_id_changes_on_reprepare covering versions impacted by CASSANDRA-15252 - add handle_id_changes_on_reprepare to test CASSANDRA-15252 for versions which include the fix BackendRequirement.java - new repeatable annotation for specifying multiple ranges of backend requirements for tests VersionRequirementTest.java - tests for multiple ranges of backend requirements refactor BaseCcmRule.java annotation logic and move to VersionRequirements.java remove duplicated annotation code from CcmPaxExam.java and EmbeddedAdsRule
1 parent 2fa0faf commit 9c44c72

File tree

9 files changed

+534
-186
lines changed

9 files changed

+534
-186
lines changed

integration-tests/src/test/java/com/datastax/dse/driver/api/core/auth/EmbeddedAdsRule.java

Lines changed: 18 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@
2020
import com.datastax.oss.driver.api.core.CqlSession;
2121
import com.datastax.oss.driver.api.core.Version;
2222
import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
23-
import com.datastax.oss.driver.api.testinfra.DseRequirement;
2423
import com.datastax.oss.driver.api.testinfra.ccm.CcmBridge;
2524
import com.datastax.oss.driver.api.testinfra.ccm.CustomCcmRule;
25+
import com.datastax.oss.driver.api.testinfra.requirement.BackendType;
26+
import com.datastax.oss.driver.api.testinfra.requirement.VersionRequirement;
2627
import com.datastax.oss.driver.api.testinfra.session.SessionUtils;
2728
import com.datastax.oss.driver.shaded.guava.common.collect.ImmutableMap;
2829
import java.io.File;
30+
import java.util.Collection;
2931
import java.util.HashMap;
3032
import java.util.Map;
3133
import org.junit.AssumptionViolatedException;
@@ -151,50 +153,25 @@ protected void before() {
151153
}
152154
}
153155

154-
private Statement buildErrorStatement(
155-
Version requirement, Version actual, String description, boolean lessThan) {
156-
return new Statement() {
157-
158-
@Override
159-
public void evaluate() {
160-
throw new AssumptionViolatedException(
161-
String.format(
162-
"Test requires %s %s %s but %s is configured. Description: %s",
163-
lessThan ? "less than" : "at least", "DSE", requirement, actual, description));
164-
}
165-
};
166-
}
167-
168156
@Override
169157
public Statement apply(Statement base, Description description) {
170-
DseRequirement dseRequirement = description.getAnnotation(DseRequirement.class);
171-
if (dseRequirement != null) {
172-
if (!CcmBridge.DSE_ENABLEMENT) {
173-
return new Statement() {
174-
@Override
175-
public void evaluate() {
176-
throw new AssumptionViolatedException("Test Requires DSE but C* is configured.");
177-
}
178-
};
179-
} else {
180-
Version dseVersion = CcmBridge.VERSION;
181-
if (!dseRequirement.min().isEmpty()) {
182-
Version minVersion = Version.parse(dseRequirement.min());
183-
if (minVersion.compareTo(dseVersion) > 0) {
184-
return buildErrorStatement(dseVersion, dseVersion, dseRequirement.description(), false);
185-
}
158+
BackendType backend = CcmBridge.DSE_ENABLEMENT ? BackendType.DSE : BackendType.CASSANDRA;
159+
Version version = CcmBridge.VERSION;
160+
161+
Collection<VersionRequirement> requirements = VersionRequirement.fromAnnotations(description);
162+
163+
if (VersionRequirement.meetsAny(requirements, backend, version)) {
164+
return super.apply(base, description);
165+
} else {
166+
// requirements not met, throw reasoning assumption to skip test
167+
return new Statement() {
168+
@Override
169+
public void evaluate() {
170+
throw new AssumptionViolatedException(
171+
VersionRequirement.buildReasonString(requirements, backend, version));
186172
}
187-
188-
if (!dseRequirement.max().isEmpty()) {
189-
Version maxVersion = Version.parse(dseRequirement.max());
190-
191-
if (maxVersion.compareTo(dseVersion) <= 0) {
192-
return buildErrorStatement(dseVersion, dseVersion, dseRequirement.description(), true);
193-
}
194-
}
195-
}
173+
};
196174
}
197-
return super.apply(base, description);
198175
}
199176

200177
@Override

integration-tests/src/test/java/com/datastax/oss/driver/core/cql/PreparedStatementIT.java

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
package com.datastax.oss.driver.core.cql;
1717

1818
import static org.assertj.core.api.Assertions.assertThat;
19-
import static org.assertj.core.api.Assertions.assertThatThrownBy;
19+
import static org.assertj.core.api.Assertions.assertThatCode;
2020
import static org.assertj.core.api.Assertions.catchThrowable;
2121

2222
import com.codahale.metrics.Gauge;
@@ -36,6 +36,8 @@
3636
import com.datastax.oss.driver.api.core.type.DataTypes;
3737
import com.datastax.oss.driver.api.testinfra.CassandraRequirement;
3838
import com.datastax.oss.driver.api.testinfra.ccm.CcmRule;
39+
import com.datastax.oss.driver.api.testinfra.requirement.BackendRequirement;
40+
import com.datastax.oss.driver.api.testinfra.requirement.BackendType;
3941
import com.datastax.oss.driver.api.testinfra.session.SessionRule;
4042
import com.datastax.oss.driver.api.testinfra.session.SessionUtils;
4143
import com.datastax.oss.driver.categories.ParallelizableTests;
@@ -54,6 +56,7 @@
5456
import java.util.concurrent.TimeUnit;
5557
import java.util.function.Consumer;
5658
import junit.framework.TestCase;
59+
import org.assertj.core.api.AbstractThrowableAssert;
5760
import org.junit.Before;
5861
import org.junit.Rule;
5962
import org.junit.Test;
@@ -425,13 +428,11 @@ public void should_create_separate_instances_for_different_statement_parameters(
425428
}
426429

427430
/**
428-
* This test relies on CASSANDRA-15252 to reproduce the error condition. If the bug gets fixed in
429-
* Cassandra, we'll need to add a version restriction.
431+
* This method reproduces CASSANDRA-15252 which is fixed in 3.0.26/3.11.12/4.0.2.
430432
*
431433
* @see <a href="https://issues.apache.org/jira/browse/CASSANDRA-15252">CASSANDRA-15252</a>
432434
*/
433-
@Test
434-
public void should_fail_fast_if_id_changes_on_reprepare() {
435+
private AbstractThrowableAssert<?, ? extends Throwable> assertableReprepareAfterIdChange() {
435436
try (CqlSession session = SessionUtils.newSession(ccmRule)) {
436437
PreparedStatement preparedStatement =
437438
session.prepare(
@@ -444,12 +445,42 @@ public void should_fail_fast_if_id_changes_on_reprepare() {
444445
executeDdl("DROP TABLE prepared_statement_test");
445446
executeDdl("CREATE TABLE prepared_statement_test (a int PRIMARY KEY, b int, c int)");
446447

447-
assertThatThrownBy(() -> session.execute(preparedStatement.bind(1)))
448-
.isInstanceOf(IllegalStateException.class)
449-
.hasMessageContaining("ID mismatch while trying to reprepare");
448+
return assertThatCode(() -> session.execute(preparedStatement.bind(1)));
450449
}
451450
}
452451

452+
// Add version bounds to the DSE requirement if there is a version containing fix for
453+
// CASSANDRA-15252
454+
@BackendRequirement(
455+
type = BackendType.DSE,
456+
description = "No DSE version contains fix for CASSANDRA-15252")
457+
@BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "3.0.0", maxExclusive = "3.0.26")
458+
@BackendRequirement(
459+
type = BackendType.CASSANDRA,
460+
minInclusive = "3.11.0",
461+
maxExclusive = "3.11.12")
462+
@BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0.0", maxExclusive = "4.0.2")
463+
@Test
464+
public void should_fail_fast_if_id_changes_on_reprepare() {
465+
assertableReprepareAfterIdChange()
466+
.isInstanceOf(IllegalStateException.class)
467+
.hasMessageContaining("ID mismatch while trying to reprepare");
468+
}
469+
470+
@BackendRequirement(
471+
type = BackendType.CASSANDRA,
472+
minInclusive = "3.0.26",
473+
maxExclusive = "3.11.0")
474+
@BackendRequirement(
475+
type = BackendType.CASSANDRA,
476+
minInclusive = "3.11.12",
477+
maxExclusive = "4.0.0")
478+
@BackendRequirement(type = BackendType.CASSANDRA, minInclusive = "4.0.2")
479+
@Test
480+
public void handle_id_changes_on_reprepare() {
481+
assertableReprepareAfterIdChange().doesNotThrowAnyException();
482+
}
483+
453484
private void invalidationResultSetTest(Consumer<CqlSession> createFn) {
454485

455486
try (CqlSession session = sessionWithCacheSizeMetric()) {

osgi-tests/src/test/java/com/datastax/oss/driver/internal/osgi/support/CcmPaxExam.java

Lines changed: 17 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@
1818
import static com.datastax.oss.driver.internal.osgi.support.CcmStagedReactor.CCM_BRIDGE;
1919

2020
import com.datastax.oss.driver.api.core.Version;
21-
import com.datastax.oss.driver.api.testinfra.CassandraRequirement;
22-
import com.datastax.oss.driver.api.testinfra.DseRequirement;
23-
import java.util.Objects;
24-
import java.util.Optional;
21+
import com.datastax.oss.driver.api.testinfra.requirement.BackendType;
22+
import com.datastax.oss.driver.api.testinfra.requirement.VersionRequirement;
23+
import java.util.Collection;
2524
import org.junit.AssumptionViolatedException;
2625
import org.junit.runner.Description;
2726
import org.junit.runner.notification.Failure;
@@ -38,69 +37,20 @@ public CcmPaxExam(Class<?> klass) throws InitializationError {
3837
@Override
3938
public void run(RunNotifier notifier) {
4039
Description description = getDescription();
41-
CassandraRequirement cassandraRequirement =
42-
description.getAnnotation(CassandraRequirement.class);
43-
if (cassandraRequirement != null) {
44-
if (!cassandraRequirement.min().isEmpty()) {
45-
Version minVersion = Objects.requireNonNull(Version.parse(cassandraRequirement.min()));
46-
if (minVersion.compareTo(CCM_BRIDGE.getCassandraVersion()) > 0) {
47-
fireRequirementsNotMet(notifier, description, cassandraRequirement.min(), false, false);
48-
return;
49-
}
50-
}
51-
if (!cassandraRequirement.max().isEmpty()) {
52-
Version maxVersion = Objects.requireNonNull(Version.parse(cassandraRequirement.max()));
53-
if (maxVersion.compareTo(CCM_BRIDGE.getCassandraVersion()) <= 0) {
54-
fireRequirementsNotMet(notifier, description, cassandraRequirement.max(), true, false);
55-
return;
56-
}
57-
}
58-
}
59-
DseRequirement dseRequirement = description.getAnnotation(DseRequirement.class);
60-
if (dseRequirement != null) {
61-
Optional<Version> dseVersionOption = CCM_BRIDGE.getDseVersion();
62-
if (!dseVersionOption.isPresent()) {
63-
notifier.fireTestAssumptionFailed(
64-
new Failure(
65-
description,
66-
new AssumptionViolatedException("Test Requires DSE but C* is configured.")));
67-
return;
68-
} else {
69-
Version dseVersion = dseVersionOption.get();
70-
if (!dseRequirement.min().isEmpty()) {
71-
Version minVersion = Objects.requireNonNull(Version.parse(dseRequirement.min()));
72-
if (minVersion.compareTo(dseVersion) > 0) {
73-
fireRequirementsNotMet(notifier, description, dseRequirement.min(), false, true);
74-
return;
75-
}
76-
}
77-
if (!dseRequirement.max().isEmpty()) {
78-
Version maxVersion = Objects.requireNonNull(Version.parse(dseRequirement.max()));
79-
if (maxVersion.compareTo(dseVersion) <= 0) {
80-
fireRequirementsNotMet(notifier, description, dseRequirement.min(), true, true);
81-
return;
82-
}
83-
}
84-
}
85-
}
86-
super.run(notifier);
87-
}
40+
BackendType backend =
41+
CCM_BRIDGE.getDseVersion().isPresent() ? BackendType.DSE : BackendType.CASSANDRA;
42+
Version version = CCM_BRIDGE.getDseVersion().orElseGet(CCM_BRIDGE::getCassandraVersion);
8843

89-
private void fireRequirementsNotMet(
90-
RunNotifier notifier,
91-
Description description,
92-
String requirement,
93-
boolean lessThan,
94-
boolean dse) {
95-
AssumptionViolatedException e =
96-
new AssumptionViolatedException(
97-
String.format(
98-
"Test requires %s %s %s but %s is configured. Description: %s",
99-
lessThan ? "less than" : "at least",
100-
dse ? "DSE" : "C*",
101-
requirement,
102-
dse ? CCM_BRIDGE.getDseVersion().orElse(null) : CCM_BRIDGE.getCassandraVersion(),
103-
description));
104-
notifier.fireTestAssumptionFailed(new Failure(description, e));
44+
Collection<VersionRequirement> requirements =
45+
VersionRequirement.fromAnnotations(getDescription());
46+
if (VersionRequirement.meetsAny(requirements, backend, version)) {
47+
super.run(notifier);
48+
} else {
49+
// requirements not met, throw reasoning assumption to skip test
50+
AssumptionViolatedException e =
51+
new AssumptionViolatedException(
52+
VersionRequirement.buildReasonString(requirements, backend, version));
53+
notifier.fireTestAssumptionFailed(new Failure(description, e));
54+
}
10555
}
10656
}

test-infra/src/main/java/com/datastax/oss/driver/api/testinfra/ccm/BaseCcmRule.java

Lines changed: 17 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@
1818
import com.datastax.oss.driver.api.core.DefaultProtocolVersion;
1919
import com.datastax.oss.driver.api.core.ProtocolVersion;
2020
import com.datastax.oss.driver.api.core.Version;
21-
import com.datastax.oss.driver.api.testinfra.CassandraRequirement;
2221
import com.datastax.oss.driver.api.testinfra.CassandraResourceRule;
23-
import com.datastax.oss.driver.api.testinfra.DseRequirement;
22+
import com.datastax.oss.driver.api.testinfra.requirement.BackendType;
23+
import com.datastax.oss.driver.api.testinfra.requirement.VersionRequirement;
24+
import java.util.Collection;
2425
import java.util.Optional;
2526
import org.junit.AssumptionViolatedException;
2627
import org.junit.runner.Description;
@@ -55,80 +56,26 @@ protected void after() {
5556
ccmBridge.remove();
5657
}
5758

58-
private Statement buildErrorStatement(
59-
Version requirement, String description, boolean lessThan, boolean dse) {
60-
return new Statement() {
61-
62-
@Override
63-
public void evaluate() {
64-
throw new AssumptionViolatedException(
65-
String.format(
66-
"Test requires %s %s %s but %s is configured. Description: %s",
67-
lessThan ? "less than" : "at least",
68-
dse ? "DSE" : "C*",
69-
requirement,
70-
dse ? ccmBridge.getDseVersion().orElse(null) : ccmBridge.getCassandraVersion(),
71-
description));
72-
}
73-
};
74-
}
75-
7659
@Override
7760
public Statement apply(Statement base, Description description) {
78-
// If test is annotated with CassandraRequirement or DseRequirement, ensure configured CCM
79-
// cluster meets those requirements.
80-
CassandraRequirement cassandraRequirement =
81-
description.getAnnotation(CassandraRequirement.class);
61+
BackendType backend =
62+
ccmBridge.getDseVersion().isPresent() ? BackendType.DSE : BackendType.CASSANDRA;
63+
Version version = ccmBridge.getDseVersion().orElseGet(ccmBridge::getCassandraVersion);
8264

83-
if (cassandraRequirement != null) {
84-
// if the configured cassandra cassandraRequirement exceeds the one being used skip this test.
85-
if (!cassandraRequirement.min().isEmpty()) {
86-
Version minVersion = Version.parse(cassandraRequirement.min());
87-
if (minVersion.compareTo(ccmBridge.getCassandraVersion()) > 0) {
88-
return buildErrorStatement(minVersion, cassandraRequirement.description(), false, false);
89-
}
90-
}
65+
Collection<VersionRequirement> requirements = VersionRequirement.fromAnnotations(description);
9166

92-
if (!cassandraRequirement.max().isEmpty()) {
93-
// if the test version exceeds the maximum configured one, fail out.
94-
Version maxVersion = Version.parse(cassandraRequirement.max());
95-
96-
if (maxVersion.compareTo(ccmBridge.getCassandraVersion()) <= 0) {
97-
return buildErrorStatement(maxVersion, cassandraRequirement.description(), true, false);
98-
}
99-
}
100-
}
101-
102-
DseRequirement dseRequirement = description.getAnnotation(DseRequirement.class);
103-
if (dseRequirement != null) {
104-
Optional<Version> dseVersionOption = ccmBridge.getDseVersion();
105-
if (!dseVersionOption.isPresent()) {
106-
return new Statement() {
107-
108-
@Override
109-
public void evaluate() {
110-
throw new AssumptionViolatedException("Test Requires DSE but C* is configured.");
111-
}
112-
};
113-
} else {
114-
Version dseVersion = dseVersionOption.get();
115-
if (!dseRequirement.min().isEmpty()) {
116-
Version minVersion = Version.parse(dseRequirement.min());
117-
if (minVersion.compareTo(dseVersion) > 0) {
118-
return buildErrorStatement(minVersion, dseRequirement.description(), false, true);
119-
}
120-
}
121-
122-
if (!dseRequirement.max().isEmpty()) {
123-
Version maxVersion = Version.parse(dseRequirement.max());
124-
125-
if (maxVersion.compareTo(dseVersion) <= 0) {
126-
return buildErrorStatement(maxVersion, dseRequirement.description(), true, true);
127-
}
67+
if (VersionRequirement.meetsAny(requirements, backend, version)) {
68+
return super.apply(base, description);
69+
} else {
70+
// requirements not met, throw reasoning assumption to skip test
71+
return new Statement() {
72+
@Override
73+
public void evaluate() {
74+
throw new AssumptionViolatedException(
75+
VersionRequirement.buildReasonString(requirements, backend, version));
12876
}
129-
}
77+
};
13078
}
131-
return super.apply(base, description);
13279
}
13380

13481
public Version getCassandraVersion() {

0 commit comments

Comments
 (0)