def test_loader_initialization(cache_full): # noqa: F811 # Set up variables in_memory_features = {} temp_cache = cache_full # Tests load_features(temp_cache, in_memory_features, DEFAULT_STRATEGY_MAPPING) assert isinstance(in_memory_features["GradualRolloutUserID"], Feature) assert isinstance(in_memory_features["GradualRolloutUserID"].strategies[0], GradualRolloutUserId) for feature_name in in_memory_features.keys(): if feature_name == 'Garbage': # Don't check purposely invalid strategy. break feature = in_memory_features[feature_name] assert len(feature.strategies) > 0 strategy = feature.strategies[0] if isinstance(strategy, UserWithId): assert strategy.parameters assert len(strategy.parsed_provisioning) if isinstance(strategy, FlexibleRollout): len(strategy.parsed_constraints) > 0 if isinstance(strategy, Variants): assert strategy.variants
def fetch_and_load_features(url: str, app_name: str, instance_id: str, custom_headers: dict, custom_options: dict, cache: BaseCache, features: dict, strategy_mapping: dict, project: str = None) -> None: (feature_provisioning, etag) = get_feature_toggles( url, app_name, instance_id, custom_headers, custom_options, project, cache.get(ETAG) ) if feature_provisioning: cache.set(FEATURES_URL, feature_provisioning) else: LOGGER.debug("No feature provisioning returned from server, using cached provisioning.") if etag: cache.set(ETAG, etag) load_features(cache, features, strategy_mapping)
def test_loader_initialization_failure(cache_custom): # noqa: F811 # Set up variables in_memory_features = {} temp_cache = cache_custom # Tests load_features(temp_cache, in_memory_features, DEFAULT_STRATEGY_MAPPING) assert isinstance(in_memory_features["UserWithId"], Feature)
def test_loader_segments(cache_segments): # Set up variables in_memory_features = {} temp_cache = cache_segments load_features(temp_cache, in_memory_features, DEFAULT_STRATEGY_MAPPING) feature = in_memory_features["Test"] loaded_constraints = list(feature.strategies[0].parsed_constraints) assert(len(loaded_constraints) == 2)
def test_loader_initialization(cache_full): # noqa: F811 # Set up variables in_memory_features = {} temp_cache = cache_full # Tests load_features(temp_cache, in_memory_features) assert isinstance(in_memory_features["GradualRolloutUserID"], Feature) assert isinstance(in_memory_features["GradualRolloutUserID"].strategies[0], GradualRolloutUserId)
def fetch_and_load_features(url, app_name, instance_id, custom_headers, cache, features, strategy_mapping): feature_provisioning = get_feature_toggles(url, app_name, instance_id, custom_headers) if feature_provisioning: cache[FEATURES_URL] = feature_provisioning cache.sync() else: LOGGER.info("Unable to get feature flag toggles, using cached values.") load_features(cache, features, strategy_mapping)
def fetch_and_load_features(url: str, app_name: str, instance_id: str, custom_headers: dict, cache: FileCache, strategies: dict) -> None: feature_provisioning = get_feature_toggles(url, app_name, instance_id, custom_headers) if feature_provisioning: cache[FEATURES_URL] = feature_provisioning cache.sync() else: LOGGER.info("Unable to get feature flag toggles, using cached values.") load_features(cache, strategies)
def test_loader_refresh(cache_full): # noqa: F811 # Set up variables in_memory_features = {} temp_cache = cache_full load_features(temp_cache, in_memory_features) # Simulate update mutation temp_cache[FEATURES_URL] = MOCK_UPDATED temp_cache.sync() load_features(temp_cache, in_memory_features) assert in_memory_features["GradualRolloutUserID"].strategies[0].parameters[ "percentage"] == 60
def test_loader_refresh_variants(cache_full): # noqa: F811 # Set up variables in_memory_features = {} temp_cache = cache_full load_features(temp_cache, in_memory_features, DEFAULT_STRATEGY_MAPPING) # Simulate update mutation mock_updated = copy.deepcopy(MOCK_ALL_FEATURES) mock_updated["features"][8]["variants"][0]["name"] = "VariantA" temp_cache.set(FEATURES_URL, mock_updated) load_features(temp_cache, in_memory_features, DEFAULT_STRATEGY_MAPPING) assert in_memory_features["Variations"].variants.variants[0]["name"] == "VariantA"
def test_loader_refresh_strategies(cache_full): # noqa: F811 # Set up variables in_memory_features = {} temp_cache = cache_full load_features(temp_cache, in_memory_features, DEFAULT_STRATEGY_MAPPING) # Simulate update mutation mock_updated = copy.deepcopy(MOCK_ALL_FEATURES) mock_updated["features"][4]["strategies"][0]["parameters"]["percentage"] = 60 temp_cache.set(FEATURES_URL, mock_updated) load_features(temp_cache, in_memory_features, DEFAULT_STRATEGY_MAPPING) assert in_memory_features["GradualRolloutUserID"].strategies[0].parameters["percentage"] == 60 assert len(temp_cache.get(FAILED_STRATEGIES)) == 1
def fetch_and_load_features(url: str, app_name: str, instance_id: str, custom_headers: dict, custom_options: dict, cache: FileCache, features: dict, strategy_mapping: dict) -> None: feature_provisioning = get_feature_toggles(url, app_name, instance_id, custom_headers, custom_options) if feature_provisioning: cache[FEATURES_URL] = feature_provisioning cache.sync() else: LOGGER.warning("Unable to get feature flag toggles, using cached provisioning.") load_features(cache, features, strategy_mapping)
def fetch_and_load_features(url: str, app_name: str, instance_id: str, custom_headers: dict, custom_options: dict, cache: redis.Redis, features: dict, strategy_mapping: dict) -> None: feature_provisioning = get_feature_toggles(url, app_name, instance_id, custom_headers, custom_options) if feature_provisioning: # Sample data we're writing into cache # { # "features": [{ # "name": "haptik.development.enable_smart_skills", # "description": "Feature to enable smart skills on dev servers", # "type": "release", # "project": "default", # "enabled": true, # "stale": false, # "strategies": [ # { # "name": "EnableForPartners", # "parameters": { # "partner_names": "Platform Demo,haptik,demo,aksc" # } # } # ], # "variants": [], # "createdAt": "2021-03-08T09:14:41.828Z" # }] # } features = feature_provisioning.get('features', []) if not features: LOGGER.warning("Features are empty") cache.set(FEATURES_URL, pickle.dumps(features)) else: LOGGER.warning( "Unable to get feature flag toggles, using cached provisioning.") load_features(cache, features, strategy_mapping)
def __init__(self, url: str, app_name: str, environment: str = "default", instance_id: str = "unleash-client-python", refresh_interval: int = 15, refresh_jitter: Optional[int] = None, metrics_interval: int = 60, metrics_jitter: Optional[int] = None, disable_metrics: bool = False, disable_registration: bool = False, custom_headers: Optional[dict] = None, custom_options: Optional[dict] = None, custom_strategies: Optional[dict] = None, cache_directory: Optional[str] = None, project_name: str = None, verbose_log_level: int = 30, cache: Optional[BaseCache] = None) -> None: custom_headers = custom_headers or {} custom_options = custom_options or {} custom_strategies = custom_strategies or {} # Configuration self.unleash_url = url.rstrip('/') self.unleash_app_name = app_name self.unleash_environment = environment self.unleash_instance_id = instance_id self.unleash_refresh_interval = refresh_interval self.unleash_refresh_jitter = int( refresh_jitter) if refresh_jitter is not None else None self.unleash_metrics_interval = metrics_interval self.unleash_metrics_jitter = int( metrics_jitter) if metrics_jitter is not None else None self.unleash_disable_metrics = disable_metrics self.unleash_disable_registration = disable_registration self.unleash_custom_headers = custom_headers self.unleash_custom_options = custom_options self.unleash_static_context = { "appName": self.unleash_app_name, "environment": self.unleash_environment } self.unleash_project_name = project_name self.unleash_verbose_log_level = verbose_log_level # Class objects self.features: dict = {} self.scheduler = BackgroundScheduler() self.fl_job: Job = None self.metric_job: Job = None self.cache = cache or FileCache(self.unleash_app_name, directory=cache_directory) self.cache.mset({ METRIC_LAST_SENT_TIME: datetime.now(timezone.utc), ETAG: '' }) self.unleash_bootstrapped = self.cache.bootstrapped # Mappings default_strategy_mapping = { "applicationHostname": ApplicationHostname, "default": Default, "gradualRolloutRandom": GradualRolloutRandom, "gradualRolloutSessionId": GradualRolloutSessionId, "gradualRolloutUserId": GradualRolloutUserId, "remoteAddress": RemoteAddress, "userWithId": UserWithId, "flexibleRollout": FlexibleRollout } if custom_strategies: strategy_v2xx_deprecation_check( [x for x in custom_strategies.values()]) # pylint: disable=R1721 self.strategy_mapping = { **custom_strategies, **default_strategy_mapping } # Client status self.is_initialized = False # Bootstrapping if self.unleash_bootstrapped: load_features(cache=self.cache, feature_toggles=self.features, strategy_mapping=self.strategy_mapping)