|
4 | 4 |
|
5 | 5 | from __future__ import annotations
|
6 | 6 |
|
| 7 | +import unittest |
| 8 | +from unittest.mock import Mock |
| 9 | + |
7 | 10 | import pytest
|
8 | 11 |
|
| 12 | +import snowflake.connector |
| 13 | + |
9 | 14 |
|
10 | 15 | @pytest.mark.skipolddriver
|
11 | 16 | def test_auth_no_auth():
|
@@ -38,3 +43,136 @@ def test_auth_no_auth():
|
38 | 43 | assert (
|
39 | 44 | reauth_response == expected_reauth_response
|
40 | 45 | ), f'reauthenticate(foo="bar") is expected to return {expected_reauth_response}, but returns {reauth_response}'
|
| 46 | + |
| 47 | + |
| 48 | +@pytest.mark.skipolddriver |
| 49 | +def test_authenticate_for_no_auth(): |
| 50 | + from snowflake.connector.auth import Auth |
| 51 | + from snowflake.connector.auth.no_auth import AuthNoAuth |
| 52 | + |
| 53 | + rest = None |
| 54 | + auth = Auth(rest) |
| 55 | + |
| 56 | + # Verify that when using AuthNoAuth, we can successfully call authenticate |
| 57 | + # even under these conditions |
| 58 | + # - None account is provided |
| 59 | + # - None user is provided |
| 60 | + # - restful client is not set up |
| 61 | + auth.authenticate(AuthNoAuth(), account=None, user=None) |
| 62 | + |
| 63 | + |
| 64 | +class TestHeartbeatExecutionFlowForNoAuth(unittest.TestCase): |
| 65 | + @pytest.mark.skipolddriver |
| 66 | + def test_hearbeat_execution_flow_for_no_auth(self): |
| 67 | + """Tests the heartbeat execution flow no-auth connections. |
| 68 | +
|
| 69 | + No-auth connection relies on these facts |
| 70 | + - connection uses _heartbeat_tick method to perform heartbeat check |
| 71 | + - _heartbeat_tick method calls connection._rest._heartbeat method to |
| 72 | + send out the actual heartbeat request |
| 73 | + - client_session_keep_alive_heartbeat_frequency (setter) calls |
| 74 | + master_validity_in_seconds of the restful client to get the |
| 75 | + reasonable value range. |
| 76 | + - _validate_client_session_keep_alive_heartbeat_frequency calls |
| 77 | + master_validity_in_seconds of the restful client to get the |
| 78 | + reasonable value range. |
| 79 | + And this test serves as a simple indicator to tell developers when a |
| 80 | + code change breaks such assumptions. |
| 81 | + """ |
| 82 | + # AuthNoAuth does not exist in old drivers, so we import at test level |
| 83 | + # to skip importing it for old driver tests. |
| 84 | + from snowflake.connector.auth.no_auth import AuthNoAuth |
| 85 | + |
| 86 | + no_auth = AuthNoAuth() |
| 87 | + conn = snowflake.connector.connect(auth_class=no_auth) |
| 88 | + # Simulate how we inject special restful client for no-auth connection. |
| 89 | + # And the tests verify that even with only the attributes listed below |
| 90 | + # available in conn._rest, the tested heartbeat functionalities are |
| 91 | + # still working as intended. |
| 92 | + conn._rest = Mock(spec=["_heartbeat", "master_validity_in_seconds"]) |
| 93 | + conn._rest.master_validity_in_seconds = 100 |
| 94 | + |
| 95 | + breaking_change_error_message = """ |
| 96 | + Unexpected execution flow for heartbeat, this means potential |
| 97 | + changes to heartbeat mechanism that will break no-auth connection |
| 98 | + feature. Please contact the owner of AuthNoAuth before proceeding. |
| 99 | + Details: {details} |
| 100 | + """ |
| 101 | + |
| 102 | + # Check that _heartbeat_tick is working as intended. |
| 103 | + try: |
| 104 | + conn._heartbeat_tick() |
| 105 | + conn._rest._heartbeat.assert_called_once() |
| 106 | + except Exception as e: |
| 107 | + raise AssertionError(breaking_change_error_message.format(details=str(e))) |
| 108 | + |
| 109 | + # Check that client_session_keep_alive_heartbeat_frequency setter is |
| 110 | + # working as intended with such a bare minimum set of interfaces |
| 111 | + # exposed in conn._rest. |
| 112 | + try: |
| 113 | + conn.client_session_keep_alive_heartbeat_frequency = 123 |
| 114 | + except Exception as e: |
| 115 | + raise AssertionError(breaking_change_error_message.format(details=str(e))) |
| 116 | + |
| 117 | + # Check that _validate_client_session_keep_alive_heartbeat_frequency is |
| 118 | + # working as intended with such a bare minimum set of interfaces |
| 119 | + # exposed in conn._rest. |
| 120 | + try: |
| 121 | + conn._validate_client_session_keep_alive_heartbeat_frequency() |
| 122 | + except Exception as e: |
| 123 | + raise AssertionError(breaking_change_error_message.format(details=str(e))) |
| 124 | + |
| 125 | + # Indirect way to check that |
| 126 | + # client_session_keep_alive_heartbeat_frequency setter calls |
| 127 | + # master_validity_in_seconds in conn._rest. |
| 128 | + conn._rest = Mock(spec=["_heartbeat"]) |
| 129 | + missing_master_validity_in_seconds_message = ( |
| 130 | + "has no attribute 'master_validity_in_seconds'" |
| 131 | + ) |
| 132 | + validity_dependency_change_template = ( |
| 133 | + "{method} no longer relies on rest.master_validity_in_seconds" |
| 134 | + ) |
| 135 | + try: |
| 136 | + # Verify that client_session_keep_alive_heartbeat_frequency setter |
| 137 | + # fails when conn._rest.master_validity_in_seconds method is |
| 138 | + # unavailable. |
| 139 | + with self.assertRaises(AttributeError) as context: |
| 140 | + conn.client_session_keep_alive_heartbeat_frequency = 123 |
| 141 | + self.assertIn( |
| 142 | + missing_master_validity_in_seconds_message, |
| 143 | + str(context.exception), |
| 144 | + ) |
| 145 | + except Exception: |
| 146 | + # This means there might be change breaking heartbeat mechanism for |
| 147 | + # no-auth connections. |
| 148 | + raise RuntimeError( |
| 149 | + breaking_change_error_message.format( |
| 150 | + details=validity_dependency_change_template.format( |
| 151 | + method="client_session_keep_alive_heartbeat_frequency (setter)" |
| 152 | + ) |
| 153 | + ) |
| 154 | + ) |
| 155 | + |
| 156 | + # Likewise, this is an indirect way to check that |
| 157 | + # _validate_client_session_keep_alive_heartbeat_frequency calls |
| 158 | + # master_validity_in_seconds in conn._rest. |
| 159 | + try: |
| 160 | + # Verify that _validate_client_session_keep_alive_heartbeat_frequency |
| 161 | + # fails when conn._rest.master_validity_in_seconds method is |
| 162 | + # unavailable. |
| 163 | + with self.assertRaises(AttributeError) as context: |
| 164 | + conn._validate_client_session_keep_alive_heartbeat_frequency() |
| 165 | + self.assertIn( |
| 166 | + missing_master_validity_in_seconds_message, |
| 167 | + str(context.exception), |
| 168 | + ) |
| 169 | + except Exception: |
| 170 | + # This means there might be change breaking heartbeat mechanism for |
| 171 | + # no-auth connections. |
| 172 | + raise RuntimeError( |
| 173 | + breaking_change_error_message.format( |
| 174 | + details=validity_dependency_change_template.format( |
| 175 | + method="_validate_client_session_keep_alive_heartbeat_frequency" |
| 176 | + ) |
| 177 | + ) |
| 178 | + ) |
0 commit comments