All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.stargate.it.cql.BoundStatementTest Maven / Gradle / Ivy

package io.stargate.it.cql;

import static io.stargate.it.cql.NowInSecondsTestUtil.testNowInSeconds;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import com.datastax.oss.driver.api.core.ConsistencyLevel;
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.cql.BoundStatement;
import com.datastax.oss.driver.api.core.cql.ExecutionInfo;
import com.datastax.oss.driver.api.core.cql.PreparedStatement;
import com.datastax.oss.driver.api.core.cql.QueryTrace;
import com.datastax.oss.driver.api.core.cql.ResultSet;
import com.datastax.oss.driver.api.core.cql.Row;
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
import com.datastax.oss.driver.api.core.data.ByteUtils;
import com.datastax.oss.driver.api.core.servererrors.InvalidQueryException;
import com.datastax.oss.driver.api.core.servererrors.ProtocolError;
import io.stargate.it.BaseIntegrationTest;
import io.stargate.it.driver.CqlSessionExtension;
import io.stargate.it.driver.CqlSessionSpec;
import io.stargate.it.driver.WithProtocolVersion;
import io.stargate.it.storage.SkipWhenDse;
import io.stargate.it.storage.StargateConnectionInfo;
import io.stargate.it.storage.StargateEnvironmentInfo;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

/**
 * Note: all tests related to unset values assume that the protocol version is always 4 or higher.
 */
@ExtendWith(CqlSessionExtension.class)
@CqlSessionSpec(
    initQueries = {
      // table where every column forms the primary key.
      "CREATE TABLE IF NOT EXISTS test (k text, v int, PRIMARY KEY(k, v))",
      // table with simple primary key, single cell.
      "CREATE TABLE IF NOT EXISTS test2 (k text primary key, v0 int)",
      // table with composite partition key
      "CREATE TABLE IF NOT EXISTS test3 (pk1 int, pk2 int, v int, PRIMARY KEY ((pk1, pk2)))",
      NowInSecondsTestUtil.SCHEMA,
    })
public abstract class BoundStatementTest extends BaseIntegrationTest {

  private static final String KEY = "test";
  private static final int VALUE = 7;

  @BeforeEach
  public void cleanupData(CqlSession session) {
    session.execute("TRUNCATE test");
    session.execute("TRUNCATE test2");
    session.execute("TRUNCATE test3");
    session.execute("TRUNCATE " + NowInSecondsTestUtil.TABLE_NAME);

    for (int i = 0; i < 100; i++) {
      session.execute(
          SimpleStatement.builder("INSERT INTO test (k, v) VALUES (?, ?)")
              .addPositionalValues(KEY, i)
              .build());
    }
  }

  @Test
  @DisplayName("Should execute statement with positional values")
  public void positionalValuesTest(CqlSession session) {
    PreparedStatement prepared = session.prepare("INSERT INTO test2 (k, v0) values (?, ?)");
    session.execute(prepared.bind(KEY, VALUE));

    Row row = session.execute("SELECT v0 FROM test2 WHERE k=?", KEY).one();
    assertThat(row.getInt("v0")).isEqualTo(VALUE);
  }

  @Test
  @DisplayName("Should execute statement with named values")
  public void namedValuesTest(CqlSession session) {
    PreparedStatement prepared = session.prepare("INSERT INTO test2 (k, v0) values (:k, :v)");
    session.execute(
        prepared.boundStatementBuilder().setString("k", KEY).setInt("v", VALUE).build());

    Row row = session.execute("SELECT v0 FROM test2 WHERE k=?", KEY).one();
    assertThat(row.getInt("v0")).isEqualTo(VALUE);
  }

  @Test
  @DisplayName("Should allow null values")
  public void nullValuesTest(CqlSession session) {
    PreparedStatement prepared = session.prepare("INSERT INTO test2 (k, v0) values (?, ?)");
    session.execute(prepared.bind(KEY, null));

    Row row = session.execute("SELECT v0 FROM test2 WHERE k=?", KEY).one();
    assertThat(row.isNull("v0")).isTrue();
  }

  @Test
  @DisplayName("Should fail if a value is missing")
  public void missingValueTest(CqlSession session) {
    PreparedStatement prepared = session.prepare("SELECT v FROM test3 WHERE pk1=? and pk2=?");
    assertThatThrownBy(() -> session.execute(prepared.bind(1)))
        .isInstanceOf(InvalidQueryException.class);
  }

  @Test
  @DisplayName("Should not write tombstone if value is implicitly unset")
  public void implicitUnsetTest(CqlSession session) {
    PreparedStatement prepared = session.prepare("INSERT INTO test2 (k, v0) values (?, ?)");
    session.execute(prepared.bind(KEY, VALUE));

    BoundStatement boundStatement = prepared.bind(KEY);
    assertThat(boundStatement.isSet("v0")).isFalse();
    session.execute(boundStatement);

    Row row = session.execute("SELECT v0 FROM test2 WHERE k=?", KEY).one();
    assertThat(row.getInt("v0")).isEqualTo(VALUE);
  }

