From afea4995662a4e55a930eae4beb1c02512d2bb77 Mon Sep 17 00:00:00 2001 From: Mark Keller Date: Thu, 7 Nov 2024 20:33:26 +0000 Subject: [PATCH 1/7] new encrypted connections files --- .../connections/connections_aws.toml.gpg | Bin 0 -> 319 bytes .../connections/connections_azure.toml.gpg | Bin 0 -> 329 bytes .../connections/connections_gcp.toml.gpg | Bin 0 -> 329 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 .github/workflows/connections/connections_aws.toml.gpg create mode 100644 .github/workflows/connections/connections_azure.toml.gpg create mode 100644 .github/workflows/connections/connections_gcp.toml.gpg diff --git a/.github/workflows/connections/connections_aws.toml.gpg b/.github/workflows/connections/connections_aws.toml.gpg new file mode 100644 index 0000000000000000000000000000000000000000..4209b3cc79998899067759eec8db8f990bf7e395 GIT binary patch literal 319 zcmV-F0l@x@4Fm}T0&8yht<55A-rmx{Z2>-V-xARK@DU|m>v!8~EH0#I)DpPCGsKQ| z<L6m7 z@-2x*$xG@}Qb%0a8{2zl8&p=OXsJ%YPdfrR#tRL&AX9KGK)%hDs*+rtgC+~qrT7Mt zGxtRf*@hnt&8cR(quwi05gsA*(Avn`NBbO;3VzbN9i9a^nM;R{E;HUe;Pmv&Xh6DE z3B9-W?gnVi0m&5iJTM;ZD4$ng$;wX*tCkr6l7q@EC1@yOi}Jvj?zMac#ESTq-*h8S RcsnOIN@Mvv+@U^ZySa?olmq|( literal 0 HcmV?d00001 diff --git a/.github/workflows/connections/connections_azure.toml.gpg b/.github/workflows/connections/connections_azure.toml.gpg new file mode 100644 index 0000000000000000000000000000000000000000..5a1f2f70dbabb3f39b80159f3d2882be074bb430 GIT binary patch literal 329 zcmV-P0k-~(4Fm}T0^T)QwCFAP^4`+GcL8DK!D;m0U7-KOIi^TW)*7p|Es>4`im#h# z6W^TgWJrgfM8CT}TMIDiFPC*Gde@a|V@VGdTy^sdRqgKf2xofit^i{%PW;{AJ}d5F zgTYUMyR-R?-y#HI^Ydbdwtp5*#GU#lsi$66jK)usGAV6HBXB~g56Qcu>)(+uP129s zvA%5_&%nZ@fa<{%^WyV(9eWuj4{F5*C3+iTG{n*JXD7fnI$*UBlI+VI(Co;)WI#57 ztNSq(?(O@KggRvaqnLGpo2o2E4IQf?9)~zdJ-E^1VS-Edl-Z4hRfW+{l;3Eq8KmEA z@pP3)FND&1je1U0GLTJoG5k5~@pMzO$f@4cuwF8PaCo7o+0=ct*$zU}SPD{hK36#eG?1$2ah#?Cq~}rbw$j literal 0 HcmV?d00001 diff --git a/.github/workflows/connections/connections_gcp.toml.gpg b/.github/workflows/connections/connections_gcp.toml.gpg new file mode 100644 index 0000000000000000000000000000000000000000..7098f47bef1b697d07c5fd3ab0bbdb3aa31d089a GIT binary patch literal 329 zcmV-P0k-~(4Fm}T0&M>l%Ci6XGTzd_cL9nH5e%hNcc~B-uV3LU5d)jA0#jdG`M1QO zm-&Gd>4#7)JqO*NupX}JnE2)U3~Ac-pmu+m-+&%@|;DH@fFAt%Cd_xF8D z^Ed7|NYTJB)ECg=@>8DAMnTp{zbsH|r}ZXS6Xe|S=0Tm0Wus3wf)Sa7he9lim*$Yc zEd-K`g+h0x#OK-bzc&!zMF; bvh?IJtYBcl2E>CH*w6@zj&G2B8?-;K%>ASD literal 0 HcmV?d00001 From a429377d4e5376d581c4ebce6c95403f08e4a792 Mon Sep 17 00:00:00 2001 From: Mark Keller Date: Thu, 7 Nov 2024 20:35:39 +0000 Subject: [PATCH 2/7] update CI test setup --- .github/workflows/build_test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index ab98dd370..e46d4427e 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -140,8 +140,9 @@ jobs: env: PARAMETERS_SECRET: ${{ secrets.PARAMETERS_SECRET }} run: | + mkdir -p ~/.snowflake gpg --quiet --batch --yes --decrypt --passphrase="$PARAMETERS_SECRET" \ - .github/workflows/parameters/public/parameters_${{ matrix.cloud-provider }}.py.gpg > test/parameters.py + .github/workflows/connections/connections_${{ matrix.cloud-provider }}.toml.gpg > ~/.snowflake/connections.toml - name: Download wheel(s) uses: actions/download-artifact@v4 with: From 610a6e549733e5928cc5d65743615e5dc07e76d6 Mon Sep 17 00:00:00 2001 From: Mark Keller Date: Thu, 7 Nov 2024 20:42:32 +0000 Subject: [PATCH 3/7] modifying test execution to use config_manager --- test/integ/conftest.py | 78 ++++++++++++++++++++--------------- test/integ/test_connection.py | 2 +- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/test/integ/conftest.py b/test/integ/conftest.py index 0f112ec30..95b68482c 100644 --- a/test/integ/conftest.py +++ b/test/integ/conftest.py @@ -17,10 +17,16 @@ import snowflake.connector from snowflake.connector.compat import IS_WINDOWS +from snowflake.connector.config_manager import CONFIG_MANAGER from snowflake.connector.connection import DefaultConverterClass from .. import running_on_public_ci -from ..parameters import CONNECTION_PARAMETERS + +try: + from ..parameters import CONNECTION_PARAMETERS +except ImportError: + CONNECTION_PARAMETERS: dict[str, Any] = {} # type: ignore + try: from ..parameters import CLIENT_FAILOVER_PARAMETERS # type: ignore @@ -34,9 +40,11 @@ RUNNING_ON_GH = os.getenv("GITHUB_ACTIONS") == "true" TEST_USING_VENDORED_ARROW = os.getenv("TEST_USING_VENDORED_ARROW") == "true" -if not isinstance(CONNECTION_PARAMETERS["host"], str): +if CONNECTION_PARAMETERS and not isinstance(CONNECTION_PARAMETERS.get("host"), str): raise Exception("default host is not a string in parameters.py") -RUNNING_AGAINST_LOCAL_SNOWFLAKE = CONNECTION_PARAMETERS["host"].endswith("local") +RUNNING_AGAINST_LOCAL_SNOWFLAKE = CONNECTION_PARAMETERS.get("host", "").endswith( + "local" +) try: from ..parameters import CONNECTION_PARAMETERS_ADMIN # type: ignore @@ -110,30 +118,38 @@ def get_db_parameters(connection_name: str = "default") -> dict[str, Any]: os.environ["TZ"] = "UTC" if not IS_WINDOWS: time.tzset() - - connections = { - "default": CONNECTION_PARAMETERS, - "client_failover": CLIENT_FAILOVER_PARAMETERS, - "admin": CONNECTION_PARAMETERS_ADMIN, - } - - chosen_connection = connections[connection_name] - if "account" not in chosen_connection: - pytest.skip(f"{connection_name} connection is unavailable in parameters.py") - - # testaccount connection info - ret = {**DEFAULT_PARAMETERS, **chosen_connection} - - # snowflake admin account. Not available in GH actions - for k, v in CONNECTION_PARAMETERS_ADMIN.items(): - ret["sf_" + k] = v - - if "host" in ret and ret["host"] == DEFAULT_PARAMETERS["host"]: - ret["host"] = ret["account"] + ".snowflakecomputing.com" - - if "account" in ret and ret["account"] == DEFAULT_PARAMETERS["account"]: - print_help() - sys.exit(2) + cm_connection_name = ( + CONFIG_MANAGER["default_connection_name"] + if connection_name == "default" + else connection_name + ) + if cm_connection_name in CONFIG_MANAGER["connections"]: + # If config_manager knows of this connection then use it + ret = CONFIG_MANAGER["connections"][cm_connection_name].value.value + else: + connections = { + "default": CONNECTION_PARAMETERS, + "failover": CLIENT_FAILOVER_PARAMETERS, + "admin": CONNECTION_PARAMETERS_ADMIN, + } + + chosen_connection = connections[connection_name] + if "account" not in chosen_connection: + pytest.skip(f"{connection_name} connection is unavailable in parameters.py") + + # testaccount connection info + ret = {**DEFAULT_PARAMETERS, **chosen_connection} + + # snowflake admin account. Not available in GH actions + for k, v in CONNECTION_PARAMETERS_ADMIN.items(): + ret["sf_" + k] = v + + if "host" in ret and ret["host"] == DEFAULT_PARAMETERS["host"]: + ret["host"] = ret["account"] + ".snowflakecomputing.com" + + if "account" in ret and ret["account"] == DEFAULT_PARAMETERS["account"]: + print_help() + sys.exit(2) # a unique table name ret["name"] = "python_tests_" + str(uuid.uuid4()).replace("-", "_") @@ -170,13 +186,7 @@ def init_test_schema(db_parameters) -> Generator[None, None, None]: """ ret = db_parameters with snowflake.connector.connect( - user=ret["user"], - password=ret["password"], - host=ret["host"], - port=ret["port"], - database=ret["database"], - account=ret["account"], - protocol=ret["protocol"], + **ret, ) as con: con.cursor().execute(f"CREATE SCHEMA IF NOT EXISTS {TEST_SCHEMA}") yield diff --git a/test/integ/test_connection.py b/test/integ/test_connection.py index bec9de556..4e74d13da 100644 --- a/test/integ/test_connection.py +++ b/test/integ/test_connection.py @@ -1133,7 +1133,7 @@ def test_client_prefetch_threads_setting(conn_cnx): @pytest.mark.external def test_client_failover_connection_url(conn_cnx): - with conn_cnx("client_failover") as conn: + with conn_cnx("failover") as conn: with conn.cursor() as cur: assert cur.execute("select 1;").fetchall() == [ (1,), From d3aea87d411e2664a2c312e390b359e74a0f2c77 Mon Sep 17 00:00:00 2001 From: Mark Keller Date: Thu, 7 Nov 2024 22:54:11 +0000 Subject: [PATCH 4/7] fix old driver tests --- test/integ/conftest.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/test/integ/conftest.py b/test/integ/conftest.py index 95b68482c..be9314777 100644 --- a/test/integ/conftest.py +++ b/test/integ/conftest.py @@ -17,11 +17,15 @@ import snowflake.connector from snowflake.connector.compat import IS_WINDOWS -from snowflake.connector.config_manager import CONFIG_MANAGER from snowflake.connector.connection import DefaultConverterClass from .. import running_on_public_ci +try: + from snowflake.connector.config_manager import CONFIG_MANAGER +except ImportError: + CONFIG_MANAGER = None + try: from ..parameters import CONNECTION_PARAMETERS except ImportError: @@ -118,14 +122,23 @@ def get_db_parameters(connection_name: str = "default") -> dict[str, Any]: os.environ["TZ"] = "UTC" if not IS_WINDOWS: time.tzset() - cm_connection_name = ( - CONFIG_MANAGER["default_connection_name"] - if connection_name == "default" - else connection_name - ) - if cm_connection_name in CONFIG_MANAGER["connections"]: + if ( + CONFIG_MANAGER is not None + and ( + CONFIG_MANAGER["default_connection_name"] + if connection_name == "default" + else connection_name + ) + in CONFIG_MANAGER["connections"] + ): # If config_manager knows of this connection then use it - ret = CONFIG_MANAGER["connections"][cm_connection_name].value.value + ret = CONFIG_MANAGER["connections"][ + ( + CONFIG_MANAGER["default_connection_name"] + if connection_name == "default" + else connection_name + ) + ].value.value else: connections = { "default": CONNECTION_PARAMETERS, From 480f064c849206ed384e6005a25ab7ccbe80d7da Mon Sep 17 00:00:00 2001 From: Mark Keller Date: Fri, 8 Nov 2024 21:25:11 +0000 Subject: [PATCH 5/7] fix tests relying on port and other specific values in parameters.py --- test/integ/conftest.py | 1 - test/integ/test_autocommit.py | 53 ++- test/integ/test_connection.py | 382 ++++++--------------- test/integ/test_converter_null.py | 73 ++-- test/integ/test_cursor.py | 202 +++++------ test/integ/test_dbapi.py | 29 +- test/integ/test_key_pair_authentication.py | 20 +- test/integ/test_network.py | 5 +- test/integ/test_session_parameters.py | 16 +- test/integ/test_transaction.py | 25 +- 10 files changed, 271 insertions(+), 535 deletions(-) diff --git a/test/integ/conftest.py b/test/integ/conftest.py index be9314777..673420fb2 100644 --- a/test/integ/conftest.py +++ b/test/integ/conftest.py @@ -152,7 +152,6 @@ def get_db_parameters(connection_name: str = "default") -> dict[str, Any]: # testaccount connection info ret = {**DEFAULT_PARAMETERS, **chosen_connection} - # snowflake admin account. Not available in GH actions for k, v in CONNECTION_PARAMETERS_ADMIN.items(): ret["sf_" + k] = v diff --git a/test/integ/test_autocommit.py b/test/integ/test_autocommit.py index 94baf0ad2..d4c01b2ef 100644 --- a/test/integ/test_autocommit.py +++ b/test/integ/test_autocommit.py @@ -5,14 +5,14 @@ from __future__ import annotations -import snowflake.connector +import uuid def exe0(cnx, sql): return cnx.cursor().execute(sql) -def _run_autocommit_off(cnx, db_parameters): +def _run_autocommit_off(cnx, name): """Runs autocommit off test. Args: @@ -21,7 +21,7 @@ def _run_autocommit_off(cnx, db_parameters): """ def exe(cnx, sql): - return cnx.cursor().execute(sql.format(name=db_parameters["name"])) + return cnx.cursor().execute(sql.format(name=name)) exe( cnx, @@ -89,7 +89,7 @@ def exe(cnx, sql): assert res[0] == 2 -def _run_autocommit_on(cnx, db_parameters): +def _run_autocommit_on(cnx, name): """Run autocommit on test. Args: @@ -98,7 +98,7 @@ def _run_autocommit_on(cnx, db_parameters): """ def exe(cnx, sql): - return cnx.cursor().execute(sql.format(name=db_parameters["name"])) + return cnx.cursor().execute(sql.format(name=name)) exe( cnx, @@ -116,7 +116,7 @@ def exe(cnx, sql): assert res[0] == 4 -def test_autocommit_attribute(conn_cnx, db_parameters): +def test_autocommit_attribute(conn_cnx): """Tests autocommit attribute. Args: @@ -124,8 +124,10 @@ def test_autocommit_attribute(conn_cnx, db_parameters): db_parameters: Database parameters. """ + name = "python_tests_" + str(uuid.uuid4()).replace("-", "_") + def exe(cnx, sql): - return cnx.cursor().execute(sql.format(name=db_parameters["name"])) + return cnx.cursor().execute(sql.format(name=name)) with conn_cnx() as cnx: exe( @@ -136,9 +138,9 @@ def exe(cnx, sql): ) try: cnx.autocommit(False) - _run_autocommit_off(cnx, db_parameters) + _run_autocommit_off(cnx, name) cnx.autocommit(True) - _run_autocommit_on(cnx, db_parameters) + _run_autocommit_on(cnx, name) finally: exe( cnx, @@ -148,25 +150,18 @@ def exe(cnx, sql): ) -def test_autocommit_parameters(db_parameters): +def test_autocommit_parameters(conn_cnx): """Tests autocommit parameter. Args: db_parameters: Database parameters. """ + name = "python_tests_" + str(uuid.uuid4()).replace("-", "_") def exe(cnx, sql): - return cnx.cursor().execute(sql.format(name=db_parameters["name"])) - - with snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - protocol=db_parameters["protocol"], - schema=db_parameters["schema"], - database=db_parameters["database"], + return cnx.cursor().execute(sql.format(name=name)) + + with conn_cnx( autocommit=False, ) as cnx: exe( @@ -175,20 +170,12 @@ def exe(cnx, sql): CREATE TABLE {name} (c1 boolean) """, ) - _run_autocommit_off(cnx, db_parameters) - - with snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - protocol=db_parameters["protocol"], - schema=db_parameters["schema"], - database=db_parameters["database"], + _run_autocommit_off(cnx, name) + + with conn_cnx( autocommit=True, ) as cnx: - _run_autocommit_on(cnx, db_parameters) + _run_autocommit_on(cnx, name) exe( cnx, """ diff --git a/test/integ/test_connection.py b/test/integ/test_connection.py index 4e74d13da..4f524fea9 100644 --- a/test/integ/test_connection.py +++ b/test/integ/test_connection.py @@ -66,64 +66,34 @@ def test_basic(conn_testaccount): assert conn_testaccount.session_id -def test_connection_without_schema(db_parameters): +def test_connection_without_schema(conn_cnx): """Basic Connection test without schema.""" - cnx = snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - database=db_parameters["database"], - protocol=db_parameters["protocol"], + with conn_cnx( timezone="UTC", - ) - assert cnx, "invalid cnx" - cnx.close() + ) as cnx: + assert cnx, "invalid cnx" -def test_connection_without_database_schema(db_parameters): +def test_connection_without_database_schema(conn_cnx): """Basic Connection test without database and schema.""" - cnx = snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - protocol=db_parameters["protocol"], + with conn_cnx( timezone="UTC", - ) - assert cnx, "invalid cnx" - cnx.close() + ) as cnx: + assert cnx, "invalid cnx" -def test_connection_without_database2(db_parameters): +def test_connection_without_database2(conn_cnx): """Basic Connection test without database.""" - cnx = snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - schema=db_parameters["schema"], - protocol=db_parameters["protocol"], + with conn_cnx( timezone="UTC", - ) - assert cnx, "invalid cnx" - cnx.close() + ) as cnx: + assert cnx, "invalid cnx" def test_with_config(db_parameters): """Creates a connection with the config parameter.""" config = { - "user": db_parameters["user"], - "password": db_parameters["password"], - "host": db_parameters["host"], - "port": db_parameters["port"], - "account": db_parameters["account"], - "schema": db_parameters["schema"], - "database": db_parameters["database"], - "protocol": db_parameters["protocol"], + **db_parameters, "timezone": "UTC", } cnx = snowflake.connector.connect(**config) @@ -145,10 +115,7 @@ def test_with_tokens(conn_cnx, db_parameters): master_token = initial_cnx.rest._master_token session_token = initial_cnx.rest._token with snowflake.connector.connect( - account=db_parameters["account"], - host=db_parameters["host"], - port=db_parameters["port"], - protocol=db_parameters["protocol"], + **db_parameters, session_token=session_token, master_token=master_token, ) as token_cnx: @@ -173,10 +140,7 @@ def test_with_tokens_expired(conn_cnx, db_parameters): with pytest.raises(ProgrammingError): token_cnx = snowflake.connector.connect( - account=db_parameters["account"], - host=db_parameters["host"], - port=db_parameters["port"], - protocol=db_parameters["protocol"], + **db_parameters, session_token=session_token, master_token=master_token, ) @@ -191,14 +155,7 @@ def test_with_tokens_expired(conn_cnx, db_parameters): def test_keep_alive_true(db_parameters): """Creates a connection with client_session_keep_alive parameter.""" config = { - "user": db_parameters["user"], - "password": db_parameters["password"], - "host": db_parameters["host"], - "port": db_parameters["port"], - "account": db_parameters["account"], - "schema": db_parameters["schema"], - "database": db_parameters["database"], - "protocol": db_parameters["protocol"], + **db_parameters, "timezone": "UTC", "client_session_keep_alive": True, } @@ -216,14 +173,7 @@ def test_keep_alive_heartbeat_frequency(db_parameters): parameter. """ config = { - "user": db_parameters["user"], - "password": db_parameters["password"], - "host": db_parameters["host"], - "port": db_parameters["port"], - "account": db_parameters["account"], - "schema": db_parameters["schema"], - "database": db_parameters["database"], - "protocol": db_parameters["protocol"], + **db_parameters, "timezone": "UTC", "client_session_keep_alive": True, "client_session_keep_alive_heartbeat_frequency": 1000, @@ -243,14 +193,7 @@ def test_keep_alive_heartbeat_frequency_min(db_parameters): Also if a value comes as string, should be properly converted to int and not fail assertion. """ config = { - "user": db_parameters["user"], - "password": db_parameters["password"], - "host": db_parameters["host"], - "port": db_parameters["port"], - "account": db_parameters["account"], - "schema": db_parameters["schema"], - "database": db_parameters["database"], - "protocol": db_parameters["protocol"], + **db_parameters, "timezone": "UTC", "client_session_keep_alive": True, "client_session_keep_alive_heartbeat_frequency": "10", @@ -264,22 +207,15 @@ def test_keep_alive_heartbeat_frequency_min(db_parameters): cnx.close() -def test_bad_db(db_parameters): +def test_bad_db(conn_cnx): """Attempts to use a bad DB.""" - cnx = snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - protocol=db_parameters["protocol"], + with conn_cnx( database="baddb", - ) - assert cnx, "invald cnx" - cnx.close() + ) as cnx: + assert cnx, "invald cnx" -def test_with_string_login_timeout(db_parameters): +def test_with_string_login_timeout(conn_cnx): """Test that login_timeout when passed as string does not raise TypeError. In this test, we pass bad login credentials to raise error and trigger login @@ -287,168 +223,116 @@ def test_with_string_login_timeout(db_parameters): comes from str - int arithmetic. """ with pytest.raises(DatabaseError): - snowflake.connector.connect( - protocol="http", + with conn_cnx( user="bogus", password="bogus", - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], login_timeout="5", - ) + ): + ... -def test_bogus(db_parameters): +def test_bogus(conn_cnx): """Attempts to login with invalid user name and password. Notes: This takes a long time. """ with pytest.raises(DatabaseError): - snowflake.connector.connect( - protocol="http", + with conn_cnx( user="bogus", password="bogus", - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], login_timeout=5, - ) + ): + ... with pytest.raises(DatabaseError): - snowflake.connector.connect( - protocol="http", + with conn_cnx( user="bogus", password="bogus", account="testaccount123", - host=db_parameters["host"], - port=db_parameters["port"], login_timeout=5, insecure_mode=True, - ) + ): + ... with pytest.raises(DatabaseError): - snowflake.connector.connect( - protocol="http", + with conn_cnx( user="snowman", password="", account="testaccount123", - host=db_parameters["host"], - port=db_parameters["port"], login_timeout=5, - ) + ): + ... with pytest.raises(ProgrammingError): - snowflake.connector.connect( - protocol="http", + with conn_cnx( user="", password="password", account="testaccount123", - host=db_parameters["host"], - port=db_parameters["port"], login_timeout=5, - ) + ): + ... def test_invalid_application(db_parameters): """Invalid application name.""" with pytest.raises(snowflake.connector.Error): snowflake.connector.connect( - protocol=db_parameters["protocol"], - user=db_parameters["user"], - password=db_parameters["password"], + **db_parameters, application="%%%", ) -def test_valid_application(db_parameters): +def test_valid_application(conn_cnx): """Valid application name.""" application = "Special_Client" - cnx = snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], + with conn_cnx( application=application, - protocol=db_parameters["protocol"], - ) - assert cnx.application == application, "Must be valid application" - cnx.close() + ) as cnx: + assert cnx.application == application, "Must be valid application" -def test_invalid_default_parameters(db_parameters): +def test_invalid_default_parameters(conn_cnx): """Invalid database, schema, warehouse and role name.""" - cnx = snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - protocol=db_parameters["protocol"], + with conn_cnx( database="neverexists", schema="neverexists", warehouse="neverexits", - ) - assert cnx, "Must be success" + ) as cnx: + assert cnx, "Must be success" with pytest.raises(snowflake.connector.DatabaseError): # must not success - snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - protocol=db_parameters["protocol"], + with conn_cnx( database="neverexists", schema="neverexists", validate_default_parameters=True, - ) + ): + ... with pytest.raises(snowflake.connector.DatabaseError): # must not success - snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - protocol=db_parameters["protocol"], - database=db_parameters["database"], + with conn_cnx( schema="neverexists", validate_default_parameters=True, - ) + ): + ... with pytest.raises(snowflake.connector.DatabaseError): # must not success - snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - protocol=db_parameters["protocol"], - database=db_parameters["database"], - schema=db_parameters["schema"], + with conn_cnx( warehouse="neverexists", validate_default_parameters=True, - ) + ): + ... # Invalid role name is already validated with pytest.raises(snowflake.connector.DatabaseError): # must not success - snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - protocol=db_parameters["protocol"], - database=db_parameters["database"], - schema=db_parameters["schema"], + with conn_cnx( role="neverexists", - ) + ): + ... @pytest.mark.skipif( @@ -523,19 +407,16 @@ def test_invalid_account_timeout(): @pytest.mark.timeout(15) -def test_invalid_proxy(db_parameters): +def test_invalid_proxy(conn_cnx): with pytest.raises(OperationalError): - snowflake.connector.connect( + with conn_cnx( protocol="http", account="testaccount", - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], login_timeout=5, proxy_host="localhost", proxy_port="3333", - ) + ): + ... # NOTE environment variable is set if the proxy parameter is specified. del os.environ["HTTP_PROXY"] del os.environ["HTTPS_PROXY"] @@ -591,7 +472,7 @@ def test_us_west_connection(tmpdir): @pytest.mark.timeout(60) -def test_privatelink(db_parameters): +def test_privatelink(conn_cnx): """Ensure the OCSP cache server URL is overridden if privatelink connection is used.""" try: os.environ["SF_OCSP_FAIL_OPEN"] = "false" @@ -613,17 +494,10 @@ def test_privatelink(db_parameters): "ocsp_response_cache.json" ) - cnx = snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - database=db_parameters["database"], - protocol=db_parameters["protocol"], + with conn_cnx( timezone="UTC", - ) - assert cnx, "invalid cnx" + ) as cnx: + assert cnx, "invalid cnx" ocsp_url = os.getenv("SF_OCSP_RESPONSE_CACHE_SERVER_URL") assert ocsp_url is None, f"OCSP URL should be None: {ocsp_url}" @@ -634,14 +508,7 @@ def test_privatelink(db_parameters): def test_disable_request_pooling(db_parameters): """Creates a connection with client_session_keep_alive parameter.""" config = { - "user": db_parameters["user"], - "password": db_parameters["password"], - "host": db_parameters["host"], - "port": db_parameters["port"], - "account": db_parameters["account"], - "schema": db_parameters["schema"], - "database": db_parameters["database"], - "protocol": db_parameters["protocol"], + **db_parameters, "timezone": "UTC", "disable_request_pooling": True, } @@ -762,7 +629,7 @@ def mock_auth(self, auth_instance): assert cnx -def test_dashed_url(db_parameters): +def test_dashed_url(): """Test whether dashed URLs get created correctly.""" with mock.patch( "snowflake.connector.network.SnowflakeRestful.fetch", @@ -787,7 +654,7 @@ def test_dashed_url(db_parameters): ) -def test_dashed_url_account_name(db_parameters): +def test_dashed_url_account_name(): """Tests whether dashed URLs get created correctly when no hostname is provided.""" with mock.patch( "snowflake.connector.network.SnowflakeRestful.fetch", @@ -851,79 +718,51 @@ def test_dashed_url_account_name(db_parameters): ), ], ) -def test_invalid_connection_parameter(db_parameters, name, value, exc_warn): +def test_invalid_connection_parameter(conn_cnx, name, value, exc_warn): with warnings.catch_warnings(record=True) as w: - conn_params = { - "account": db_parameters["account"], - "user": db_parameters["user"], - "password": db_parameters["password"], - "schema": db_parameters["schema"], - "database": db_parameters["database"], - "protocol": db_parameters["protocol"], - "host": db_parameters["host"], - "port": db_parameters["port"], - "validate_default_parameters": True, - name: value, - } - try: - conn = snowflake.connector.connect(**conn_params) - assert getattr(conn, "_" + name) == value - assert len(w) == 1 - assert str(w[0].message) == str(exc_warn) - finally: - conn.close() + with conn_cnx( + **{ + "validate_default_parameters": True, + name: value, + } + ) as conn: + ... + assert getattr(conn, "_" + name) == value + assert any( + map( + lambda e: str(e.message) == str(exc_warn), + w, + ) + ) -def test_invalid_connection_parameters_turned_off(db_parameters): +def test_invalid_connection_parameters_turned_off(conn_cnx): """Makes sure parameter checking can be turned off.""" with warnings.catch_warnings(record=True) as w: - conn_params = { - "account": db_parameters["account"], - "user": db_parameters["user"], - "password": db_parameters["password"], - "schema": db_parameters["schema"], - "database": db_parameters["database"], - "protocol": db_parameters["protocol"], - "host": db_parameters["host"], - "port": db_parameters["port"], - "validate_default_parameters": False, - "autocommit": "True", # Wrong type - "applucation": "this is a typo or my own variable", # Wrong name - } - try: - conn = snowflake.connector.connect(**conn_params) - assert conn._autocommit == conn_params["autocommit"] - assert conn._applucation == conn_params["applucation"] + w.clear() + with conn_cnx( + validate_default_parameters=False, + autocommit="True", # Wrong type + applucation="this is a typo or my own variable", # Wrong name + ) as conn: + assert conn._autocommit == "True" + assert conn._applucation == "this is a typo or my own variable" assert len(w) == 0 - finally: - conn.close() -def test_invalid_connection_parameters_only_warns(db_parameters): +def test_invalid_connection_parameters_only_warns(conn_cnx): """This test supresses warnings to only have warehouse, database and schema checking.""" with warnings.catch_warnings(record=True) as w: - conn_params = { - "account": db_parameters["account"], - "user": db_parameters["user"], - "password": db_parameters["password"], - "schema": db_parameters["schema"], - "database": db_parameters["database"], - "protocol": db_parameters["protocol"], - "host": db_parameters["host"], - "port": db_parameters["port"], - "validate_default_parameters": True, - "autocommit": "True", # Wrong type - "applucation": "this is a typo or my own variable", # Wrong name - } - try: - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - conn = snowflake.connector.connect(**conn_params) - assert conn._autocommit == conn_params["autocommit"] - assert conn._applucation == conn_params["applucation"] - assert len(w) == 0 - finally: - conn.close() + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + with conn_cnx( + validate_default_parameters=True, + autocommit="True", # Wrong type + applucation="this is a typo or my own variable", # Wrong name + ) as conn: + assert conn._autocommit == "True" + assert conn._applucation == "this is a typo or my own variable" + assert len(w) == 0 @pytest.mark.skipolddriver @@ -1225,14 +1064,7 @@ def check_packages(message: str, expected_packages: list[str]) -> bool: # test different application new_application_name = "PythonSnowpark" config = { - "user": db_parameters["user"], - "password": db_parameters["password"], - "host": db_parameters["host"], - "port": db_parameters["port"], - "account": db_parameters["account"], - "schema": db_parameters["schema"], - "database": db_parameters["database"], - "protocol": db_parameters["protocol"], + **db_parameters, "timezone": "UTC", "application": new_application_name, } diff --git a/test/integ/test_converter_null.py b/test/integ/test_converter_null.py index 0297c625b..057bfb5d1 100644 --- a/test/integ/test_converter_null.py +++ b/test/integ/test_converter_null.py @@ -8,58 +8,49 @@ import re from datetime import datetime, timedelta, timezone -import snowflake.connector from snowflake.connector.converter import ZERO_EPOCH from snowflake.connector.converter_null import SnowflakeNoConverterToPython NUMERIC_VALUES = re.compile(r"-?[\d.]*\d$") -def test_converter_no_converter_to_python(db_parameters): +def test_converter_no_converter_to_python(conn_cnx): """Tests no converter. This should not translate the Snowflake internal data representation to the Python native types. """ - con = snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - database=db_parameters["database"], - schema=db_parameters["schema"], - protocol=db_parameters["protocol"], + with conn_cnx( timezone="UTC", converter_class=SnowflakeNoConverterToPython, - ) - con.cursor().execute( - """ -alter session set python_connector_query_result_format='JSON' -""" - ) - - ret = ( - con.cursor() - .execute( + ) as con: + con.cursor().execute( """ -select current_timestamp(), - 1::NUMBER, - 2.0::FLOAT, - 'test1' -""" + alter session set python_connector_query_result_format='JSON' + """ + ) + + ret = ( + con.cursor() + .execute( + """ + select current_timestamp(), + 1::NUMBER, + 2.0::FLOAT, + 'test1' + """ + ) + .fetchone() ) - .fetchone() - ) - assert isinstance(ret[0], str) - assert NUMERIC_VALUES.match(ret[0]) - assert isinstance(ret[1], str) - assert NUMERIC_VALUES.match(ret[1]) - con.cursor().execute("create or replace table testtb(c1 timestamp_ntz(6))") - try: - current_time = datetime.now(timezone.utc).replace(tzinfo=None) - # binding value should have no impact - con.cursor().execute("insert into testtb(c1) values(%s)", (current_time,)) - ret = con.cursor().execute("select * from testtb").fetchone()[0] - assert ZERO_EPOCH + timedelta(seconds=(float(ret))) == current_time - finally: - con.cursor().execute("drop table if exists testtb") + assert isinstance(ret[0], str) + assert NUMERIC_VALUES.match(ret[0]) + assert isinstance(ret[1], str) + assert NUMERIC_VALUES.match(ret[1]) + con.cursor().execute("create or replace table testtb(c1 timestamp_ntz(6))") + try: + current_time = datetime.now(timezone.utc).replace(tzinfo=None) + # binding value should have no impact + con.cursor().execute("insert into testtb(c1) values(%s)", (current_time,)) + ret = con.cursor().execute("select * from testtb").fetchone()[0] + assert ZERO_EPOCH + timedelta(seconds=(float(ret))) == current_time + finally: + con.cursor().execute("drop table if exists testtb") diff --git a/test/integ/test_cursor.py b/test/integ/test_cursor.py index 384e5e95a..205947a26 100644 --- a/test/integ/test_cursor.py +++ b/test/integ/test_cursor.py @@ -11,6 +11,7 @@ import os import pickle import time +import uuid from datetime import date, datetime, timezone from typing import TYPE_CHECKING, NamedTuple from unittest import mock @@ -96,17 +97,8 @@ def _drop_warehouse(conn, db_parameters): @pytest.fixture() -def conn(request, conn_cnx, db_parameters): - def fin(): - with conn_cnx() as cnx: - cnx.cursor().execute( - "use {db}.{schema}".format( - db=db_parameters["database"], schema=db_parameters["schema"] - ) - ) - cnx.cursor().execute("drop table {name}".format(name=db_parameters["name"])) - - request.addfinalizer(fin) +def conn(conn_cnx, db_parameters): + name = "python_tests_" + str(uuid.uuid4()).replace("-", "_") with conn_cnx() as cnx: cnx.cursor().execute( @@ -123,11 +115,19 @@ def fin(): ratio number(5,2), b binary) """.format( - name=db_parameters["name"] + name=name ) ) - return conn_cnx + yield conn_cnx, name + with conn_cnx() as cnx: + cnx.cursor().execute( + "use {db}.{schema}".format( + db=db_parameters["database"], + schema=db_parameters["schema"], + ) + ) + cnx.cursor().execute(f"drop table {name}") def _check_results(cursor, results): @@ -153,14 +153,15 @@ def _type_from_description(named_access: bool): @pytest.mark.skipolddriver -def test_insert_select(conn, db_parameters, caplog): +def test_insert_select(conn, caplog): """Inserts and selects integer data.""" + conn, name = conn with conn() as cnx: c = cnx.cursor() try: c.execute( "insert into {name}(aa) values(123456)," - "(98765),(65432)".format(name=db_parameters["name"]) + "(98765),(65432)".format(name=name) ) cnt = 0 for rec in c: @@ -172,9 +173,7 @@ def test_insert_select(conn, db_parameters, caplog): try: c = cnx.cursor() - c.execute( - "select aa from {name} order by aa".format(name=db_parameters["name"]) - ) + c.execute(f"select aa from {name} order by aa") results = [] for rec in c: results.append(rec[0]) @@ -186,9 +185,7 @@ def test_insert_select(conn, db_parameters, caplog): with cnx.cursor(snowflake.connector.DictCursor) as c: caplog.clear() assert "Number of results in first chunk: 3" not in caplog.text - c.execute( - "select aa from {name} order by aa".format(name=db_parameters["name"]) - ) + c.execute(f"select aa from {name} order by aa") results = [] for rec in c: results.append(rec["AA"]) @@ -197,13 +194,12 @@ def test_insert_select(conn, db_parameters, caplog): @pytest.mark.skipolddriver -def test_insert_and_select_by_separate_connection(conn, db_parameters, caplog): +def test_insert_and_select_by_separate_connection(conn, conn_cnx, caplog): """Inserts a record and select it by a separate connection.""" + conn, name = conn with conn() as cnx: result = cnx.cursor().execute( - "insert into {name}(aa) values({value})".format( - name=db_parameters["name"], value="1234" - ) + "insert into {name}(aa) values({value})".format(name=name, value="1234") ) cnt = 0 for rec in result: @@ -211,20 +207,11 @@ def test_insert_and_select_by_separate_connection(conn, db_parameters, caplog): assert cnt == 1, "wrong number of records were inserted" assert result.rowcount == 1, "wrong number of records were inserted" - cnx2 = snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - database=db_parameters["database"], - schema=db_parameters["schema"], - protocol=db_parameters["protocol"], + with conn_cnx( timezone="UTC", - ) - try: + ) as cnx2: c = cnx2.cursor() - c.execute("select aa from {name}".format(name=db_parameters["name"])) + c.execute(f"select aa from {name}") results = [] for rec in c: results.append(rec[0]) @@ -232,8 +219,6 @@ def test_insert_and_select_by_separate_connection(conn, db_parameters, caplog): assert results[0] == 1234, "the first result was wrong" assert result.rowcount == 1, "wrong number of records were selected" assert "Number of results in first chunk: 1" in caplog.text - finally: - cnx2.close() def _total_milliseconds_from_timedelta(td): @@ -246,12 +231,13 @@ def _total_seconds_from_timedelta(td): return _total_milliseconds_from_timedelta(td) // 10**3 -def test_insert_timestamp_select(conn, db_parameters): +def test_insert_timestamp_select(conn, conn_cnx): """Inserts and gets timestamp, timestamp with tz, date, and time. Notes: Currently the session parameter TIMEZONE is ignored. """ + conn, name = conn PST_TZ = "America/Los_Angeles" JST_TZ = "Asia/Tokyo" current_timestamp = datetime.now(timezone.utc).replace(tzinfo=None) @@ -271,7 +257,7 @@ def test_insert_timestamp_select(conn, db_parameters): "%(dt)s, %(tm)s)" ) c.execute( - fmt.format(name=db_parameters["name"]), + fmt.format(name=name), { "value": 1234, "tsltz": current_timestamp, @@ -289,24 +275,11 @@ def test_insert_timestamp_select(conn, db_parameters): finally: c.close() - cnx2 = snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - database=db_parameters["database"], - schema=db_parameters["schema"], - protocol=db_parameters["protocol"], + with conn_cnx( timezone="UTC", - ) - try: + ) as cnx2: c = cnx2.cursor() - c.execute( - "select aa, tsltz, tstz, tsntz, dt, tm from {name}".format( - name=db_parameters["name"] - ) - ) + c.execute(f"select aa, tsltz, tstz, tsntz, dt, tm from {name}") result_numeric_value = [] result_timestamp_value = [] @@ -380,12 +353,11 @@ def test_insert_timestamp_select(conn, db_parameters): assert ( constants.FIELD_ID_TO_NAME[type_code(desc[5])] == "TIME" ), "invalid column name" - finally: - cnx2.close() -def test_insert_timestamp_ltz(conn, db_parameters): +def test_insert_timestamp_ltz(conn): """Inserts and retrieve timestamp ltz.""" + conn, name = conn tzstr = "America/New_York" # sync with the session parameter with conn() as cnx: @@ -398,7 +370,7 @@ def test_insert_timestamp_ltz(conn, db_parameters): try: fmt = "insert into {name}(aa, tsltz) values(%(value)s,%(ts)s)" c.execute( - fmt.format(name=db_parameters["name"]), + fmt.format(name=name), { "value": 8765, "ts": current_time, @@ -413,7 +385,7 @@ def test_insert_timestamp_ltz(conn, db_parameters): try: c = cnx.cursor() - c.execute("select aa,tsltz from {name}".format(name=db_parameters["name"])) + c.execute(f"select aa,tsltz from {name}") result_numeric_value = [] result_timestamp_value = [] for aa, ts in c: @@ -429,8 +401,9 @@ def test_insert_timestamp_ltz(conn, db_parameters): c.close() -def test_struct_time(conn, db_parameters): +def test_struct_time(conn): """Binds struct_time object for updating timestamp.""" + conn, name = conn tzstr = "America/New_York" os.environ["TZ"] = tzstr if not IS_WINDOWS: @@ -442,7 +415,7 @@ def test_struct_time(conn, db_parameters): try: fmt = "insert into {name}(aa, tsltz) values(%(value)s,%(ts)s)" c.execute( - fmt.format(name=db_parameters["name"]), + fmt.format(name=name), { "value": 87654, "ts": test_time, @@ -459,9 +432,7 @@ def test_struct_time(conn, db_parameters): assert cnt == 1, "wrong number of records were inserted" try: - result = cnx.cursor().execute( - "select aa, tsltz from {name}".format(name=db_parameters["name"]) - ) + result = cnx.cursor().execute(f"select aa, tsltz from {name}") for _, _tsltz in result: pass @@ -479,34 +450,25 @@ def test_struct_time(conn, db_parameters): time.tzset() -def test_insert_binary_select(conn, db_parameters): +def test_insert_binary_select(conn, conn_cnx): """Inserts and get a binary value.""" + conn, name = conn value = b"\x00\xFF\xA1\xB2\xC3" with conn() as cnx: c = cnx.cursor() try: fmt = "insert into {name}(b) values(%(b)s)" - c.execute(fmt.format(name=db_parameters["name"]), {"b": value}) + c.execute(fmt.format(name=name), {"b": value}) count = sum(int(rec[0]) for rec in c) assert count == 1, "wrong number of records were inserted" assert c.rowcount == 1, "wrong number of records were selected" finally: c.close() - cnx2 = snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - database=db_parameters["database"], - schema=db_parameters["schema"], - protocol=db_parameters["protocol"], - ) - try: + with conn_cnx() as cnx2: c = cnx2.cursor() - c.execute("select b from {name}".format(name=db_parameters["name"])) + c.execute(f"select b from {name}") results = [b for (b,) in c] assert value == results[0], "the binary result was wrong" @@ -527,38 +489,27 @@ def test_insert_binary_select(conn, db_parameters): assert ( constants.FIELD_ID_TO_NAME[type_code(desc[0])] == "BINARY" ), "invalid column name" - finally: - cnx2.close() -def test_insert_binary_select_with_bytearray(conn, db_parameters): +def test_insert_binary_select_with_bytearray(conn, conn_cnx): """Inserts and get a binary value using the bytearray type.""" + conn, name = conn value = bytearray(b"\x00\xFF\xA1\xB2\xC3") with conn() as cnx: c = cnx.cursor() try: fmt = "insert into {name}(b) values(%(b)s)" - c.execute(fmt.format(name=db_parameters["name"]), {"b": value}) + c.execute(fmt.format(name=name), {"b": value}) count = sum(int(rec[0]) for rec in c) assert count == 1, "wrong number of records were inserted" assert c.rowcount == 1, "wrong number of records were selected" finally: c.close() - cnx2 = snowflake.connector.connect( - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - account=db_parameters["account"], - database=db_parameters["database"], - schema=db_parameters["schema"], - protocol=db_parameters["protocol"], - ) - try: + with conn_cnx() as cnx2: c = cnx2.cursor() - c.execute("select b from {name}".format(name=db_parameters["name"])) + c.execute(f"select b from {name}") results = [b for (b,) in c] assert bytes(value) == results[0], "the binary result was wrong" @@ -579,13 +530,12 @@ def test_insert_binary_select_with_bytearray(conn, db_parameters): assert ( constants.FIELD_ID_TO_NAME[type_code(desc[0])] == "BINARY" ), "invalid column name" - finally: - cnx2.close() -def test_variant(conn, db_parameters): +def test_variant(conn): """Variant including JSON object.""" - name_variant = db_parameters["name"] + "_variant" + conn, name = conn + name_variant = name + "_variant" with conn() as cnx: cnx.cursor().execute( """ @@ -774,12 +724,13 @@ def test_timeout_query(conn_cnx): ) -def test_executemany(conn, db_parameters): +def test_executemany(conn): """Executes many statements. Client binding is supported by either dict, or list data types. Notes: The binding data type is dict and tuple, respectively. """ + conn, name = conn table_name = random_string(5, "test_executemany_") with conn() as cnx: with cnx.cursor() as c: @@ -797,7 +748,7 @@ def test_executemany(conn, db_parameters): assert c.rowcount == 4, "wrong number of records were inserted" with cnx.cursor() as c: - fmt = "insert into {name}(aa) values(%s)".format(name=db_parameters["name"]) + fmt = f"insert into {name}(aa) values(%s)" c.executemany( fmt, [ @@ -813,7 +764,8 @@ def test_executemany(conn, db_parameters): @pytest.mark.skipolddriver -def test_executemany_qmark_types(conn, db_parameters): +def test_executemany_qmark_types(conn): + conn, _ = conn table_name = random_string(5, "test_executemany_qmark_types_") with conn(paramstyle="qmark") as cnx: with cnx.cursor() as cur: @@ -850,6 +802,7 @@ def test_executemany_qmark_types(conn, db_parameters): @pytest.mark.skipolddriver def test_executemany_params_iterator(conn): """Cursor.executemany() works with an interator of params.""" + conn, _ = conn table_name = random_string(5, "executemany_params_iterator_") with conn() as cnx: with cnx.cursor() as c: @@ -869,6 +822,7 @@ def test_executemany_params_iterator(conn): @pytest.mark.skipolddriver def test_executemany_empty_params(conn): """Cursor.executemany() does nothing if params is empty.""" + conn, _ = conn table_name = random_string(5, "executemany_empty_params_") with conn() as cnx: with cnx.cursor() as c: @@ -880,12 +834,13 @@ def test_executemany_empty_params(conn): @pytest.mark.skipolddriver( reason="old driver raises DatabaseError instead of InterfaceError" ) -def test_closed_cursor(conn, db_parameters): +def test_closed_cursor(conn): """Attempts to use the closed cursor. It should raise errors. Notes: The binding data type is scalar. """ + conn, _ = conn table_name = random_string(5, "test_closed_cursor_") with conn() as cnx: with cnx.cursor() as c: @@ -913,7 +868,8 @@ def test_closed_cursor(conn, db_parameters): @pytest.mark.skipolddriver -def test_fetchmany(conn, db_parameters, caplog): +def test_fetchmany(conn, caplog): + conn, _ = conn table_name = random_string(5, "test_fetchmany_") with conn() as cnx: with cnx.cursor() as c: @@ -951,8 +907,9 @@ def test_fetchmany(conn, db_parameters, caplog): assert len(c.fetchmany(15)) == 0, "The number of records" -def test_process_params(conn, db_parameters): +def test_process_params(conn): """Binds variables for insert and other queries.""" + conn, _ = conn table_name = random_string(5, "test_process_params_") with conn() as cnx: with cnx.cursor() as c: @@ -996,11 +953,12 @@ def test_process_params_empty(conn_cnx, interpolate_empty_sequences, expected_ou assert cursor.fetchone() == (expected_outcome,) -def test_real_decimal(conn, db_parameters): +def test_real_decimal(conn): + conn, name = conn with conn() as cnx: c = cnx.cursor() fmt = ("insert into {name}(aa, pct, ratio) " "values(%s,%s,%s)").format( - name=db_parameters["name"] + name=name, ) c.execute(fmt, (9876, 12.3, decimal.Decimal("23.4"))) for (_cnt,) in c: @@ -1009,7 +967,7 @@ def test_real_decimal(conn, db_parameters): c.close() c = cnx.cursor() - fmt = "select aa, pct, ratio from {name}".format(name=db_parameters["name"]) + fmt = f"select aa, pct, ratio from {name}" c.execute(fmt) for _aa, _pct, _ratio in c: pass @@ -1019,7 +977,7 @@ def test_real_decimal(conn, db_parameters): c.close() with cnx.cursor(snowflake.connector.DictCursor) as c: - fmt = "select aa, pct, ratio from {name}".format(name=db_parameters["name"]) + fmt = f"select aa, pct, ratio from {name}" c.execute(fmt) rec = c.fetchone() assert rec["AA"] == 9876, "the integer value" @@ -1083,7 +1041,8 @@ def test_execute_after_close(conn_testaccount): cursor.execute("show tables") -def test_multi_table_insert(conn, db_parameters): +def test_multi_table_insert(conn): + conn, name = conn try: with conn() as cnx: cur = cnx.cursor() @@ -1091,7 +1050,7 @@ def test_multi_table_insert(conn, db_parameters): """ INSERT INTO {name}(aa) VALUES(1234),(9876),(2345) """.format( - name=db_parameters["name"] + name=name ) ) assert cur.rowcount == 3, "the number of records" @@ -1100,7 +1059,7 @@ def test_multi_table_insert(conn, db_parameters): """ CREATE OR REPLACE TABLE {name}_foo (aa_foo int) """.format( - name=db_parameters["name"] + name=name, ) ) @@ -1108,7 +1067,7 @@ def test_multi_table_insert(conn, db_parameters): """ CREATE OR REPLACE TABLE {name}_bar (aa_bar int) """.format( - name=db_parameters["name"] + name=name, ) ) @@ -1119,7 +1078,7 @@ def test_multi_table_insert(conn, db_parameters): INTO {name}_bar(aa_bar) VALUES(aa) SELECT aa FROM {name} """.format( - name=db_parameters["name"] + name=name, ) ) assert cur.rowcount == 6 @@ -1129,14 +1088,14 @@ def test_multi_table_insert(conn, db_parameters): """ DROP TABLE IF EXISTS {name}_foo """.format( - name=db_parameters["name"] + name=name, ) ) cnx.cursor().execute( """ DROP TABLE IF EXISTS {name}_bar """.format( - name=db_parameters["name"] + name=name, ) ) @@ -1161,6 +1120,7 @@ def test_close_twice(conn_testaccount): @pytest.mark.parametrize("result_format", ("arrow", "json")) def test_fetch_out_of_range_timestamp_value(conn, result_format): + conn, _ = conn with conn() as cnx: cur = cnx.cursor() cur.execute( @@ -1173,6 +1133,7 @@ def test_fetch_out_of_range_timestamp_value(conn, result_format): @pytest.mark.skipolddriver def test_null_in_non_null(conn): + conn, _ = conn table_name = random_string(5, "null_in_non_null") error_msg = "NULL result in a non-nullable column" with conn() as cnx: @@ -1185,6 +1146,7 @@ def test_null_in_non_null(conn): @pytest.mark.parametrize("sql", (None, ""), ids=["None", "empty"]) def test_empty_execution(conn, sql): """Checks whether executing an empty string, or nothing behaves as expected.""" + conn, _ = conn with conn() as cnx: with cnx.cursor() as cur: if sql is not None: @@ -1205,6 +1167,7 @@ def test_empty_execution(conn, sql): ) def test_reset_fetch(conn, reuse_results): """Tests behavior after resetting an open cursor.""" + conn, _ = conn with conn(reuse_results=reuse_results) as cnx: with cnx.cursor() as cur: cur.execute("select 1") @@ -1223,6 +1186,7 @@ def test_reset_fetch(conn, reuse_results): def test_rownumber(conn): """Checks whether rownumber is returned as expected.""" + conn, _ = conn with conn() as cnx: with cnx.cursor() as cur: assert cur.execute("select * from values (1), (2)") @@ -1235,6 +1199,7 @@ def test_rownumber(conn): def test_values_set(conn): """Checks whether a bunch of properties start as Nones, but get set to something else when a query was executed.""" + conn, _ = conn properties = [ "timestamp_output_format", "timestamp_ltz_output_format", @@ -1271,6 +1236,7 @@ def test_execute_helper_params_error(conn_testaccount): @pytest.mark.skipolddriver def test_desc_rewrite(conn, caplog): """Tests whether describe queries are rewritten as expected and this action is logged.""" + conn, _ = conn with conn() as cnx: with cnx.cursor() as cur: table_name = random_string(5, "test_desc_rewrite_") diff --git a/test/integ/test_dbapi.py b/test/integ/test_dbapi.py index 97d3c6e47..ac8b0bb80 100644 --- a/test/integ/test_dbapi.py +++ b/test/integ/test_dbapi.py @@ -135,20 +135,9 @@ def test_exceptions_as_connection_attributes(conn_cnx): assert con.NotSupportedError == errors.NotSupportedError -def test_commit(db_parameters): - con = snowflake.connector.connect( - account=db_parameters["account"], - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - protocol=db_parameters["protocol"], - ) - try: - # Commit must work, even if it doesn't do anything +def test_commit(conn_cnx, db_parameters): + with conn_cnx() as con: con.commit() - finally: - con.close() def test_rollback(conn_cnx, db_parameters): @@ -244,19 +233,9 @@ def test_rowcount(conn_local): assert cur.rowcount == 1, "cursor.rowcount should the number of rows returned" -def test_close(db_parameters): - con = snowflake.connector.connect( - account=db_parameters["account"], - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - protocol=db_parameters["protocol"], - ) - try: +def test_close(conn_cnx): + with conn_cnx() as con: cur = con.cursor() - finally: - con.close() # commit is currently a nop; disabling for now # connection.commit should raise an Error if called after connection is diff --git a/test/integ/test_key_pair_authentication.py b/test/integ/test_key_pair_authentication.py index ec4fedea3..ee4fdba8e 100644 --- a/test/integ/test_key_pair_authentication.py +++ b/test/integ/test_key_pair_authentication.py @@ -220,18 +220,7 @@ def fin(): pass -def test_bad_private_key(db_parameters): - db_config = { - "protocol": db_parameters["protocol"], - "account": db_parameters["account"], - "user": db_parameters["user"], - "host": db_parameters["host"], - "port": db_parameters["port"], - "database": db_parameters["database"], - "schema": db_parameters["schema"], - "timezone": "UTC", - } - +def test_bad_private_key(conn_cnx): dsa_private_key = dsa.generate_private_key(key_size=2048, backend=default_backend()) dsa_private_key_der = dsa_private_key.private_bytes( encoding=serialization.Encoding.DER, @@ -254,9 +243,12 @@ def test_bad_private_key(db_parameters): ] for private_key in bad_private_key_test_cases: - db_config["private_key"] = private_key with pytest.raises(snowflake.connector.errors.ProgrammingError) as exec_info: - snowflake.connector.connect(**db_config) + with conn_cnx( + timezone="UTC", + private_key=private_key, + ): + ... assert exec_info.value.errno == 251008 diff --git a/test/integ/test_network.py b/test/integ/test_network.py index bf4ab44ac..95910acc3 100644 --- a/test/integ/test_network.py +++ b/test/integ/test_network.py @@ -24,7 +24,10 @@ def test_no_auth(db_parameters): """SNOW-13588: No auth Rest API test.""" - rest = SnowflakeRestful(host=db_parameters["host"], port=db_parameters["port"]) + rest = SnowflakeRestful( + host=db_parameters["host"], + port=db_parameters.get("port", 443), + ) try: # no auth # show warehouse diff --git a/test/integ/test_session_parameters.py b/test/integ/test_session_parameters.py index 73ae5fa65..28d8f68a5 100644 --- a/test/integ/test_session_parameters.py +++ b/test/integ/test_session_parameters.py @@ -20,20 +20,12 @@ CONNECTION_PARAMETERS_ADMIN = {} -def test_session_parameters(db_parameters): +def test_session_parameters(conn_cnx): """Sets the session parameters in connection time.""" - connection = snowflake.connector.connect( - protocol=db_parameters["protocol"], - account=db_parameters["account"], - user=db_parameters["user"], - password=db_parameters["password"], - host=db_parameters["host"], - port=db_parameters["port"], - database=db_parameters["database"], - schema=db_parameters["schema"], + with conn_cnx( session_parameters={"TIMEZONE": "UTC"}, - ) - ret = connection.cursor().execute("show parameters like 'TIMEZONE'").fetchone() + ) as connection: + ret = connection.cursor().execute("show parameters like 'TIMEZONE'").fetchone() assert ret[1] == "UTC" diff --git a/test/integ/test_transaction.py b/test/integ/test_transaction.py index c36b2a041..303257d76 100644 --- a/test/integ/test_transaction.py +++ b/test/integ/test_transaction.py @@ -69,21 +69,12 @@ def test_transaction(conn_cnx, db_parameters): assert total == 13824, "total integer" -def test_connection_context_manager(request, db_parameters): - db_config = { - "protocol": db_parameters["protocol"], - "account": db_parameters["account"], - "user": db_parameters["user"], - "password": db_parameters["password"], - "host": db_parameters["host"], - "port": db_parameters["port"], - "database": db_parameters["database"], - "schema": db_parameters["schema"], - "timezone": "UTC", - } +def test_connection_context_manager(request, conn_cnx, db_parameters): def fin(): - with snowflake.connector.connect(**db_config) as cnx: + with conn_cnx( + timezone="UTC", + ) as cnx: cnx.cursor().execute( """ DROP TABLE IF EXISTS {name} @@ -95,7 +86,9 @@ def fin(): request.addfinalizer(fin) try: - with snowflake.connector.connect(**db_config) as cnx: + with conn_cnx( + timezone="UTC", + ) as cnx: cnx.autocommit(False) cnx.cursor().execute( """ @@ -152,7 +145,9 @@ def fin(): except snowflake.connector.Error: # syntax error should be caught here # and the last change must have been rollbacked - with snowflake.connector.connect(**db_config) as cnx: + with conn_cnx( + timezone="UTC", + ) as cnx: ret = ( cnx.cursor() .execute( From 16986f5e2bfa51291352bba87e34abeb126fd24d Mon Sep 17 00:00:00 2001 From: Mark Keller Date: Fri, 8 Nov 2024 23:24:19 +0000 Subject: [PATCH 6/7] fix last test failure --- .github/workflows/build_test.yml | 1 + src/snowflake/connector/config_manager.py | 2 +- src/snowflake/connector/connection.py | 13 ++++++------- test/integ/test_connection.py | 4 +++- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index e46d4427e..a67794a2e 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -143,6 +143,7 @@ jobs: mkdir -p ~/.snowflake gpg --quiet --batch --yes --decrypt --passphrase="$PARAMETERS_SECRET" \ .github/workflows/connections/connections_${{ matrix.cloud-provider }}.toml.gpg > ~/.snowflake/connections.toml + chmod 0600 "/home/runner/.snowflake/connections.toml" || true - name: Download wheel(s) uses: actions/download-artifact@v4 with: diff --git a/src/snowflake/connector/config_manager.py b/src/snowflake/connector/config_manager.py index 29f864453..d2a197428 100644 --- a/src/snowflake/connector/config_manager.py +++ b/src/snowflake/connector/config_manager.py @@ -330,7 +330,7 @@ def read_config( continue if ( - sliceoptions.check_permissions # Skip checking if this file couldn't hold sensitive information + sliceoptions.check_permissions # Skip checking if this slice isn't holding sensitive information # Same check as openssh does for permissions # https://github.com/openssh/openssh-portable/blob/2709809fd616a0991dc18e3a58dea10fb383c3f0/readconf.c#LL2264C1-L2264C1 and filep.stat().st_mode & READABLE_BY_OTHERS != 0 diff --git a/src/snowflake/connector/connection.py b/src/snowflake/connector/connection.py index 5205bafc1..dfa928430 100644 --- a/src/snowflake/connector/connection.py +++ b/src/snowflake/connector/connection.py @@ -1338,13 +1338,12 @@ def cmd_query( data["queryContextDTO"] = queryContext client = "sfsql_file_transfer" if is_file_transfer else "sfsql" - if logger.getEffectiveLevel() <= logging.DEBUG: - logger.debug( - "sql=[%s], sequence_id=[%s], is_file_transfer=[%s]", - self._format_query_for_log(data["sqlText"]), - data["sequenceId"], - is_file_transfer, - ) + logger.debug( + "sql=[%s], sequence_id=[%s], is_file_transfer=[%s]", + self._format_query_for_log(data["sqlText"]), + data["sequenceId"], + is_file_transfer, + ) url_parameters = {REQUEST_ID: request_id} diff --git a/test/integ/test_connection.py b/test/integ/test_connection.py index 4f524fea9..418371577 100644 --- a/test/integ/test_connection.py +++ b/test/integ/test_connection.py @@ -22,6 +22,7 @@ import snowflake.connector from snowflake.connector import DatabaseError, OperationalError, ProgrammingError +from snowflake.connector.compat import IS_WINDOWS from snowflake.connector.connection import ( DEFAULT_CLIENT_PREFETCH_THREADS, SnowflakeConnection, @@ -747,7 +748,8 @@ def test_invalid_connection_parameters_turned_off(conn_cnx): ) as conn: assert conn._autocommit == "True" assert conn._applucation == "this is a typo or my own variable" - assert len(w) == 0 + # TODO: Windows tests will emit a warning about connections file privileges + assert len(w) == (1 if IS_WINDOWS else 0) def test_invalid_connection_parameters_only_warns(conn_cnx): From c8c2378f048ce67adaac70240b1ec81159efed2a Mon Sep 17 00:00:00 2001 From: Mark Keller Date: Sat, 9 Nov 2024 00:56:21 +0000 Subject: [PATCH 7/7] fix extras tests --- test/extras/simple_select1.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/extras/simple_select1.py b/test/extras/simple_select1.py index 957cf88ed..bfdee4e88 100644 --- a/test/extras/simple_select1.py +++ b/test/extras/simple_select1.py @@ -4,9 +4,7 @@ from snowflake.connector import connect -from ..parameters import CONNECTION_PARAMETERS - -with connect(**CONNECTION_PARAMETERS) as conn: +with connect() as conn: with conn.cursor() as cur: assert cur.execute("select 1;").fetchall() == [ (1,),