Skip to content

Commit 5024114

Browse files
committed
Enable mock test (#42)
* Add todo for noauth validation * mock server with token auth Add tests * run same test with both modes * Enable ODBC tests in workflow * Switch current test cases to use FlightSQLODBCTestBase So the tests can be skipped when `TEST_CONNECT_STR` is not set. * Change tests to run on both mock and remote modes Wrap usage of TEST_CONNECT_STR where possible * Rename test fixtures and make connection string functions virtual * Fix lint issue * Attempt to enable ODBC build on Windows platforms * Attempt to fix clang64 and MinGW errors * Attempt to register ODBC * Address James' comments Use constant string for token * use ServerMiddleware to validate token
1 parent 56acbac commit 5024114

9 files changed

Lines changed: 248 additions & 69 deletions

File tree

.github/workflows/cpp.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,10 @@ jobs:
476476
PIPX_BASE_PYTHON: ${{ steps.python-install.outputs.python-path }}
477477
run: |
478478
ci/scripts/install_gcs_testbench.sh default
479+
- name: Register Flight SQL ODBC Driver
480+
shell: cmd
481+
run: |
482+
call "cpp\src\arrow\flight\sql\odbc\install\install_amd64.cmd" ${{github.workspace}}\build\cpp\%ARROW_BUILD_TYPE%\libarrow_flight_sql_odbc.dll
479483
- name: Test
480484
shell: msys2 {0}
481485
run: |

ci/scripts/cpp_test.sh

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,6 @@ case "$(uname)" in
7373
exclude_tests="${exclude_tests}|gandiva-precompiled-test"
7474
exclude_tests="${exclude_tests}|gandiva-projector-test"
7575
exclude_tests="${exclude_tests}|gandiva-utf8-test"
76-
# TODO: Enable ODBC tests
77-
exclude_tests="${exclude_tests}|arrow-connection-test"
7876
ctest_options+=(--exclude-regex "${exclude_tests}")
7977
;;
8078
*)

cpp/cmake_modules/DefineOptions.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ endmacro()
108108

109109
macro(resolve_option_dependencies)
110110
# Arrow Flight SQL ODBC is available only for Windows for now.
111-
if(NOT MSVC_TOOLCHAIN)
111+
if(NOT WIN32)
112112
set(ARROW_FLIGHT_SQL_ODBC OFF)
113113
endif()
114114
if(MSVC_TOOLCHAIN)

cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_auth_method.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ class NoOpAuthMethod : public FlightSqlAuthMethod {
4545
void Authenticate(FlightSqlConnection& connection,
4646
FlightCallOptions& call_options) override {
4747
// Do nothing
48+
49+
// TODO: implement NoOpAuthMethod to validate server address.
50+
// Can use NoOpClientAuthHandler.
51+
// https://github.com/apache/arrow/issues/46733
4852
}
4953
};
5054

