Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions driver-core/src/main/java/com/datastax/driver/core/Requests.java
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ public String toString() {

static class Execute extends Message.Request {

public static final byte[] EMPTY_BYTES = new byte[0];

static final Message.Coder<Execute> coder =
new Message.Coder<Execute>() {
@Override
Expand All @@ -233,17 +235,23 @@ public void encode(
ProtocolVersion version,
ProtocolFeatureStore featureStore) {
CBUtil.writeShortBytes(msg.statementId.bytes, dest);
if (ProtocolFeatures.PREPARED_METADATA_CHANGES.isSupportedBy(version, featureStore))
CBUtil.writeShortBytes(msg.resultMetadataId.bytes, dest);
if (ProtocolFeatures.PREPARED_METADATA_CHANGES.isSupportedBy(version, featureStore)) {
byte[] bytes =
msg.resultMetadataId != null ? msg.resultMetadataId.bytes : EMPTY_BYTES;
CBUtil.writeShortBytes(bytes, dest);
}
msg.options.encode(dest, version);
}

@Override
public int encodedSize(
Execute msg, ProtocolVersion version, ProtocolFeatureStore featureStore) {
int size = CBUtil.sizeOfShortBytes(msg.statementId.bytes);
if (ProtocolFeatures.PREPARED_METADATA_CHANGES.isSupportedBy(version, featureStore))
size += CBUtil.sizeOfShortBytes(msg.resultMetadataId.bytes);
if (ProtocolFeatures.PREPARED_METADATA_CHANGES.isSupportedBy(version, featureStore)) {
byte[] bytes =
msg.resultMetadataId != null ? msg.resultMetadataId.bytes : EMPTY_BYTES;
size += CBUtil.sizeOfShortBytes(bytes);
}
size += msg.options.encodedSize(version);
return size;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,11 @@ public void beforeTestClass() throws Exception {
* @throws Exception
*/
public void beforeTestClass(Object testInstance) throws Exception {
// Check for class-level skip conditions before setting up CCM cluster
// Workaround for testng 6.13.x bug ensuring that test clusters are not created for skipped
// tests
TestListener.checkForSkipConditions(testInstance.getClass());

testMode = determineTestMode(testInstance.getClass());
if (testMode == PER_CLASS) {
closer = Closer.create();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.datastax.driver.core;

import static org.testng.Assert.assertEquals;

import com.datastax.driver.core.utils.Bytes;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class RequestsTest {

public static class ExecuteTest {

@Test(groups = "unit", dataProvider = "shouldProperlyEncodeMessages")
void should_properly_encode_messages(
MD5Digest resultMetadataId,
ProtocolVersion protocolVersion,
ProtocolFeatureStore protocolFeatureStore,
int expectedSize) {
// given
ByteBuf destination = ByteBufAllocator.DEFAULT.buffer();
Requests.Execute request =
new Requests.Execute(
MD5Digest.wrap(Bytes.fromHexString("0xcafebabe").array()),
resultMetadataId,
Requests.QueryProtocolOptions.DEFAULT,
false);

// when
int size = Requests.Execute.coder.encodedSize(request, protocolVersion, protocolFeatureStore);
Requests.Execute.coder.encode(request, destination, protocolVersion, protocolFeatureStore);

// then
assertEquals(size, expectedSize);
assertEquals(destination.writerIndex(), expectedSize);
}

@DataProvider
Object[][] shouldProperlyEncodeMessages() {
return new Object[][] {
{
MD5Digest.wrap(Bytes.fromHexString("0xdeadbeef").array()),
ProtocolVersion.V4,
new ProtocolFeatureStore(null, null, null, false),
9
},
{
MD5Digest.wrap(Bytes.fromHexString("0xdeadbeef").array()),
ProtocolVersion.V4,
new ProtocolFeatureStore(null, null, null, true),
15
},
{null, ProtocolVersion.V4, new ProtocolFeatureStore(null, null, null, true), 11},
{
MD5Digest.wrap(Bytes.fromHexString("0xdeadbeef").array()),
ProtocolVersion.V5,
new ProtocolFeatureStore(null, null, null, false),
18
},
{null, ProtocolVersion.V5, new ProtocolFeatureStore(null, null, null, false), 14},
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,6 @@ public class TestListener extends TestListenerAdapter implements IInvokedMethodL

@Override
public void onTestFailure(ITestResult tr) {
if (tr.getThrowable() instanceof SkipException) {
// Workaround for testng 6.13.x bug https://github.com/testng-team/testng/issues/1632
// When SkipException thrown from beforeInvocation marks test as FAILED
tr.setStatus(ITestResult.SKIP);
return;
}
long elapsedTime = TimeUnit.NANOSECONDS.toSeconds((System.nanoTime() - start_time));
long testTime = tr.getEndMillis() - tr.getStartMillis();
tr.getThrowable().printStackTrace();
Expand Down Expand Up @@ -120,19 +114,34 @@ public void beforeInvocation(IInvokedMethod testMethod, ITestResult testResult)
ITestNGMethod testNgMethod = testResult.getMethod();
ConstructorOrMethod constructorOrMethod = testNgMethod.getConstructorOrMethod();

Class<?> clazz = testNgMethod.getInstance().getClass();
if (clazz != null) {
try {
Class<?> clazz = testNgMethod.getInstance().getClass();
do {
if (scanAnnotatedElement(clazz)) break;
// Check for skip conditions and break early if version annotations are found
if (checkForSkipConditions(clazz)) break;
} while (!(clazz = clazz.getSuperclass()).equals(Object.class));
}
Method method = constructorOrMethod.getMethod();
if (method != null) {
scanAnnotatedElement(method);
Method method = constructorOrMethod.getMethod();
if (method != null) {
checkForSkipConditions(method); // Don't need return value for methods
}
} catch (SkipException e) {
// Workaround for testng 6.13.x bug https://github.com/testng-team/testng/issues/1632
// When SkipException thrown from beforeInvocation marks test as FAILED
// Instead of letting TestNG handle it, we manually set the skip status
testResult.setStatus(ITestResult.SKIP);
testResult.setThrowable(e);
testResult.setEndMillis(System.currentTimeMillis());
// Don't re-throw the exception to avoid the bug
}
}

private boolean scanAnnotatedElement(AnnotatedElement element) {
/**
* Static method to check for skip conditions on a class or method. Throws SkipException if the
* element should be skipped.
*
* @return true if version-related annotations were found (to break early in class hierarchy scan)
*/
public static boolean checkForSkipConditions(AnnotatedElement element) {
if (CCMBridge.getGlobalScyllaVersion() != null) {
if (element.isAnnotationPresent(ScyllaSkip.class)) {
throw new SkipException("Skipping test because it is disabled for Scylla cluster.");
Expand All @@ -158,8 +167,6 @@ private boolean scanAnnotatedElement(AnnotatedElement element) {
throw new SkipException(
"Skipping test because it is designed for DSE only, but running on Scylla cluster.");
}

return false;
} else if (CCMBridge.isDse()) {
if (element.isAnnotationPresent(ScyllaOnly.class)) {
throw new SkipException("Skipping test because it is enabled only for Scylla cluster.");
Expand All @@ -181,31 +188,28 @@ private boolean scanAnnotatedElement(AnnotatedElement element) {
throw new SkipException(
"Skipping test because it is designed for Scylla only, but running on DSE cluster.");
}
} else {
if (element.isAnnotationPresent(ScyllaOnly.class)) {
throw new SkipException("Skipping test because it is enabled only for Scylla cluster.");
}

return false;
}

if (element.isAnnotationPresent(ScyllaOnly.class)) {
throw new SkipException("Skipping test because it is enabled only for Scylla cluster.");
}

if (element.isAnnotationPresent(CassandraVersion.class)) {
CassandraVersion cassandraVersion = element.getAnnotation(CassandraVersion.class);
cassandraVersionCheck(cassandraVersion);
return true;
}
if (element.isAnnotationPresent(CassandraVersion.class)) {
CassandraVersion cassandraVersion = element.getAnnotation(CassandraVersion.class);
cassandraVersionCheck(cassandraVersion);
return true;
}

if (element.isAnnotationPresent(ScyllaVersion.class)) {
throw new SkipException(
"Skipping test because it is designed for Scylla only, but running on Cassandra cluster.");
}
if (element.isAnnotationPresent(ScyllaVersion.class)) {
throw new SkipException(
"Skipping test because it is designed for Scylla only, but running on Cassandra cluster.");
}

if (element.isAnnotationPresent(DseVersion.class)) {
throw new SkipException(
"Skipping test because it is designed for DSE only, but running on Cassandra cluster.");
if (element.isAnnotationPresent(DseVersion.class)) {
throw new SkipException(
"Skipping test because it is designed for DSE only, but running on Cassandra cluster.");
}
}

return false;
return false; // No version annotations found, continue scanning
}

@Override
Expand Down