diff --git a/src/snowflake/cli/_plugins/connection/util.py b/src/snowflake/cli/_plugins/connection/util.py index 3fff14d568..b2adef6a8e 100644 --- a/src/snowflake/cli/_plugins/connection/util.py +++ b/src/snowflake/cli/_plugins/connection/util.py @@ -19,8 +19,7 @@ import os from enum import Enum from functools import lru_cache -from textwrap import dedent -from typing import Dict, Optional, TypeVar +from typing import Any, Dict, Optional from click.exceptions import ClickException from snowflake.connector import SnowflakeConnection @@ -60,12 +59,9 @@ class UIParameter(Enum): NA_FEATURE_RELEASE_CHANNELS = "FEATURE_RELEASE_CHANNELS" -T = TypeVar("T") - - def get_ui_parameter( - conn: SnowflakeConnection, parameter: UIParameter, default: T -) -> str | T: + conn: SnowflakeConnection, parameter: UIParameter, default: Any +) -> Any: """ Returns the value of a single UI parameter. If the parameter is not found, the default value is returned. @@ -76,26 +72,22 @@ def get_ui_parameter( @lru_cache() -def get_ui_parameters(conn: SnowflakeConnection) -> Dict[UIParameter, str]: +def get_ui_parameters(conn: SnowflakeConnection) -> Dict[UIParameter, Any]: """ Returns the UI parameters from the SYSTEM$BOOTSTRAP_DATA_REQUEST function """ - parameters_to_fetch = sorted([param.value for param in UIParameter]) + parameters_to_fetch = [param.value for param in UIParameter] - query = dedent( - f""" - select value['value']::string as PARAM_VALUE, value['name']::string as PARAM_NAME from table(flatten( - input => parse_json(SYSTEM$BOOTSTRAP_DATA_REQUEST()), - path => 'clientParamsInfo' - )) where value['name'] in ('{"', '".join(parameters_to_fetch)}'); - """ - ) + query = "call system$bootstrap_data_request('CLIENT_PARAMS_INFO')" + *_, cursor = conn.execute_string(query) - *_, cursor = conn.execute_string(query, cursor_class=DictCursor) + json_map = json.loads(cursor.fetchone()[0]) return { - UIParameter(row["PARAM_NAME"]): row["PARAM_VALUE"] for row in cursor.fetchall() + UIParameter(row["name"]): row["value"] + for row in json_map["clientParamsInfo"] + if row["name"] in parameters_to_fetch } @@ -107,12 +99,7 @@ def is_regionless_redirect(conn: SnowflakeConnection) -> bool: assume it's regionless, as this is true for most production deployments. """ try: - return ( - get_ui_parameter( - conn, UIParameter.NA_ENABLE_REGIONLESS_REDIRECT, "true" - ).lower() - == "true" - ) + return get_ui_parameter(conn, UIParameter.NA_ENABLE_REGIONLESS_REDIRECT, True) except: log.warning( "Cannot determine regionless redirect; assuming True.", exc_info=True diff --git a/src/snowflake/cli/_plugins/nativeapp/codegen/compiler.py b/src/snowflake/cli/_plugins/nativeapp/codegen/compiler.py index 7671969100..07302e6356 100644 --- a/src/snowflake/cli/_plugins/nativeapp/codegen/compiler.py +++ b/src/snowflake/cli/_plugins/nativeapp/codegen/compiler.py @@ -155,5 +155,5 @@ def _should_invoke_processors(self): def _is_enabled(self, processor: ProcessorMapping) -> bool: if processor.name.lower() == NA_SETUP_PROCESSOR: - return FeatureFlag.ENABLE_NATIVE_APP_PYTHON_SETUP.get_flag_value() is True + return FeatureFlag.ENABLE_NATIVE_APP_PYTHON_SETUP.is_enabled() return True diff --git a/src/snowflake/cli/_plugins/nativeapp/entities/application.py b/src/snowflake/cli/_plugins/nativeapp/entities/application.py index 759ee868e4..b93e680567 100644 --- a/src/snowflake/cli/_plugins/nativeapp/entities/application.py +++ b/src/snowflake/cli/_plugins/nativeapp/entities/application.py @@ -137,18 +137,12 @@ def __init__( self._is_dev_mode = install_method.is_dev_mode self._metrics = get_cli_context().metrics self._console = console - connection = get_sql_executor()._conn # noqa: SLF001 - self._event_sharing_enabled = ( - get_snowflake_facade() - .get_ui_parameter(UIParameter.NA_EVENT_SHARING_V2, "true") - .lower() - == "true" + + self._event_sharing_enabled = get_snowflake_facade().get_ui_parameter( + UIParameter.NA_EVENT_SHARING_V2, True ) - self._event_sharing_enforced = ( - get_snowflake_facade() - .get_ui_parameter(UIParameter.NA_ENFORCE_MANDATORY_FILTERS, "true") - .lower() - == "true" + self._event_sharing_enforced = get_snowflake_facade().get_ui_parameter( + UIParameter.NA_ENFORCE_MANDATORY_FILTERS, True ) self._share_mandatory_events = ( diff --git a/src/snowflake/cli/_plugins/nativeapp/entities/application_package.py b/src/snowflake/cli/_plugins/nativeapp/entities/application_package.py index 213791878c..c61b7939dc 100644 --- a/src/snowflake/cli/_plugins/nativeapp/entities/application_package.py +++ b/src/snowflake/cli/_plugins/nativeapp/entities/application_package.py @@ -831,17 +831,17 @@ def _get_enable_release_channels_flag(self) -> Optional[bool]: It retrieves the value from the configuration file and checks that the feature is enabled in the account. If return value is None, it means do not explicitly set the flag. """ - feature_flag_from_config = FeatureFlag.ENABLE_RELEASE_CHANNELS.get_flag_value() + feature_flag_from_config = FeatureFlag.ENABLE_RELEASE_CHANNELS.get_value() feature_enabled_in_account = ( - get_snowflake_facade() - .get_ui_parameter(UIParameter.NA_FEATURE_RELEASE_CHANNELS, "enabled") - .lower() - == "enabled" + get_snowflake_facade().get_ui_parameter( + UIParameter.NA_FEATURE_RELEASE_CHANNELS, "ENABLED" + ) + == "ENABLED" ) if feature_flag_from_config is not None and not feature_enabled_in_account: self._workspace_ctx.console.warning( - f"Cannot use feature flag {FeatureFlag.ENABLE_RELEASE_CHANNELS.name} because release channels are not enabled in the current account." + f"Ignoring feature flag {FeatureFlag.ENABLE_RELEASE_CHANNELS.name} because release channels are not enabled in the current account." ) return None diff --git a/src/snowflake/cli/_plugins/nativeapp/feature_flags.py b/src/snowflake/cli/_plugins/nativeapp/feature_flags.py index fe99799db4..dbc47e7483 100644 --- a/src/snowflake/cli/_plugins/nativeapp/feature_flags.py +++ b/src/snowflake/cli/_plugins/nativeapp/feature_flags.py @@ -12,45 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -from enum import Enum, unique -from typing import Any, NamedTuple, Optional +from enum import unique -from snowflake.cli.api.config import FEATURE_FLAGS_SECTION_PATH, get_config_value -from snowflake.cli.api.utils.types import try_cast_to_bool - - -class OptionalBooleanFlag(NamedTuple): - name: str - default: Optional[bool] = None - - -@unique -class OptionalFeatureFlagMixin(Enum): - """ - Mixin for feature flags that can be enabled, disabled, or unset. - """ - - def get_flag_value(self) -> Optional[bool]: - value = self._get_raw_value() - if value is None: - return self.value.default - return try_cast_to_bool(value) - - def _get_raw_value(self) -> Any: - return get_config_value( - *FEATURE_FLAGS_SECTION_PATH, - key=self.value.name.lower(), - default=None, - ) +from snowflake.cli.api.feature_flags import BooleanFlag, FeatureFlagMixin @unique -class FeatureFlag(OptionalFeatureFlagMixin): - """ - Enum for Native Apps feature flags. - """ - - ENABLE_NATIVE_APP_PYTHON_SETUP = OptionalBooleanFlag( +class FeatureFlag(FeatureFlagMixin): + ENABLE_NATIVE_APP_PYTHON_SETUP = BooleanFlag( "ENABLE_NATIVE_APP_PYTHON_SETUP", False ) - ENABLE_RELEASE_CHANNELS = OptionalBooleanFlag("ENABLE_RELEASE_CHANNELS", None) + ENABLE_RELEASE_CHANNELS = BooleanFlag("ENABLE_RELEASE_CHANNELS", None) diff --git a/src/snowflake/cli/_plugins/nativeapp/sf_sql_facade.py b/src/snowflake/cli/_plugins/nativeapp/sf_sql_facade.py index 42d8712888..bd7386ffef 100644 --- a/src/snowflake/cli/_plugins/nativeapp/sf_sql_facade.py +++ b/src/snowflake/cli/_plugins/nativeapp/sf_sql_facade.py @@ -16,7 +16,7 @@ import logging from contextlib import contextmanager from textwrap import dedent -from typing import Any, Dict, List, TypeVar +from typing import Any, Dict, List from snowflake.cli._plugins.connection.util import UIParameter, get_ui_parameter from snowflake.cli._plugins.nativeapp.constants import SPECIAL_COMMENT @@ -588,9 +588,7 @@ def alter_application_package_properties( f"Failed to update enable_release_channels for application package {package_name}.", ) - T = TypeVar("T") - - def get_ui_parameter(self, parameter: UIParameter, default: T) -> str | T: + def get_ui_parameter(self, parameter: UIParameter, default: Any) -> Any: """ Returns the value of a single UI parameter. If the parameter is not found, the default value is returned. diff --git a/src/snowflake/cli/api/config.py b/src/snowflake/cli/api/config.py index b6e26a68d7..0b5111f3ef 100644 --- a/src/snowflake/cli/api/config.py +++ b/src/snowflake/cli/api/config.py @@ -286,8 +286,12 @@ def get_config_value(*path, key: str, default: Optional[Any] = Empty) -> Any: raise -def get_config_bool_value(*path, key: str, default: Optional[Any] = Empty) -> bool: - value = get_config_value(*path, key=key, default=default) +def get_config_bool_value(*path, key: str, default: Any = Empty) -> bool | None: + value = get_config_value(*path, key=key, default=None) + + if value is None and default is not Empty: + return default + try: return try_cast_to_bool(value) except ValueError: diff --git a/src/snowflake/cli/api/feature_flags.py b/src/snowflake/cli/api/feature_flags.py index 2ed9728e55..d504056e02 100644 --- a/src/snowflake/cli/api/feature_flags.py +++ b/src/snowflake/cli/api/feature_flags.py @@ -24,20 +24,31 @@ class BooleanFlag(NamedTuple): name: str - default: bool = False + default: bool | None = False @unique class FeatureFlagMixin(Enum): - def is_enabled(self) -> bool: + def get_value(self) -> bool | None: return get_config_bool_value( *FEATURE_FLAGS_SECTION_PATH, key=self.value.name.lower(), default=self.value.default, ) - def is_disabled(self): - return not self.is_enabled() + def is_enabled(self) -> bool: + return self.get_value() is True + + def is_disabled(self) -> bool: + return self.get_value() is False + + def is_set(self) -> bool: + return ( + get_config_bool_value( + *FEATURE_FLAGS_SECTION_PATH, key=self.value.name.lower(), default=None + ) + is not None + ) def env_variable(self): return get_env_variable_name(*FEATURE_FLAGS_SECTION_PATH, key=self.value.name) diff --git a/tests/api/test_feature_flags.py b/tests/api/test_feature_flags.py index 0b41a3626f..d4d9da8e9c 100644 --- a/tests/api/test_feature_flags.py +++ b/tests/api/test_feature_flags.py @@ -15,7 +15,6 @@ from unittest import mock import pytest -from click import ClickException from snowflake.cli.api.feature_flags import BooleanFlag, FeatureFlagMixin @@ -23,22 +22,36 @@ class _TestFlags(FeatureFlagMixin): # Intentional inconsistency between constant and the enum name to make sure there's no strict relation ENABLED_BY_DEFAULT = BooleanFlag("ENABLED_DEFAULT", True) DISABLED_BY_DEFAULT = BooleanFlag("DISABLED_DEFAULT", False) - NON_BOOLEAN = BooleanFlag("NON_BOOLEAN", "xys") # type: ignore + NON_BOOLEAN_DEFAULT = BooleanFlag("NON_BOOLEAN", "xys") # type: ignore + NONE_AS_DEFAULT = BooleanFlag("NON_BOOLEAN", "xys") # type: ignore -def test_flag_value_has_to_be_boolean(): - with pytest.raises(ClickException): - _TestFlags.NON_BOOLEAN.is_enabled() +def test_flag_value_default_non_boolean(): + _TestFlags.NON_BOOLEAN_DEFAULT.is_enabled() is False + _TestFlags.NON_BOOLEAN_DEFAULT.is_disabled() is False + _TestFlags.NON_BOOLEAN_DEFAULT.get_value() == "xys" + _TestFlags.NON_BOOLEAN_DEFAULT.is_set() is True + + +def test_flag_value_default_is_none(): + _TestFlags.NONE_AS_DEFAULT.is_enabled() is False + _TestFlags.NONE_AS_DEFAULT.is_disabled() is False + _TestFlags.NONE_AS_DEFAULT.get_value() is None + _TestFlags.NONE_AS_DEFAULT.is_set() is False def test_flag_is_enabled(): assert _TestFlags.ENABLED_BY_DEFAULT.is_enabled() is True assert _TestFlags.ENABLED_BY_DEFAULT.is_disabled() is False + assert _TestFlags.ENABLED_BY_DEFAULT.get_value() is True + assert _TestFlags.ENABLED_BY_DEFAULT.is_set() is False def test_flag_is_disabled(): assert _TestFlags.DISABLED_BY_DEFAULT.is_enabled() is False assert _TestFlags.DISABLED_BY_DEFAULT.is_disabled() is True + assert _TestFlags.DISABLED_BY_DEFAULT.get_value() is False + assert _TestFlags.DISABLED_BY_DEFAULT.is_set() is False def test_flag_env_variable_value(): @@ -53,13 +66,50 @@ def test_flag_env_variable_value(): @mock.patch("snowflake.cli.api.config.get_config_value") -@pytest.mark.parametrize("value_from_config", [True, False]) -def test_flag_from_config_file(mock_get_config_value, value_from_config): +@pytest.mark.parametrize("value_from_config", [True, False, None]) +def test_is_enabled_flag_from_config_file(mock_get_config_value, value_from_config): + mock_get_config_value.return_value = value_from_config + + assert _TestFlags.DISABLED_BY_DEFAULT.is_enabled() is (value_from_config or False) + mock_get_config_value.assert_called_once_with( + "cli", "features", key="disabled_default", default=None + ) + + +@mock.patch("snowflake.cli.api.config.get_config_value") +@pytest.mark.parametrize("value_from_config", [True, False, None]) +def test_is_disabled_flag_from_config_file(mock_get_config_value, value_from_config): + mock_get_config_value.return_value = value_from_config + + assert _TestFlags.DISABLED_BY_DEFAULT.is_disabled() is not ( + value_from_config or False + ) + mock_get_config_value.assert_called_once_with( + "cli", "features", key="disabled_default", default=None + ) + + +@mock.patch("snowflake.cli.api.config.get_config_value") +@pytest.mark.parametrize("value_from_config", [True, False, None]) +def test_is_set_flag_from_config_file(mock_get_config_value, value_from_config): mock_get_config_value.return_value = value_from_config - assert _TestFlags.DISABLED_BY_DEFAULT.is_enabled() is value_from_config + assert _TestFlags.DISABLED_BY_DEFAULT.is_set() is (value_from_config is not None) + + mock_get_config_value.assert_called_once_with( + "cli", "features", key="disabled_default", default=None + ) + + +@mock.patch("snowflake.cli.api.config.get_config_value") +@pytest.mark.parametrize("value_from_config", [True, False, None]) +def test_get_value_flag_from_config_file(mock_get_config_value, value_from_config): + mock_get_config_value.return_value = value_from_config + + assert _TestFlags.DISABLED_BY_DEFAULT.get_value() == (value_from_config or False) + mock_get_config_value.assert_called_once_with( - "cli", "features", key="disabled_default", default=False + "cli", "features", key="disabled_default", default=None ) diff --git a/tests/nativeapp/test_application_package_entity.py b/tests/nativeapp/test_application_package_entity.py index 2c1690e32a..d07683ac94 100644 --- a/tests/nativeapp/test_application_package_entity.py +++ b/tests/nativeapp/test_application_package_entity.py @@ -77,7 +77,7 @@ def test_bundle(project_directory): @mock.patch(f"{APP_PACKAGE_ENTITY}.execute_post_deploy_hooks") @mock.patch(f"{APP_PACKAGE_ENTITY}.validate_setup_script") @mock.patch(f"{APPLICATION_PACKAGE_ENTITY_MODULE}.sync_deploy_root_with_stage") -@mock.patch(SQL_FACADE_GET_UI_PARAMETER, return_value="enabled") +@mock.patch(SQL_FACADE_GET_UI_PARAMETER, return_value="ENABLED") def test_deploy( mock_get_parameter, mock_sync, @@ -169,7 +169,7 @@ def test_deploy( mock_validate.assert_called_once() mock_execute_post_deploy_hooks.assert_called_once_with() mock_get_parameter.assert_called_once_with( - UIParameter.NA_FEATURE_RELEASE_CHANNELS, "enabled" + UIParameter.NA_FEATURE_RELEASE_CHANNELS, "ENABLED" ) assert mock_execute.mock_calls == expected diff --git a/tests/nativeapp/test_event_sharing.py b/tests/nativeapp/test_event_sharing.py index c26285f9b8..041957ebf3 100644 --- a/tests/nativeapp/test_event_sharing.py +++ b/tests/nativeapp/test_event_sharing.py @@ -426,8 +426,8 @@ def _setup_mocks_for_upgrade_app( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @pytest.mark.parametrize( @@ -497,8 +497,8 @@ def test_event_sharing_disabled_no_change_to_current_behavior( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @pytest.mark.parametrize( @@ -562,8 +562,8 @@ def test_event_sharing_disabled_but_we_add_event_sharing_flag_in_project_definit @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "true", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: True, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @pytest.mark.parametrize( @@ -626,8 +626,8 @@ def test_event_sharing_enabled_not_enforced_no_mandatory_events_then_flag_respec @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "true", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "true", + UIParameter.NA_EVENT_SHARING_V2: True, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: True, }, ) @pytest.mark.parametrize( @@ -690,8 +690,8 @@ def test_event_sharing_enabled_when_upgrade_flag_matches_existing_app_then_do_no @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "true", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: True, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @pytest.mark.parametrize( @@ -760,8 +760,8 @@ def test_event_sharing_enabled_with_mandatory_events_and_explicit_authorization_ @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "true", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: True, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @pytest.mark.parametrize( @@ -835,8 +835,8 @@ def test_event_sharing_enabled_with_mandatory_events_but_no_authorization_then_f @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "true", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "true", + UIParameter.NA_EVENT_SHARING_V2: True, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: True, }, ) @pytest.mark.parametrize( @@ -897,8 +897,8 @@ def test_enforced_events_sharing_with_no_mandatory_events_then_use_value_provide @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "true", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "true", + UIParameter.NA_EVENT_SHARING_V2: True, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: True, }, ) @pytest.mark.parametrize( @@ -958,8 +958,8 @@ def test_enforced_events_sharing_with_mandatory_events_and_authorization_provide @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "true", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "true", + UIParameter.NA_EVENT_SHARING_V2: True, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: True, }, ) @pytest.mark.parametrize( @@ -1032,8 +1032,8 @@ def test_enforced_events_sharing_with_mandatory_events_and_authorization_refused @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "true", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "true", + UIParameter.NA_EVENT_SHARING_V2: True, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: True, }, ) @pytest.mark.parametrize( @@ -1106,8 +1106,8 @@ def test_enforced_events_sharing_with_mandatory_events_manifest_and_authorizatio @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "true", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "true", + UIParameter.NA_EVENT_SHARING_V2: True, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: True, }, ) @pytest.mark.parametrize( @@ -1167,8 +1167,8 @@ def test_enforced_events_sharing_with_mandatory_events_and_dev_mode_then_default @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "true", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "true", + UIParameter.NA_EVENT_SHARING_V2: True, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: True, }, ) @pytest.mark.parametrize( @@ -1239,8 +1239,8 @@ def test_enforced_events_sharing_with_mandatory_events_and_authorization_not_spe @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "true", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "true", + UIParameter.NA_EVENT_SHARING_V2: True, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: True, }, ) @pytest.mark.parametrize( @@ -1305,8 +1305,8 @@ def test_enforced_events_sharing_with_mandatory_events_and_authorization_not_spe @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "true", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "true", + UIParameter.NA_EVENT_SHARING_V2: True, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: True, }, ) @pytest.mark.parametrize( @@ -1369,8 +1369,8 @@ def test_shared_events_with_no_enabled_mandatory_events_then_error( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "true", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "true", + UIParameter.NA_EVENT_SHARING_V2: True, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: True, }, ) @pytest.mark.parametrize( diff --git a/tests/nativeapp/test_feature_flags.py b/tests/nativeapp/test_feature_flags.py index 5215004c61..6c40d47ad4 100644 --- a/tests/nativeapp/test_feature_flags.py +++ b/tests/nativeapp/test_feature_flags.py @@ -18,16 +18,14 @@ from snowflake.cli._plugins.nativeapp.feature_flags import FeatureFlag -@mock.patch("snowflake.cli._plugins.nativeapp.feature_flags.get_config_value") +@mock.patch("snowflake.cli.api.config.get_config_value") @pytest.mark.parametrize("value_from_config", [True, False]) def test_feature_setup_script_generation_enabled( mock_get_config_value, value_from_config ): mock_get_config_value.return_value = value_from_config - assert ( - FeatureFlag.ENABLE_NATIVE_APP_PYTHON_SETUP.get_flag_value() == value_from_config - ) + assert FeatureFlag.ENABLE_NATIVE_APP_PYTHON_SETUP.is_enabled() is value_from_config mock_get_config_value.assert_called_once_with( "cli", "features", key="enable_native_app_python_setup", default=None ) diff --git a/tests/nativeapp/test_manager.py b/tests/nativeapp/test_manager.py index 5422c63583..603e0ca7f4 100644 --- a/tests/nativeapp/test_manager.py +++ b/tests/nativeapp/test_manager.py @@ -776,9 +776,9 @@ def test_get_snowsight_url_without_pdf_warehouse( # Test create_app_package() with no existing package available @mock.patch(APP_PACKAGE_ENTITY_GET_EXISTING_APP_PKG_INFO, return_value=None) -@mock.patch(SQL_FACADE_GET_UI_PARAMETER, return_value="enabled") +@mock.patch(SQL_FACADE_GET_UI_PARAMETER, return_value="ENABLED") @mock.patch(SQL_FACADE_CREATE_APP_PKG) -@mock.patch("snowflake.cli._plugins.nativeapp.feature_flags.get_config_value") +@mock.patch("snowflake.cli.api.config.get_config_value") @pytest.mark.parametrize("feature_flag", [True, False, None]) def test_given_no_existing_pkg_when_create_app_pkg_then_success_and_respect_release_channels_flag( mock_get_config_value, @@ -819,9 +819,9 @@ def test_given_no_existing_pkg_when_create_app_pkg_then_success_and_respect_rele @mock.patch(APP_PACKAGE_ENTITY_GET_EXISTING_APP_PKG_INFO) @mock_get_app_pkg_distribution_in_sf() @mock.patch(APP_PACKAGE_ENTITY_IS_DISTRIBUTION_SAME) -@mock.patch(SQL_FACADE_GET_UI_PARAMETER, return_value="enabled") +@mock.patch(SQL_FACADE_GET_UI_PARAMETER, return_value="ENABLED") @mock.patch(SQL_FACADE_ALTER_APP_PKG_PROPERTIES) -@mock.patch("snowflake.cli._plugins.nativeapp.feature_flags.get_config_value") +@mock.patch("snowflake.cli.api.config.get_config_value") @pytest.mark.parametrize("feature_flag", [True, False, None]) def test_given_existing_app_package_with_feature_flag_set_when_create_pkg_then_set_pkg_property_to_same_value( mock_get_config_value, @@ -872,7 +872,7 @@ def test_given_existing_app_package_with_feature_flag_set_when_create_pkg_then_s @mock.patch(APP_PACKAGE_ENTITY_GET_EXISTING_APP_PKG_INFO) @mock_get_app_pkg_distribution_in_sf() @mock.patch(APP_PACKAGE_ENTITY_IS_DISTRIBUTION_SAME, return_value=True) -@mock.patch(SQL_FACADE_GET_UI_PARAMETER, return_value="enabled") +@mock.patch(SQL_FACADE_GET_UI_PARAMETER, return_value="ENABLED") def test_create_app_pkg_different_owner( mock_get_ui_parameter, mock_is_distribution_same, @@ -917,7 +917,7 @@ def test_create_app_pkg_different_owner( "is_pkg_distribution_same", [False, True], ) -@mock.patch(SQL_FACADE_GET_UI_PARAMETER, return_value="enabled") +@mock.patch(SQL_FACADE_GET_UI_PARAMETER, return_value="ENABLED") def test_create_app_pkg_external_distribution( mock_get_ui_parameter, mock_is_distribution_same, @@ -967,7 +967,7 @@ def test_create_app_pkg_external_distribution( (True, SPECIAL_COMMENT_OLD), ], ) -@mock.patch(SQL_FACADE_GET_UI_PARAMETER, return_value="enabled") +@mock.patch(SQL_FACADE_GET_UI_PARAMETER, return_value="ENABLED") def test_create_app_pkg_internal_distribution_special_comment( mock_get_ui_parameter, mock_is_distribution_same, diff --git a/tests/nativeapp/test_run_processor.py b/tests/nativeapp/test_run_processor.py index 9a91c9f88b..675ace73a1 100644 --- a/tests/nativeapp/test_run_processor.py +++ b/tests/nativeapp/test_run_processor.py @@ -204,8 +204,8 @@ def setup_project_file(current_working_directory: str, pdf=None): @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) def test_create_dev_app_w_warehouse_access_exception( @@ -263,8 +263,8 @@ def test_create_dev_app_w_warehouse_access_exception( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) def test_create_dev_app_create_new_w_no_additional_privileges( @@ -336,8 +336,8 @@ def test_create_dev_app_create_new_w_no_additional_privileges( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @pytest.mark.parametrize( @@ -469,8 +469,8 @@ def test_create_or_upgrade_dev_app_with_warning( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) def test_create_dev_app_create_new_with_additional_privileges( @@ -560,8 +560,8 @@ def test_create_dev_app_create_new_with_additional_privileges( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) def test_create_dev_app_create_new_w_missing_warehouse_exception( @@ -629,8 +629,8 @@ def test_create_dev_app_create_new_w_missing_warehouse_exception( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @pytest.mark.parametrize( @@ -695,8 +695,8 @@ def test_create_dev_app_incorrect_properties( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) def test_create_dev_app_incorrect_owner( @@ -760,8 +760,8 @@ def test_create_dev_app_incorrect_owner( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @mock_connection() @@ -844,8 +844,8 @@ def test_create_dev_app_no_diff_changes( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) def test_create_dev_app_w_diff_changes( @@ -927,8 +927,8 @@ def test_create_dev_app_w_diff_changes( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) def test_create_dev_app_recreate_w_missing_warehouse_exception( @@ -994,8 +994,8 @@ def test_create_dev_app_recreate_w_missing_warehouse_exception( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) def test_create_dev_app_create_new_quoted( @@ -1094,8 +1094,8 @@ def test_create_dev_app_create_new_quoted( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) def test_create_dev_app_create_new_quoted_override( @@ -1177,8 +1177,8 @@ def test_create_dev_app_create_new_quoted_override( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) def test_create_dev_app_recreate_app_when_orphaned( @@ -1284,8 +1284,8 @@ def test_create_dev_app_recreate_app_when_orphaned( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) def test_create_dev_app_recreate_app_when_orphaned_requires_cascade( @@ -1410,8 +1410,8 @@ def test_create_dev_app_recreate_app_when_orphaned_requires_cascade( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) def test_create_dev_app_recreate_app_when_orphaned_requires_cascade_unknown_objects( @@ -1523,8 +1523,8 @@ def test_create_dev_app_recreate_app_when_orphaned_requires_cascade_unknown_obje @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @pytest.mark.parametrize( @@ -1578,8 +1578,8 @@ def test_upgrade_app_warehouse_error( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @pytest.mark.parametrize( @@ -1643,8 +1643,8 @@ def test_upgrade_app_incorrect_owner( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @pytest.mark.parametrize( @@ -1723,8 +1723,8 @@ def test_upgrade_app_succeeds( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @pytest.mark.parametrize( @@ -1792,8 +1792,8 @@ def test_upgrade_app_fails_generic_error( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @pytest.mark.parametrize( @@ -1860,8 +1860,8 @@ def test_upgrade_app_fails_upgrade_restriction_error( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) def test_versioned_app_upgrade_to_unversioned( @@ -1976,8 +1976,8 @@ def test_versioned_app_upgrade_to_unversioned( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @pytest.mark.parametrize( @@ -2052,8 +2052,8 @@ def test_upgrade_app_fails_drop_fails( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @pytest.mark.parametrize("policy_param", [allow_always_policy, ask_always_policy]) @@ -2212,8 +2212,8 @@ def test_upgrade_app_from_version_throws_usage_error_two( @mock.patch( GET_UI_PARAMETERS, return_value={ - UIParameter.NA_EVENT_SHARING_V2: "false", - UIParameter.NA_ENFORCE_MANDATORY_FILTERS: "false", + UIParameter.NA_EVENT_SHARING_V2: False, + UIParameter.NA_ENFORCE_MANDATORY_FILTERS: False, }, ) @pytest.mark.parametrize("policy_param", [allow_always_policy, ask_always_policy]) diff --git a/tests/nativeapp/test_sf_sql_facade.py b/tests/nativeapp/test_sf_sql_facade.py index ce2b6de0aa..c97a7cfe79 100644 --- a/tests/nativeapp/test_sf_sql_facade.py +++ b/tests/nativeapp/test_sf_sql_facade.py @@ -1865,15 +1865,7 @@ def test_given_privilege_exception_when_update_application_package_then_raise_pr ) -ui_parameters_str = ", ".join(sorted([f"'{param.value}'" for param in UIParameter])) -expected_ui_params_query = dedent( - f""" - select value['value']::string as PARAM_VALUE, value['name']::string as PARAM_NAME from table(flatten( - input => parse_json(SYSTEM$BOOTSTRAP_DATA_REQUEST()), - path => 'clientParamsInfo' - )) where value['name'] in ({ui_parameters_str}); - """ -) +expected_ui_params_query = "call system$bootstrap_data_request('CLIENT_PARAMS_INFO')" def test_get_ui_parameter_with_value(mock_cursor): @@ -1883,25 +1875,27 @@ def test_get_ui_parameter_with_value(mock_cursor): None, mock_cursor( [ - { - "PARAM_NAME": UIParameter.NA_FEATURE_RELEASE_CHANNELS.value, - "PARAM_VALUE": "true", - } + ( + """\ + { + "clientParamsInfo": [{ + "name": "FEATURE_RELEASE_CHANNELS", + "value": true + }] + } + """, + ) ], [], ), ) assert ( - sql_facade.get_ui_parameter( - UIParameter.NA_FEATURE_RELEASE_CHANNELS, "false" - ) - == "true" + sql_facade.get_ui_parameter(UIParameter.NA_FEATURE_RELEASE_CHANNELS, False) + is True ) - execute_str_mock.assert_called_once_with( - expected_ui_params_query, cursor_class=DictCursor - ) + execute_str_mock.assert_called_once_with(expected_ui_params_query) def test_get_ui_parameter_with_empty_value_then_use_empty_value(mock_cursor): @@ -1911,25 +1905,27 @@ def test_get_ui_parameter_with_empty_value_then_use_empty_value(mock_cursor): None, mock_cursor( [ - { - "PARAM_NAME": UIParameter.NA_FEATURE_RELEASE_CHANNELS.value, - "PARAM_VALUE": "", - } + ( + """\ + { + "clientParamsInfo": [{ + "name": "FEATURE_RELEASE_CHANNELS", + "value": "" + }] + } + """, + ) ], [], ), ) assert ( - sql_facade.get_ui_parameter( - UIParameter.NA_FEATURE_RELEASE_CHANNELS, "false" - ) + sql_facade.get_ui_parameter(UIParameter.NA_FEATURE_RELEASE_CHANNELS, False) == "" ) - execute_str_mock.assert_called_once_with( - expected_ui_params_query, cursor_class=DictCursor - ) + execute_str_mock.assert_called_once_with(expected_ui_params_query) def test_get_ui_parameter_with_no_value_then_use_default(mock_cursor): @@ -1938,7 +1934,15 @@ def test_get_ui_parameter_with_no_value_then_use_default(mock_cursor): execute_str_mock.return_value = ( None, mock_cursor( - [], + [ + ( + """\ + { + "clientParamsInfo": [] + } + """, + ) + ], [], ), ) @@ -1950,6 +1954,4 @@ def test_get_ui_parameter_with_no_value_then_use_default(mock_cursor): == "false" ) - execute_str_mock.assert_called_once_with( - expected_ui_params_query, cursor_class=DictCursor - ) + execute_str_mock.assert_called_once_with(expected_ui_params_query) diff --git a/tests/streamlit/test_commands.py b/tests/streamlit/test_commands.py index 68464053bd..f0d53541bd 100644 --- a/tests/streamlit/test_commands.py +++ b/tests/streamlit/test_commands.py @@ -66,7 +66,7 @@ def _put_query(source: str, dest: str): @mock.patch("snowflake.connector.connect") @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) @mock_streamlit_exists def test_deploy_only_streamlit_file( @@ -121,7 +121,7 @@ def test_deploy_only_streamlit_file( @mock.patch("snowflake.connector.connect") @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) @mock_streamlit_exists def test_deploy_only_streamlit_file_no_stage( @@ -175,7 +175,7 @@ def test_deploy_only_streamlit_file_no_stage( @mock.patch("snowflake.connector.connect") @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) @mock_streamlit_exists def test_deploy_with_empty_pages( @@ -231,7 +231,7 @@ def test_deploy_with_empty_pages( @mock.patch("snowflake.connector.connect") @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) @mock_streamlit_exists def test_deploy_only_streamlit_file_replace( @@ -302,7 +302,7 @@ def test_artifacts_must_exists( @mock.patch("snowflake.connector.connect") @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) @mock_streamlit_exists def test_deploy_launch_browser( @@ -337,7 +337,7 @@ def test_deploy_launch_browser( @mock.patch("snowflake.connector.connect") @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) @mock_streamlit_exists def test_deploy_streamlit_and_environment_files( @@ -382,7 +382,7 @@ def test_deploy_streamlit_and_environment_files( @mock.patch("snowflake.connector.connect") @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) @mock_streamlit_exists def test_deploy_streamlit_and_pages_files( @@ -426,7 +426,7 @@ def test_deploy_streamlit_and_pages_files( @mock.patch("snowflake.connector.connect") @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) @mock_streamlit_exists def test_deploy_all_streamlit_files( @@ -471,7 +471,7 @@ def test_deploy_all_streamlit_files( @mock.patch("snowflake.connector.connect") @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) @mock_streamlit_exists def test_deploy_put_files_on_stage( @@ -518,7 +518,7 @@ def test_deploy_put_files_on_stage( @mock.patch("snowflake.connector.connect") @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) @mock_streamlit_exists def test_deploy_all_streamlit_files_not_defaults( @@ -563,7 +563,7 @@ def test_deploy_all_streamlit_files_not_defaults( @pytest.mark.parametrize("enable_streamlit_no_checkouts", [True, False]) @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) @mock_streamlit_exists def test_deploy_streamlit_main_and_pages_files_experimental( @@ -640,7 +640,7 @@ def test_deploy_streamlit_main_and_pages_files_experimental( @mock.patch("snowflake.connector.connect") @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) @mock_streamlit_exists def test_deploy_streamlit_main_and_pages_files_experimental_double_deploy( @@ -707,7 +707,7 @@ def test_deploy_streamlit_main_and_pages_files_experimental_double_deploy( @pytest.mark.parametrize("enable_streamlit_versioned_stage", [True, False]) @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) @mock_streamlit_exists def test_deploy_streamlit_main_and_pages_files_experimental_no_stage( @@ -769,7 +769,7 @@ def test_deploy_streamlit_main_and_pages_files_experimental_no_stage( @mock.patch("snowflake.connector.connect") @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) @mock_streamlit_exists def test_deploy_streamlit_main_and_pages_files_experimental_replace( @@ -862,7 +862,7 @@ def test_drop_streamlit(mock_connector, runner, mock_ctx): @mock.patch("snowflake.connector.connect") @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) def test_get_streamlit_url(mock_param, mock_connector, mock_cursor, runner, mock_ctx): ctx = mock_ctx( @@ -944,7 +944,7 @@ def test_multiple_streamlit_raise_error_if_multiple_entities( @mock.patch("snowflake.connector.connect") @mock.patch( GET_UI_PARAMETERS, - return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "false"}, + return_value={UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: False}, ) def test_deploy_streamlit_with_comment_v2( mock_param, mock_connector, mock_cursor, runner, mock_ctx, project_directory diff --git a/tests/test_utils.py b/tests/test_utils.py index 92383086c2..10eadc479a 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -15,7 +15,6 @@ import json import os from pathlib import Path -from textwrap import dedent from unittest import mock from unittest.mock import MagicMock, patch @@ -37,7 +36,6 @@ from snowflake.cli.api.secure_path import SecurePath from snowflake.cli.api.utils import path_utils from snowflake.connector import SnowflakeConnection -from snowflake.connector.cursor import DictCursor from tests.test_data import test_data @@ -293,110 +291,153 @@ def test_get_host_region(host, expected): assert get_host_region(host) == expected -ui_parameters_str = ", ".join(sorted([f"'{param.value}'" for param in UIParameter])) -expected_ui_params_query = dedent( - f""" - select value['value']::string as PARAM_VALUE, value['name']::string as PARAM_NAME from table(flatten( - input => parse_json(SYSTEM$BOOTSTRAP_DATA_REQUEST()), - path => 'clientParamsInfo' - )) where value['name'] in ({ui_parameters_str}); - """ -) +expected_ui_params_query = "call system$bootstrap_data_request('CLIENT_PARAMS_INFO')" -def test_get_ui_parameters_no_param(): +def test_get_ui_parameters_no_param(mock_cursor): connection = MagicMock() - cursor = MagicMock() - connection.execute_string.return_value = (None, cursor) - cursor.fetchall.return_value = [] + connection.execute_string.return_value = ( + None, + mock_cursor([('{"clientParamsInfo": []}',)], []), + ) + assert get_ui_parameters(connection) == {} - connection.execute_string.assert_called_with( - expected_ui_params_query, cursor_class=DictCursor - ) + connection.execute_string.assert_called_with(expected_ui_params_query) -def test_get_ui_parameters_one_param(): +def test_get_ui_parameters_one_param(mock_cursor): connection = MagicMock() - cursor = MagicMock() - connection.execute_string.return_value = (None, cursor) - cursor.fetchall.return_value = [ - { - "PARAM_NAME": UIParameter.NA_ENABLE_REGIONLESS_REDIRECT.value, - "PARAM_VALUE": "true", - } - ] + connection.execute_string.return_value = ( + None, + mock_cursor( + [ + ( + """\ + { + "clientParamsInfo": [{ + "name": "UI_SNOWSIGHT_ENABLE_REGIONLESS_REDIRECT", + "value": true + }] + } + """, + ) + ], + [], + ), + ) + assert get_ui_parameters(connection) == { - UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "true" + UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: True } - connection.execute_string.assert_called_with( - expected_ui_params_query, cursor_class=DictCursor - ) + connection.execute_string.assert_called_with(expected_ui_params_query) -def test_get_ui_parameters_multiple_params(): +def test_get_ui_parameters_multiple_params(mock_cursor): connection = MagicMock() - cursor = MagicMock() - connection.execute_string.return_value = (None, cursor) - cursor.fetchall.return_value = [ - { - "PARAM_NAME": UIParameter.NA_ENABLE_REGIONLESS_REDIRECT.value, - "PARAM_VALUE": "true", - }, - { - "PARAM_NAME": UIParameter.NA_EVENT_SHARING_V2.value, - "PARAM_VALUE": "false", - }, - ] + connection.execute_string.return_value = ( + None, + mock_cursor( + [ + ( + """\ + { + "clientParamsInfo": [{ + "name": "UI_SNOWSIGHT_ENABLE_REGIONLESS_REDIRECT", + "value": true + }, + { + "name": "ENABLE_EVENT_SHARING_V2_IN_THE_SAME_ACCOUNT", + "value": false + }] + } + """, + ) + ], + [], + ), + ) + assert get_ui_parameters(connection) == { - UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: "true", - UIParameter.NA_EVENT_SHARING_V2: "false", + UIParameter.NA_ENABLE_REGIONLESS_REDIRECT: True, + UIParameter.NA_EVENT_SHARING_V2: False, } - connection.execute_string.assert_called_with( - expected_ui_params_query, cursor_class=DictCursor - ) + connection.execute_string.assert_called_with(expected_ui_params_query) -def test_get_ui_parameter_with_value(): +def test_get_ui_parameter_with_value(mock_cursor): connection = MagicMock() - cursor = MagicMock() - connection.execute_string.return_value = (None, cursor) - cursor.fetchall.return_value = [ - { - "PARAM_NAME": UIParameter.NA_ENABLE_REGIONLESS_REDIRECT.value, - "PARAM_VALUE": "true", - } - ] + connection.execute_string.return_value = ( + None, + mock_cursor( + [ + ( + """\ + { + "clientParamsInfo": [{ + "name": "UI_SNOWSIGHT_ENABLE_REGIONLESS_REDIRECT", + "value": true + }] + } + """, + ) + ], + [], + ), + ) assert ( - get_ui_parameter(connection, UIParameter.NA_ENABLE_REGIONLESS_REDIRECT, "false") - == "true" + get_ui_parameter(connection, UIParameter.NA_ENABLE_REGIONLESS_REDIRECT, False) + is True ) -def test_get_ui_parameter_with_empty_value_then_use_empty_value(): +def test_get_ui_parameter_with_empty_value_then_use_empty_value(mock_cursor): connection = MagicMock() - cursor = MagicMock() - connection.execute_string.return_value = (None, cursor) - cursor.fetchall.return_value = [ - { - "PARAM_NAME": UIParameter.NA_ENABLE_REGIONLESS_REDIRECT.value, - "PARAM_VALUE": "", - } - ] + connection.execute_string.return_value = ( + None, + mock_cursor( + [ + ( + """\ + { + "clientParamsInfo": [{ + "name": "UI_SNOWSIGHT_ENABLE_REGIONLESS_REDIRECT", + "value": "" + }] + } + """, + ) + ], + [], + ), + ) assert ( get_ui_parameter(connection, UIParameter.NA_ENABLE_REGIONLESS_REDIRECT, "false") == "" ) -def test_get_ui_parameter_with_no_value_then_use_default(): +def test_get_ui_parameter_with_no_value_then_use_default(mock_cursor): connection = MagicMock() - cursor = MagicMock() - connection.execute_string.return_value = (None, cursor) - cursor.fetchall.return_value = [] + connection.execute_string.return_value = ( + None, + mock_cursor( + [ + ( + """\ + { + "clientParamsInfo": [] + } + """, + ) + ], + [], + ), + ) + assert ( - get_ui_parameter(connection, UIParameter.NA_ENABLE_REGIONLESS_REDIRECT, "false") - == "false" + get_ui_parameter(connection, UIParameter.NA_ENABLE_REGIONLESS_REDIRECT, "any") + == "any" )