cpp/src/arrow/flight/sql/odbc/flight_sql/system_dsn.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ bool DisplayConnectionWindow(void* windowParent, Configuration& config);
4040
* @param windowParent Parent window handle.
4141
* @param config Output configuration, presumed to be empty, it will be using values from
4242
* properties.
43-
* @param config Output properties.
43+
* @param properties Output properties.
4444
* @return True on success and false on fail.
4545
*/
4646
bool DisplayConnectionWindow(void* windowParent, Configuration& config,

cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,25 @@ include_directories(${ODBC_INCLUDE_DIRS})
2121

2222
add_definitions(-DUNICODE=1)
2323

24+
find_package(SQLite3Alt REQUIRED)
25+
26+
set(ARROW_FLIGHT_SQL_MOCK_SERVER_SRCS
27+
../../example/sqlite_sql_info.cc
28+
../../example/sqlite_type_info.cc
29+
../../example/sqlite_statement.cc
30+
../../example/sqlite_statement_batch_reader.cc
31+
../../example/sqlite_server.cc
32+
../../example/sqlite_tables_schema_batch_reader.cc)
33+
2434
add_arrow_test(connection_test
2535
SOURCES
2636
connection_test.cc
2737
odbc_test_suite.cc
2838
odbc_test_suite.h
39+
${ARROW_FLIGHT_SQL_MOCK_SERVER_SRCS}
2940
EXTRA_LINK_LIBS
3041
${ODBC_LIBRARIES}
3142
${ODBCINST}
43+
${SQLite3_LIBRARIES}
3244
arrow_odbc_spi_impl
3345
odbcabstraction)

cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc

Lines changed: 51 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -200,49 +200,51 @@ TEST(SQLSetEnvAttr, TestSQLSetEnvAttrODBCVersionInvalid) {
200200
EXPECT_TRUE(return_set == SQL_ERROR);
201201
}
202202

203-
TEST_F(FlightSQLODBCTestBase, TestSQLGetEnvAttrOutputNTS) {
204-
connect();
203+
TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetEnvAttrOutputNTS) {
204+
this->connect();
205205

206206
SQLINTEGER output_nts;
207207

208-
SQLRETURN return_get = SQLGetEnvAttr(env, SQL_ATTR_OUTPUT_NTS, &output_nts, 0, 0);
208+
SQLRETURN return_get = SQLGetEnvAttr(this->env, SQL_ATTR_OUTPUT_NTS, &output_nts, 0, 0);
209209

210210
EXPECT_TRUE(return_get == SQL_SUCCESS);
211211

212212
EXPECT_EQ(output_nts, SQL_TRUE);
213213

214-
disconnect();
214+
this->disconnect();
215215
}
216216

217-
TEST_F(FlightSQLODBCTestBase, TestSQLGetEnvAttrGetLength) {
217+
TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetEnvAttrGetLength) {
218218
// Test is disabled because call to SQLGetEnvAttr is handled by the driver manager on
219-
// Windows. This test case can be potentionally used on macOS/Linux
219+
// Windows. This test case can be potentially used on macOS/Linux
220220
GTEST_SKIP();
221221

222-
connect();
222+
this->connect();
223223

224224
SQLINTEGER length;
225225

226-
SQLRETURN return_get = SQLGetEnvAttr(env, SQL_ATTR_ODBC_VERSION, nullptr, 0, &length);
226+
SQLRETURN return_get =
227+
SQLGetEnvAttr(this->env, SQL_ATTR_ODBC_VERSION, nullptr, 0, &length);
227228

228229
EXPECT_TRUE(return_get == SQL_SUCCESS);
229230

230231
EXPECT_EQ(length, sizeof(SQLINTEGER));
231232

232-
disconnect();
233+
this->disconnect();
233234
}
234235

235-
TEST_F(FlightSQLODBCTestBase, TestSQLGetEnvAttrNullValuePointer) {
236+
TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetEnvAttrNullValuePointer) {
236237
// Test is disabled because call to SQLGetEnvAttr is handled by the driver manager on
237-
// Windows. This test case can be potentionally used on macOS/Linux
238+
// Windows. This test case can be potentially used on macOS/Linux
238239
GTEST_SKIP();
239-
connect();
240+
this->connect();
240241

241-
SQLRETURN return_get = SQLGetEnvAttr(env, SQL_ATTR_ODBC_VERSION, nullptr, 0, nullptr);
242+
SQLRETURN return_get =
243+
SQLGetEnvAttr(this->env, SQL_ATTR_ODBC_VERSION, nullptr, 0, nullptr);
242244

243245
EXPECT_TRUE(return_get == SQL_ERROR);
244246

245-
disconnect();
247+
this->disconnect();
246248
}
247249

248250
TEST(SQLSetEnvAttr, TestSQLSetEnvAttrOutputNTSValid) {
@@ -292,7 +294,7 @@ TEST(SQLSetEnvAttr, TestSQLSetEnvAttrNullValuePointer) {
292294
EXPECT_TRUE(return_set == SQL_ERROR);
293295
}
294296

295-
TEST(SQLDriverConnect, TestSQLDriverConnect) {
297+
TYPED_TEST(FlightSQLODBCTestBase, TestSQLDriverConnect) {
296298
// ODBC Environment
297299
SQLHENV env;
298300
SQLHDBC conn;
@@ -312,8 +314,7 @@ TEST(SQLDriverConnect, TestSQLDriverConnect) {
312314
EXPECT_TRUE(ret == SQL_SUCCESS);
313315

314316
// Connect string
315-
ASSERT_OK_AND_ASSIGN(std::string connect_str,
316-
arrow::internal::GetEnvVar(TEST_CONNECT_STR));
317+
std::string connect_str = this->getConnectionString();
317318
ASSERT_OK_AND_ASSIGN(std::wstring wconnect_str,
318319
arrow::util::UTF8ToWideString(connect_str));
319320
std::vector<SQLWCHAR> connect_str0(wconnect_str.begin(), wconnect_str.end());
@@ -361,7 +362,7 @@ TEST(SQLDriverConnect, TestSQLDriverConnect) {
361362
EXPECT_TRUE(ret == SQL_SUCCESS);
362363
}
363364

364-
TEST(SQLDriverConnect, TestSQLDriverConnectInvalidUid) {
365+
TEST_F(FlightSQLODBCRemoteTestBase, TestSQLDriverConnectInvalidUid) {
365366
// ODBC Environment
366367
SQLHENV env;
367368
SQLHDBC conn;
@@ -380,11 +381,8 @@ TEST(SQLDriverConnect, TestSQLDriverConnectInvalidUid) {
380381

381382
EXPECT_TRUE(ret == SQL_SUCCESS);
382383

383-
// Connect string
384-
ASSERT_OK_AND_ASSIGN(std::string connect_str,
385-
arrow::internal::GetEnvVar(TEST_CONNECT_STR));
386-
// Append invalid uid to connection string
387-
connect_str += std::string("uid=non_existent_id;");
384+
// Invalid connect string
385+
std::string connect_str = getInvalidConnectionString();
388386

389387
ASSERT_OK_AND_ASSIGN(std::wstring wconnect_str,
390388
arrow::util::UTF8ToWideString(connect_str));
@@ -418,7 +416,7 @@ TEST(SQLDriverConnect, TestSQLDriverConnectInvalidUid) {
418416
EXPECT_TRUE(ret == SQL_SUCCESS);
419417
}
420418

421-
TEST(SQLConnect, TestSQLConnect) {
419+
TYPED_TEST(FlightSQLODBCTestBase, TestSQLConnect) {
422420
// ODBC Environment
423421
SQLHENV env;
424422
SQLHDBC conn;
@@ -438,8 +436,7 @@ TEST(SQLConnect, TestSQLConnect) {
438436
EXPECT_TRUE(ret == SQL_SUCCESS);
439437

440438
// Connect string
441-
ASSERT_OK_AND_ASSIGN(std::string connect_str,
442-
arrow::internal::GetEnvVar(TEST_CONNECT_STR));
439+
std::string connect_str = this->getConnectionString();
443440

444441
// Write connection string content into a DSN,
445442
// must succeed before continuing
@@ -454,7 +451,7 @@ TEST(SQLConnect, TestSQLConnect) {
454451
std::vector<SQLWCHAR> uid0(wuid.begin(), wuid.end());
455452
std::vector<SQLWCHAR> pwd0(wpwd.begin(), wpwd.end());
456453

457-
// Connecting to ODBC server.
454+
// Connecting to ODBC server. Empty uid and pwd should be ignored.
458455
ret = SQLConnect(conn, dsn0.data(), static_cast<SQLSMALLINT>(dsn0.size()), uid0.data(),
459456
static_cast<SQLSMALLINT>(uid0.size()), pwd0.data(),
460457
static_cast<SQLSMALLINT>(pwd0.size()));
@@ -488,7 +485,7 @@ TEST(SQLConnect, TestSQLConnect) {
488485
EXPECT_TRUE(ret == SQL_SUCCESS);
489486
}
490487

491-
TEST(SQLConnect, TestSQLConnectInputUidPwd) {
488+
TEST_F(FlightSQLODBCRemoteTestBase, TestSQLConnectInputUidPwd) {
492489
// ODBC Environment
493490
SQLHENV env;
494491
SQLHDBC conn;
@@ -508,10 +505,9 @@ TEST(SQLConnect, TestSQLConnectInputUidPwd) {
508505
EXPECT_TRUE(ret == SQL_SUCCESS);
509506

510507
// Connect string
511-
ASSERT_OK_AND_ASSIGN(std::string connect_str,
512-
arrow::internal::GetEnvVar(TEST_CONNECT_STR));
508+
std::string connect_str = getConnectionString();
513509

514-
// Retrieve valid uid and pwd
510+
// Retrieve valid uid and pwd, assumes TEST_CONNECT_STR contains uid and pwd
515511
Connection::ConnPropertyMap properties;
516512
ODBC::ODBCConnection::getPropertiesFromConnString(connect_str, properties);
517513
std::string uid_key("uid");
@@ -567,7 +563,7 @@ TEST(SQLConnect, TestSQLConnectInputUidPwd) {
567563
EXPECT_TRUE(ret == SQL_SUCCESS);
568564
}
569565

570-
TEST(SQLConnect, TestSQLConnectInvalidUid) {
566+
TEST_F(FlightSQLODBCRemoteTestBase, TestSQLConnectInvalidUid) {
571567
// ODBC Environment
572568
SQLHENV env;
573569
SQLHDBC conn;
@@ -587,10 +583,9 @@ TEST(SQLConnect, TestSQLConnectInvalidUid) {
587583
EXPECT_TRUE(ret == SQL_SUCCESS);
588584

589585
// Connect string
590-
ASSERT_OK_AND_ASSIGN(std::string connect_str,
591-
arrow::internal::GetEnvVar(TEST_CONNECT_STR));
586+
std::string connect_str = getConnectionString();
592587

593-
// Retrieve valid uid and pwd
588+
// Retrieve valid uid and pwd, assumes TEST_CONNECT_STR contains uid and pwd
594589
Connection::ConnPropertyMap properties;
595590
ODBC::ODBCConnection::getPropertiesFromConnString(connect_str, properties);
596591
std::string uid = properties[std::string("uid")];
@@ -636,7 +631,7 @@ TEST(SQLConnect, TestSQLConnectInvalidUid) {
636631
EXPECT_TRUE(ret == SQL_SUCCESS);
637632
}
638633

639-
TEST(SQLConnect, TestSQLConnectDSNPrecedence) {
634+
TEST_F(FlightSQLODBCRemoteTestBase, TestSQLConnectDSNPrecedence) {
640635
// ODBC Environment
641636
SQLHENV env;
642637
SQLHDBC conn;
@@ -656,13 +651,13 @@ TEST(SQLConnect, TestSQLConnectDSNPrecedence) {
656651
EXPECT_TRUE(ret == SQL_SUCCESS);
657652

658653
// Connect string
659-
ASSERT_OK_AND_ASSIGN(std::string connect_str,
660-
arrow::internal::GetEnvVar(TEST_CONNECT_STR));
654+
std::string connect_str = getConnectionString();
661655

662656
// Write connection string content into a DSN,
663657
// must succeed before continuing
664658

665-
// Pass incorrect uid and password to SQLConnect, they will be ignored
659+
// Pass incorrect uid and password to SQLConnect, they will be ignored.
660+
// Assumes TEST_CONNECT_STR contains uid and pwd
666661
std::string uid("non_existent_id"), pwd("non_existent_password");
667662
ASSERT_TRUE(writeDSN(connect_str));
668663

@@ -746,7 +741,7 @@ TEST(SQLDisconnect, TestSQLDisconnectWithoutConnection) {
746741
EXPECT_TRUE(ret == SQL_SUCCESS);
747742
}
748743

749-
TEST(SQLGetDiagFieldW, TestSQLGetDiagFieldWForConnectFailure) {
744+
TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetDiagFieldWForConnectFailure) {
750745
// ODBC Environment
751746
SQLHENV env;
752747
SQLHDBC conn;
@@ -765,11 +760,8 @@ TEST(SQLGetDiagFieldW, TestSQLGetDiagFieldWForConnectFailure) {
765760

766761
EXPECT_TRUE(ret == SQL_SUCCESS);
767762

768-
// Connect string
769-
ASSERT_OK_AND_ASSIGN(std::string connect_str,
770-
arrow::internal::GetEnvVar(TEST_CONNECT_STR));
771-
// Append invalid uid to connection string
772-
connect_str += std::string("uid=non_existent_id;");
763+
// Invalid connect string
764+
std::string connect_str = this->getInvalidConnectionString();
773765

774766
ASSERT_OK_AND_ASSIGN(std::wstring wconnect_str,
775767
arrow::util::UTF8ToWideString(connect_str));
@@ -859,9 +851,9 @@ TEST(SQLGetDiagFieldW, TestSQLGetDiagFieldWForConnectFailure) {
859851
EXPECT_TRUE(ret == SQL_SUCCESS);
860852
}
861853

862-
TEST(SQLGetDiagFieldW, TestSQLGetDiagFieldWForConnectFailureNTS) {
854+
TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetDiagFieldWForConnectFailureNTS) {
863855
// Test is disabled because driver manager on Windows does not pass through SQL_NTS
864-
// This test case can be potentionally used on macOS/Linux
856+
// This test case can be potentially used on macOS/Linux
865857
GTEST_SKIP();
866858
// ODBC Environment
867859
SQLHENV env;
@@ -881,11 +873,8 @@ TEST(SQLGetDiagFieldW, TestSQLGetDiagFieldWForConnectFailureNTS) {
881873

882874
EXPECT_TRUE(ret == SQL_SUCCESS);
883875

884-
// Connect string
885-
ASSERT_OK_AND_ASSIGN(std::string connect_str,
886-
arrow::internal::GetEnvVar(TEST_CONNECT_STR));
887-
// Append invalid uid to connection string
888-
connect_str += std::string("uid=non_existent_id;");
876+
// Invalid connect string
877+
std::string connect_str = this->getInvalidConnectionString();
889878

890879
ASSERT_OK_AND_ASSIGN(std::wstring wconnect_str,
891880
arrow::util::UTF8ToWideString(connect_str));
@@ -902,7 +891,6 @@ TEST(SQLGetDiagFieldW, TestSQLGetDiagFieldWForConnectFailureNTS) {
902891
EXPECT_TRUE(ret == SQL_ERROR);
903892

904893
// Retrieve all supported header level and record level data
905-
SQLSMALLINT HEADER_LEVEL = 0;
906894
SQLSMALLINT RECORD_1 = 1;
907895

908896
// SQL_DIAG_MESSAGE_TEXT SQL_NTS
@@ -929,7 +917,7 @@ TEST(SQLGetDiagFieldW, TestSQLGetDiagFieldWForConnectFailureNTS) {
929917
EXPECT_TRUE(ret == SQL_SUCCESS);
930918
}
931919

932-
TEST(SQLGetDiagRec, TestSQLGetDiagRecForConnectFailure) {
920+
TYPED_TEST(FlightSQLODBCTestBase, TestSQLGetDiagRecForConnectFailure) {
933921
// ODBC Environment
934922
SQLHENV env;
935923
SQLHDBC conn;
@@ -948,11 +936,8 @@ TEST(SQLGetDiagRec, TestSQLGetDiagRecForConnectFailure) {
948936

949937
EXPECT_TRUE(ret == SQL_SUCCESS);
950938

951-
// Connect string
952-
ASSERT_OK_AND_ASSIGN(std::string connect_str,
953-
arrow::internal::GetEnvVar(TEST_CONNECT_STR));
954-
// Append invalid uid to connection string
955-
connect_str += std::string("uid=non_existent_id;");
939+
// Invalid connect string
940+
std::string connect_str = this->getInvalidConnectionString();
956941

957942
ASSERT_OK_AND_ASSIGN(std::wstring wconnect_str,
958943
arrow::util::UTF8ToWideString(connect_str));
@@ -978,7 +963,7 @@ TEST(SQLGetDiagRec, TestSQLGetDiagRecForConnectFailure) {
978963

979964
EXPECT_TRUE(ret == SQL_SUCCESS);
980965

981-
EXPECT_GT(message_length, 200);
966+
EXPECT_GT(message_length, 120);
982967

983968
EXPECT_EQ(native_error, 200);
984969

@@ -1000,6 +985,12 @@ TEST(SQLGetDiagRec, TestSQLGetDiagRecForConnectFailure) {
1000985
EXPECT_TRUE(ret == SQL_SUCCESS);
1001986
}
1002987

988+
TYPED_TEST(FlightSQLODBCTestBase, TestConnect) {
989+
// Verifies connect and disconnect works on its own
990+
this->connect();
991+
this->disconnect();
992+
}
993+
1003994
} // namespace integration_tests
1004995
} // namespace odbc
1005996
} // namespace flight

0 commit comments

Comments
 (0)