  @Test
  @DisplayName("Should not write tombstone if value is explicitly unset")
  public void explicitUnsetTest(CqlSession session) {
    PreparedStatement prepared = session.prepare("INSERT INTO test2 (k, v0) values (?, ?)");
    BoundStatement boundStatement = prepared.bind(KEY, VALUE);
    session.execute(boundStatement);

    session.execute(boundStatement.unset("v0"));

    Row row = session.execute("SELECT v0 FROM test2 WHERE k=?", KEY).one();
    assertThat(row.getInt("v0")).isEqualTo(VALUE);
  }

  @Test
  @DisplayName("Should execute statement with custom page size")
  public void pageSizeTest(CqlSession session) {
    PreparedStatement prepared =
        session.prepare(
            SimpleStatement.newInstance("SELECT v FROM test WHERE k=?").setPageSize(20));
    BoundStatement statement = prepared.bind(KEY);
    ResultSet resultSet = session.execute(statement);
    assertThat(resultSet.getAvailableWithoutFetching()).isEqualTo(20);

    statement = statement.copy(resultSet.getExecutionInfo().getPagingState());
    resultSet = session.execute(statement);

    assertThat(resultSet.iterator().next().getInt("v")).isEqualTo(20);
  }

  @Test
  @DisplayName("Should fail if the paging state is corrupted")
  public void corruptPagingStateTest(CqlSession session) {
    PreparedStatement prepared = session.prepare("SELECT v FROM test WHERE k=?");
    BoundStatement statement =
        prepared
            .boundStatementBuilder(KEY)
            .setPagingState(ByteUtils.fromHexString("0x1234"))
            .build();
    assertThatThrownBy(() -> session.execute(statement)).isInstanceOf(ProtocolError.class);
  }

  @Test
  @DisplayName("Should execute statement with custom query timestamp")
  public void queryTimestampTest(CqlSession session) {
    long timestamp = 10; // whatever
    session.execute(
        SimpleStatement.builder("INSERT INTO test2 (k, v0) values ('test', 1)")
            .setQueryTimestamp(timestamp)
            .build());

    Row row = session.execute("SELECT writetime(v0) FROM test2 WHERE k = 'test'").one();
    assertThat(row).isNotNull();
    assertThat(row.getLong(0)).isEqualTo(timestamp);
  }

  @Test
  @DisplayName("Should execute statement with tracing and retrieve trace")
  public void tracingTest(CqlSession session, StargateEnvironmentInfo stargate) {
    PreparedStatement prepared = session.prepare("SELECT v FROM test WHERE k=?");
    BoundStatement statement = prepared.bind(KEY);

    ExecutionInfo executionInfo = session.execute(statement).getExecutionInfo();
    assertThat(executionInfo.getTracingId()).isNull();

    executionInfo = session.execute(statement.setTracing(true)).getExecutionInfo();
    assertThat(executionInfo.getTracingId()).isNotNull();
    QueryTrace queryTrace = executionInfo.getQueryTrace();
    assertThat(queryTrace).isNotNull();
    assertThat(stargate.nodes())
        .extracting(StargateConnectionInfo::seedAddress)
        .contains(queryTrace.getCoordinatorAddress().getAddress().getHostAddress());
    assertThat(queryTrace.getRequestType()).isEqualTo("Execute CQL3 prepared query");
    assertThat(queryTrace.getEvents()).isNotEmpty();
  }

  @Test
  @DisplayName("Should use statement-level consistency levels")
  public void consistencyLevelsTest(CqlSession session) {
    PreparedStatement prepared = session.prepare("SELECT v FROM test WHERE k=?");
    BoundStatement statement = prepared.bind(KEY).setTracing(true);
    QueryTrace queryTrace = session.execute(statement).getExecutionInfo().getQueryTrace();
    // Driver defaults
    assertThat(queryTrace.getParameters().get("consistency_level")).isEqualTo("LOCAL_ONE");
    assertThat(queryTrace.getParameters().get("serial_consistency_level")).isEqualTo("SERIAL");

    statement =
        statement
            .setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM)
            // Irrelevant for that query, but we just want to check that it gets reflected in the
            // trace
            .setSerialConsistencyLevel(ConsistencyLevel.LOCAL_SERIAL);
    queryTrace = session.execute(statement).getExecutionInfo().getQueryTrace();
    assertThat(queryTrace.getParameters().get("consistency_level")).isEqualTo("LOCAL_QUORUM");
    assertThat(queryTrace.getParameters().get("serial_consistency_level"))
        .isEqualTo("LOCAL_SERIAL");
  }

  @WithProtocolVersion("V4")
  public static class WithV4ProtocolVersionTest extends BoundStatementTest {}

  @WithProtocolVersion("V5")
  public static class WithV5ProtocolVersionTest extends BoundStatementTest {
    @Test
    @DisplayName("Should use setNowInSeconds() with bound statement")
    @SkipWhenDse
    public void nowInSecondsTest(CqlSession session) {
      testNowInSeconds(
          queryString -> {
            PreparedStatement preparedStatement = session.prepare(queryString);
            return preparedStatement.bind();
          },
          session);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy