Skip to content

Commit

Permalink
[AD-845] User and auth are supported in SQLConnect (#109)
Browse files Browse the repository at this point in the history
* [AD-845] Update user and password if passed to SQLConnect.

* [AD-845] Add tests for SQLConnect.

* [AD-845] Refactor Windows-specific code.

* [AD-845] Attempt to resolve MacOS test error for writing to ODBC.INI

* [AD-845] Attempt to resolve MacOS test error for writing to ODBC.INI

* [AD-845] Fix Linux ODBC compile error.

* [AD-845] Fix MacOS ODBC compile error.

* [AD-845] Attempt to resolve Linux test error for writing to ODBC.INI

* [AD-845] Attempt to resolve Linux test error for prefixed text in error message.

* [AD-845] Refactor location to ODBC.INI

* [AD-845] Attempt to resolve MacOS test error for writing to ODBC.INI

* [AD-845] Code review suggestions.
  • Loading branch information
Bruce Irschick authored Aug 15, 2022
1 parent f287d53 commit 5690962
Show file tree
Hide file tree
Showing 9 changed files with 418 additions and 70 deletions.
1 change: 1 addition & 0 deletions .github/workflows/mac-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ env:
DOC_DB_LOG_LEVEL: "debug"
JDBC_DRIVER_VERSION: "1.3.0"
ODBCINSTINI: "${{github.workspace}}/build/odbc/lib/documentdb-odbc-install.ini"
ODBCINI: "${{github.workspace}}/odbc.ini"

jobs:
build-mac:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/mac-debug-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ env:
DOC_DB_LOG_LEVEL: "debug"
JDBC_DRIVER_VERSION: "1.3.0"
ODBCINSTINI: "${{github.workspace}}/build/odbc/lib/documentdb-odbc-install.ini"
ODBCINI: "${{github.workspace}}/odbc.ini"

jobs:
build-mac-debug:
Expand Down
73 changes: 69 additions & 4 deletions src/odbc-test/include/odbc_test_suite.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
#include <boost/test/unit_test.hpp>

#include <documentdb/odbc/common/platform_utils.h>
#include <documentdb/odbc/config/configuration.h>
#include <documentdb/odbc/config/connection_string_parser.h>

using namespace documentdb::odbc::config;

#ifndef BOOST_TEST_CONTEXT
#define BOOST_TEST_CONTEXT(...)
Expand Down Expand Up @@ -68,16 +72,77 @@ struct OdbcTestSuite {
*/
void Connect(const std::string& connectStr);

/**
* Establish connection to node using default handles.
*
* @param dsn The DSN of the connection
* @param username user name
* @param password password
*/
void Connect(const std::string& dsn, const std::string& username,
const std::string& password);

/**
* Parse the connection string into configuration.
*
* @param connectionString the connection string to parse.
* @param config the configuration to update.
*/
void ParseConnectionString(const std::string& connectionString,
Configuration& config);

/**
* Writes the DSN configuration
*
* @param dsn The DSN to write
* @param config The configuration to write
*/
void WriteDsnConfiguration(const Configuration& config);

/**
* Writes the DSN configuration for a local connection.
* Ensures the username and password are not set in the DSN.
* Instead sets the username and password parameters to be used
* with SQLConnect.
*
* @param dsn the DSN to write configuration for.
* @param username the updated username for the connection.
* @param password the updated password for the connection.
*/
void WriteDsnConfiguration(const std::string& dsn,
const std::string& connectionString,
std::string& username, std::string& password);

/**
* Removes the DSN configuration
*
* @param dsn The DSN to write
*/
void DeleteDsnConfiguration(const std::string& dsn);

/**
* Expect connection to be rejected by the node.
*
* @param connectStr Connection string.
* @return SQL State.
*/
std::string ExpectConnectionReject(
const std::string& connectStr,
const std::string& expectedError =
"08001: Failed to establish connection with the host.");
std::string ExpectConnectionReject(const std::string& connectStr,
const std::string& expectedState,
const std::string& expectedError);

/**
* Expect connection to be rejected by the node.
*
* @param dsn the DSN for the connection
* @param username the username for the connection.
* @param password the password for the connection.
* @return SQL State.
*/
std::string ExpectConnectionReject(const std::string& dsn,
const std::string& username,
const std::string& password,
const std::string& expectedState,
const std::string& expectedError);

/**
* Disconnect.
Expand Down
130 changes: 108 additions & 22 deletions src/odbc-test/src/connection_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@
#include <sqlext.h>

#include <boost/test/unit_test.hpp>
#include <boost/test/data/test_case.hpp>
#include <boost/test/data/monomorphic.hpp>
#include <string>

#include "odbc_test_suite.h"
#include "test_utils.h"

using namespace boost::unit_test;
using boost::unit_test::precondition;
using documentdb::odbc::if_integration;
using documentdb::odbc::OdbcTestSuite;
Expand Down Expand Up @@ -98,14 +101,33 @@ BOOST_AUTO_TEST_CASE(TestConnectionRestoreExternalSSHTunnel,
Disconnect();
}

BOOST_AUTO_TEST_CASE(TestConnectionRestoreLocalServer) {
BOOST_DATA_TEST_CASE_F(ConnectionTestSuiteFixture,
TestConnectionRestoreLocalServer, data::make({false, true}), useSqlConnect) {
std::string dsn = "RestoreLocalServer";
std::string connectionString;
CreateDsnConnectionStringForLocalServer(connectionString);
Connect(connectionString);

if (useSqlConnect) {
std::string username;
std::string password;
WriteDsnConfiguration(dsn, connectionString, username, password);
Connect(dsn, username, password);
} else {
Connect(connectionString);
}

Disconnect();

if (useSqlConnect) {
DeleteDsnConfiguration(dsn);
}
}

BOOST_AUTO_TEST_CASE(TestConnectionRestoreMiscOptionsSet) {
BOOST_DATA_TEST_CASE_F(ConnectionTestSuiteFixture,
TestConnectionRestoreMiscOptionsSet,
data::make({false, true}), useSqlConnect) {
const std::string dsn = "RestoreMiscOptionsSet";

const std::string miscOptions =
"APP_NAME=TestAppName;"
"LOGIN_TIMEOUT_SEC=30;"
Expand All @@ -119,26 +141,55 @@ BOOST_AUTO_TEST_CASE(TestConnectionRestoreMiscOptionsSet) {
std::string connectionString;
CreateDsnConnectionStringForLocalServer(connectionString, "", "",
miscOptions);

Connect(connectionString);
if (useSqlConnect) {
std::string username;
std::string password;
WriteDsnConfiguration(dsn, connectionString, username, password);
Connect(dsn, username, password);
} else {
Connect(connectionString);
}
Disconnect();

if (useSqlConnect) {
DeleteDsnConfiguration(dsn);
}
}

BOOST_AUTO_TEST_CASE(TestConnectionIncompleteBasicProperties) {
BOOST_DATA_TEST_CASE_F(ConnectionTestSuiteFixture,
TestConnectionIncompleteBasicProperties,
data::make({false, true}), useSqlConnect) {
const std::string dsn = "IncompleteBasicProperties";
std::string connectionString =
"DRIVER={Amazon DocumentDB};"
"HOSTNAME=localhost;"
"USER=user;"
"PASSWORD=password;";

ExpectConnectionReject(connectionString,
"01S00: Hostname, username, password, and database "
"are required to connect.");
if (useSqlConnect) {
std::string username;
std::string password;
WriteDsnConfiguration(dsn, connectionString, username, password);
ExpectConnectionReject(dsn, username, password, "01S00",
"Hostname, username, password, and database "
"are required to connect.");
} else {
ExpectConnectionReject(connectionString, "01S00",
"Hostname, username, password, and database "
"are required to connect.");
}

Disconnect();

if (useSqlConnect) {
DeleteDsnConfiguration(dsn);
}
}

BOOST_AUTO_TEST_CASE(TestConnectionIncompleteSSHTunnelProperties) {
BOOST_DATA_TEST_CASE_F(ConnectionTestSuiteFixture,
TestConnectionIncompleteSSHTunnelProperties,
data::make({false, true}), useSqlConnect) {
const std::string dsn = "IncompleteSSHTunnelProperties";
std::string connectionString =
"DRIVER={Amazon DocumentDB};"
"HOSTNAME=host.com;"
Expand All @@ -148,27 +199,62 @@ BOOST_AUTO_TEST_CASE(TestConnectionIncompleteSSHTunnelProperties) {
"SSH_USER=sshUser;"
"SSH_HOST=sshHost;";

ExpectConnectionReject(
connectionString,
"01S00: If using an internal SSH tunnel, all of ssh_host, ssh_user, "
"ssh_private_key_file are required to connect.");
if (useSqlConnect) {
std::string username;
std::string password;
WriteDsnConfiguration(dsn, connectionString, username, password);
ExpectConnectionReject(
dsn, username, password, "01S00",
"If using an internal SSH tunnel, all of ssh_host, ssh_user, "
"ssh_private_key_file are required to connect.");
} else {
ExpectConnectionReject(
connectionString, "01S00",
"If using an internal SSH tunnel, all of ssh_host, ssh_user, "
"ssh_private_key_file are required to connect.");
}

Disconnect();

if (useSqlConnect) {
DeleteDsnConfiguration(dsn);
}
}

BOOST_AUTO_TEST_CASE(TestConnectionInvalidUser) {
BOOST_DATA_TEST_CASE_F(ConnectionTestSuiteFixture, TestConnectionInvalidUser,
data::make({false, true}), useSqlConnect) {
const std::string dsn = "InvalidUser";
std::string connectionString;
CreateDsnConnectionStringForLocalServer(connectionString, "", "invaliduser");

ExpectConnectionReject(
connectionString,
"08001: Failed to establish connection with the host.\n"
"Invalid username or password or user is not authorized on database "
"'odbc-test'. "
"Please check your settings. Authorization failed for user 'invaliduser' "
"on database 'admin' with mechanism");
if (useSqlConnect) {
std::string username;
std::string password;
WriteDsnConfiguration(dsn, connectionString, username, password);
ExpectConnectionReject(
dsn, username, password, "08001",
"Failed to establish connection with the host.\n"
"Invalid username or password or user is not authorized on database "
"'odbc-test'. "
"Please check your settings. Authorization failed for user "
"'invaliduser' "
"on database 'admin' with mechanism");
} else {
ExpectConnectionReject(
connectionString, "08001",
"Failed to establish connection with the host.\n"
"Invalid username or password or user is not authorized on database "
"'odbc-test'. "
"Please check your settings. Authorization failed for user "
"'invaliduser' "
"on database 'admin' with mechanism");
}

Disconnect();

if (useSqlConnect) {
DeleteDsnConfiguration(dsn);
}
}

BOOST_AUTO_TEST_SUITE_END()
Loading

0 comments on commit 5690962

Please sign in to comment.