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

test(go/adbc/driver/snowflake): fix flaky integration tests #1561

Merged
merged 12 commits into from
Feb 23, 2024
111 changes: 108 additions & 3 deletions c/driver/snowflake/snowflake_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <nanoarrow/nanoarrow.h>
#include <algorithm>
#include <cstring>
#include <random>
#include "validation/adbc_validation.h"
#include "validation/adbc_validation_util.h"

Expand All @@ -35,6 +36,26 @@ using adbc_validation::IsOkStatus;
} \
} while (false)

namespace {
std::string GetUuid() {
static std::random_device dev;
static std::mt19937 rng(dev());

std::uniform_int_distribution<int> dist(0, 15);

const char* v = "0123456789ABCDEF";
const bool dash[] = {0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0};

std::string res;
for (int i = 0; i < 16; i++) {
if (dash[i]) res += "-";
res += v[dist(rng)];
res += v[dist(rng)];
}
return res;
}
} // namespace

class SnowflakeQuirks : public adbc_validation::DriverQuirks {
public:
SnowflakeQuirks() {
Expand All @@ -47,6 +68,13 @@ class SnowflakeQuirks : public adbc_validation::DriverQuirks {
AdbcStatusCode SetupDatabase(struct AdbcDatabase* database,
struct AdbcError* error) const override {
EXPECT_THAT(AdbcDatabaseSetOption(database, "uri", uri_, error), IsOkStatus(error));
EXPECT_THAT(AdbcDatabaseSetOption(
database, "adbc.snowflake.sql.client_option.use_high_precision",
"false", error),
IsOkStatus(error));
EXPECT_THAT(AdbcDatabaseSetOption(database, "adbc.snowflake.sql.schema",
schema_.c_str(), error),
IsOkStatus(error));
return ADBC_STATUS_OK;
}

Expand Down Expand Up @@ -119,11 +147,13 @@ class SnowflakeQuirks : public adbc_validation::DriverQuirks {
bool supports_metadata_current_db_schema() const override { return false; }
bool supports_partitioned_data() const override { return false; }
bool supports_dynamic_parameter_binding() const override { return false; }
bool supports_error_on_incompatible_schema() const override { return false; }
bool ddl_implicit_commit_txn() const override { return true; }
std::string db_schema() const override { return "ADBC_TESTING"; }
std::string db_schema() const override { return schema_; }

const char* uri_;
bool skip_{false};
std::string schema_{"ADBC_TESTING"};
};

class SnowflakeTest : public ::testing::Test, public adbc_validation::DatabaseTest {
Expand Down Expand Up @@ -175,6 +205,7 @@ class SnowflakeStatementTest : public ::testing::Test,
public adbc_validation::StatementTest {
public:
const adbc_validation::DriverQuirks* quirks() const override { return &quirks_; }

void SetUp() override {
if (quirks_.skip_) {
GTEST_SKIP();
Expand All @@ -192,6 +223,78 @@ class SnowflakeStatementTest : public ::testing::Test,

void TestSqlIngestColumnEscaping() { GTEST_SKIP(); }

public:
// will need to be updated to SetUpTestSuite when gtest is upgraded
static void SetUpTestCase() {
struct AdbcError error;
struct AdbcDatabase db;
struct AdbcConnection connection;
struct AdbcStatement statement;

std::memset(&error, 0, sizeof(error));
std::memset(&db, 0, sizeof(db));
std::memset(&connection, 0, sizeof(connection));
std::memset(&statement, 0, sizeof(statement));

ASSERT_THAT(AdbcDatabaseNew(&db, &error), IsOkStatus(&error));
ASSERT_THAT(quirks_.SetupDatabase(&db, &error), IsOkStatus(&error));
ASSERT_THAT(AdbcDatabaseInit(&db, &error), IsOkStatus(&error));

ASSERT_THAT(AdbcConnectionNew(&connection, &error), IsOkStatus(&error));
ASSERT_THAT(AdbcConnectionInit(&connection, &db, &error), IsOkStatus(&error));

std::string schema_name = "ADBC_TESTING_" + GetUuid();
std::string query =
"CREATE SCHEMA IDENTIFIER('\"ADBC_TESTING\".\"" + schema_name + "\"')";

ASSERT_THAT(AdbcStatementNew(&connection, &statement, &error), IsOkStatus(&error));
ASSERT_THAT(AdbcStatementSetSqlQuery(&statement, query.c_str(), &error),
IsOkStatus(&error));
ASSERT_THAT(AdbcStatementExecuteQuery(&statement, nullptr, nullptr, &error),
IsOkStatus(&error));

quirks_.schema_ = schema_name;

ASSERT_THAT(AdbcStatementRelease(&statement, &error), IsOkStatus(&error));
ASSERT_THAT(AdbcConnectionRelease(&connection, &error), IsOkStatus(&error));
ASSERT_THAT(AdbcDatabaseRelease(&db, &error), IsOkStatus(&error));
}

// will need to be updated to TearDownTestSuite when gtest is upgraded
static void TearDownTestCase() {
struct AdbcError error;
struct AdbcDatabase db;
struct AdbcConnection connection;
struct AdbcStatement statement;

std::memset(&error, 0, sizeof(error));
std::memset(&db, 0, sizeof(db));
std::memset(&connection, 0, sizeof(connection));
std::memset(&statement, 0, sizeof(statement));

ASSERT_THAT(AdbcDatabaseNew(&db, &error), IsOkStatus(&error));
ASSERT_THAT(quirks_.SetupDatabase(&db, &error), IsOkStatus(&error));
ASSERT_THAT(AdbcDatabaseInit(&db, &error), IsOkStatus(&error));

ASSERT_THAT(AdbcConnectionNew(&connection, &error), IsOkStatus(&error));
ASSERT_THAT(AdbcConnectionInit(&connection, &db, &error), IsOkStatus(&error));

std::string query =
"DROP SCHEMA IDENTIFIER('\"ADBC_TESTING\".\"" + quirks_.schema_ + "\"')";

ASSERT_THAT(AdbcStatementNew(&connection, &statement, &error), IsOkStatus(&error));
ASSERT_THAT(AdbcStatementSetSqlQuery(&statement, query.c_str(), &error),
IsOkStatus(&error));
ASSERT_THAT(AdbcStatementExecuteQuery(&statement, nullptr, nullptr, &error),
IsOkStatus(&error));

quirks_.schema_ = "ADBC_TESTING";

ASSERT_THAT(AdbcStatementRelease(&statement, &error), IsOkStatus(&error));
ASSERT_THAT(AdbcConnectionRelease(&connection, &error), IsOkStatus(&error));
ASSERT_THAT(AdbcDatabaseRelease(&db, &error), IsOkStatus(&error));
}

protected:
void ValidateIngestedTemporalData(struct ArrowArrayView* values, ArrowType type,
enum ArrowTimeUnit unit,
Expand All @@ -204,7 +307,7 @@ class SnowflakeStatementTest : public ::testing::Test,
expected = {std::nullopt, -42, 0, 42};
break;
case NANOARROW_TIME_UNIT_MILLI:
expected = {std::nullopt, -42000, 0, 42000};
expected = {std::nullopt, -42, 0, 42};
break;
case NANOARROW_TIME_UNIT_MICRO:
expected = {std::nullopt, -42, 0, 42};
Expand All @@ -222,6 +325,8 @@ class SnowflakeStatementTest : public ::testing::Test,
}
}

SnowflakeQuirks quirks_;
static SnowflakeQuirks quirks_;
};

SnowflakeQuirks SnowflakeStatementTest::quirks_;
ADBCV_TEST_STATEMENT(SnowflakeStatementTest)
4 changes: 4 additions & 0 deletions c/validation/adbc_validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ class DriverQuirks {
/// \brief Whether we can get statistics
virtual bool supports_statistics() const { return false; }

/// \brief Whether ingest errors on an incompatible schema or simply performs
/// column matching.
virtual bool supports_error_on_incompatible_schema() const { return true; }

/// \brief Default catalog to use for tests
virtual std::string catalog() const { return ""; }

Expand Down
29 changes: 17 additions & 12 deletions c/validation/adbc_validation_connection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ void ConnectionTest::TestMetadataGetObjectsDbSchemas() {
ASSERT_NO_FATAL_FAILURE(CheckGetObjectsSchema(&reader.schema.value));
ASSERT_NO_FATAL_FAILURE(reader.Next());
ASSERT_NE(nullptr, reader.array->release);
ASSERT_GT(reader.array->length, 0);
ASSERT_GE(reader.array->length, 0);
do {
for (int64_t row = 0; row < reader.array->length; row++) {
struct ArrowArrayView* catalog_db_schemas_list = reader.array_view->children[1];
Expand Down Expand Up @@ -596,19 +596,24 @@ void ConnectionTest::TestMetadataGetObjectsTables() {
ASSERT_NO_FATAL_FAILURE(CheckGetObjectsSchema(&reader.schema.value));
ASSERT_NO_FATAL_FAILURE(reader.Next());
ASSERT_NE(nullptr, reader.array->release);
ASSERT_GT(reader.array->length, 0);

// type: list<db_schema_schema>
struct ArrowArrayView* catalog_db_schemas_list = reader.array_view->children[1];
// type: db_schema_schema (struct)
struct ArrowArrayView* catalog_db_schemas = catalog_db_schemas_list->children[0];
// type: list<table_schema>
struct ArrowArrayView* db_schema_tables_list = catalog_db_schemas->children[1];
// type: table_schema (struct)
struct ArrowArrayView* db_schema_tables = db_schema_tables_list->children[0];

if (expected.second) {
ASSERT_GT(reader.array->length, 0);
} else {
ASSERT_EQ(db_schema_tables->length, 0);
}
bool found_expected_table = false;
do {
for (int64_t row = 0; row < reader.array->length; row++) {
// type: list<db_schema_schema>
struct ArrowArrayView* catalog_db_schemas_list = reader.array_view->children[1];
// type: db_schema_schema (struct)
struct ArrowArrayView* catalog_db_schemas = catalog_db_schemas_list->children[0];
// type: list<table_schema>
struct ArrowArrayView* db_schema_tables_list = catalog_db_schemas->children[1];
// type: table_schema (struct)
struct ArrowArrayView* db_schema_tables = db_schema_tables_list->children[0];

ASSERT_FALSE(ArrowArrayViewIsNull(catalog_db_schemas_list, row))
<< "Row " << row << " should have non-null catalog_db_schemas";

Expand Down Expand Up @@ -670,7 +675,7 @@ void ConnectionTest::TestMetadataGetObjectsTablesTypes() {
ASSERT_NO_FATAL_FAILURE(CheckGetObjectsSchema(&reader.schema.value));
ASSERT_NO_FATAL_FAILURE(reader.Next());
ASSERT_NE(nullptr, reader.array->release);
ASSERT_GT(reader.array->length, 0);
ASSERT_GE(reader.array->length, 0);
bool found_expected_table = false;
do {
for (int64_t row = 0; row < reader.array->length; row++) {
Expand Down
Loading
Loading