Skip to content

Commit 16393c4

Browse files
pijushcsjonathanedeylahirumarambaPijush Chakrabortyrathovarun1032
committed
Fixing SSRC Typos and Minor Bugs (#841)
* Changes for percent comparison * Fixing semantic version issues with invalid version * Fixing Config values must retrun default values from invalid get operations * Updating tolerance for percentage evaluation * Removing dependency changes from fix branch * Updating ServerConfig methods as per review changes * Updating comments and vars for readability * Added unit and integration tests * Refactor and add unit test * Implementation for Fetching and Caching Server Side Remote Config (#825) * Minor update to API signature * Updating init params for ServerTemplateData * Adding validation errors and test * Removing parameter groups * Addressing PR comments and fixing async flow during fetch call * Fixing lint issues --------- Co-authored-by: Jonathan Edey <[email protected]> Co-authored-by: Lahiru Maramba <[email protected]> Co-authored-by: Pijush Chakraborty <[email protected]> Co-authored-by: varun rathore <[email protected]> Co-authored-by: Varun Rathore <[email protected]>
1 parent bcc261f commit 16393c4

File tree

2 files changed

+131
-56
lines changed

2 files changed

+131
-56
lines changed

firebase_admin/remote_config.py

+46-40
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2017 Google Inc.
1+
# Copyright 2024 Google Inc.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -185,21 +185,19 @@ def __init__(self, config_values):
185185
self._config_values = config_values # dictionary of param key to values
186186

187187
def get_boolean(self, key):
188-
return self.get_value(key).as_boolean()
188+
return self._get_value(key).as_boolean()
189189

190190
def get_string(self, key):
191-
return self.get_value(key).as_string()
191+
return self._get_value(key).as_string()
192192

193193
def get_int(self, key):
194-
return self.get_value(key).as_int()
194+
return self._get_value(key).as_int()
195195

196196
def get_float(self, key):
197-
return self.get_value(key).as_float()
197+
return self._get_value(key).as_float()
198198

199-
def get_value(self, key):
200-
if self._config_values[key]:
201-
return self._config_values[key]
202-
return _Value('static')
199+
def _get_value(self, key):
200+
return self._config_values.get(key, _Value('static'))
203201

204202

205203
class _RemoteConfigService:
@@ -421,11 +419,11 @@ def evaluate_percent_condition(self, percent_condition,
421419

422420
hash64 = self.hash_seeded_randomization_id(string_to_hash)
423421
instance_micro_percentile = hash64 % (100 * 1000000)
424-
if percent_operator == PercentConditionOperator.LESS_OR_EQUAL:
422+
if percent_operator == PercentConditionOperator.LESS_OR_EQUAL.value:
425423
return instance_micro_percentile <= norm_micro_percent
426-
if percent_operator == PercentConditionOperator.GREATER_THAN:
424+
if percent_operator == PercentConditionOperator.GREATER_THAN.value:
427425
return instance_micro_percentile > norm_micro_percent
428-
if percent_operator == PercentConditionOperator.BETWEEN:
426+
if percent_operator == PercentConditionOperator.BETWEEN.value:
429427
return norm_percent_lower_bound < instance_micro_percentile <= norm_percent_upper_bound
430428
logger.warning("Unknown percent operator: %s", percent_operator)
431429
return False
@@ -454,10 +452,10 @@ def evaluate_custom_signal_condition(self, custom_signal_condition,
454452
Returns:
455453
True if the condition is met, False otherwise.
456454
"""
457-
custom_signal_operator = custom_signal_condition.get('custom_signal_operator') or {}
458-
custom_signal_key = custom_signal_condition.get('custom_signal_key') or {}
455+
custom_signal_operator = custom_signal_condition.get('customSignalOperator') or {}
456+
custom_signal_key = custom_signal_condition.get('customSignalKey') or {}
459457
target_custom_signal_values = (
460-
custom_signal_condition.get('target_custom_signal_values') or {})
458+
custom_signal_condition.get('targetCustomSignalValues') or {})
461459

462460
if not all([custom_signal_operator, custom_signal_key, target_custom_signal_values]):
463461
logger.warning("Missing operator, key, or target values for custom signal condition.")
@@ -471,71 +469,71 @@ def evaluate_custom_signal_condition(self, custom_signal_condition,
471469
logger.warning("Custom signal value not found in context: %s", custom_signal_key)
472470
return False
473471

474-
if custom_signal_operator == CustomSignalOperator.STRING_CONTAINS:
472+
if custom_signal_operator == CustomSignalOperator.STRING_CONTAINS.value:
475473
return self._compare_strings(target_custom_signal_values,
476474
actual_custom_signal_value,
477475
lambda target, actual: target in actual)
478-
if custom_signal_operator == CustomSignalOperator.STRING_DOES_NOT_CONTAIN:
476+
if custom_signal_operator == CustomSignalOperator.STRING_DOES_NOT_CONTAIN.value:
479477
return not self._compare_strings(target_custom_signal_values,
480478
actual_custom_signal_value,
481479
lambda target, actual: target in actual)
482-
if custom_signal_operator == CustomSignalOperator.STRING_EXACTLY_MATCHES:
480+
if custom_signal_operator == CustomSignalOperator.STRING_EXACTLY_MATCHES.value:
483481
return self._compare_strings(target_custom_signal_values,
484482
actual_custom_signal_value,
485483
lambda target, actual: target.strip() == actual.strip())
486-
if custom_signal_operator == CustomSignalOperator.STRING_CONTAINS_REGEX:
484+
if custom_signal_operator == CustomSignalOperator.STRING_CONTAINS_REGEX.value:
487485
return self._compare_strings(target_custom_signal_values,
488486
actual_custom_signal_value,
489487
re.search)
490488

491489
# For numeric operators only one target value is allowed.
492-
if custom_signal_operator == CustomSignalOperator.NUMERIC_LESS_THAN:
490+
if custom_signal_operator == CustomSignalOperator.NUMERIC_LESS_THAN.value:
493491
return self._compare_numbers(target_custom_signal_values[0],
494492
actual_custom_signal_value,
495493
lambda r: r < 0)
496-
if custom_signal_operator == CustomSignalOperator.NUMERIC_LESS_EQUAL:
494+
if custom_signal_operator == CustomSignalOperator.NUMERIC_LESS_EQUAL.value:
497495
return self._compare_numbers(target_custom_signal_values[0],
498496
actual_custom_signal_value,
499497
lambda r: r <= 0)
500-
if custom_signal_operator == CustomSignalOperator.NUMERIC_EQUAL:
498+
if custom_signal_operator == CustomSignalOperator.NUMERIC_EQUAL.value:
501499
return self._compare_numbers(target_custom_signal_values[0],
502500
actual_custom_signal_value,
503501
lambda r: r == 0)
504-
if custom_signal_operator == CustomSignalOperator.NUMERIC_NOT_EQUAL:
502+
if custom_signal_operator == CustomSignalOperator.NUMERIC_NOT_EQUAL.value:
505503
return self._compare_numbers(target_custom_signal_values[0],
506504
actual_custom_signal_value,
507505
lambda r: r != 0)
508-
if custom_signal_operator == CustomSignalOperator.NUMERIC_GREATER_THAN:
506+
if custom_signal_operator == CustomSignalOperator.NUMERIC_GREATER_THAN.value:
509507
return self._compare_numbers(target_custom_signal_values[0],
510508
actual_custom_signal_value,
511509
lambda r: r > 0)
512-
if custom_signal_operator == CustomSignalOperator.NUMERIC_GREATER_EQUAL:
510+
if custom_signal_operator == CustomSignalOperator.NUMERIC_GREATER_EQUAL.value:
513511
return self._compare_numbers(target_custom_signal_values[0],
514512
actual_custom_signal_value,
515513
lambda r: r >= 0)
516514

517515
# For semantic operators only one target value is allowed.
518-
if custom_signal_operator == CustomSignalOperator.SEMANTIC_VERSION_LESS_THAN:
516+
if custom_signal_operator == CustomSignalOperator.SEMANTIC_VERSION_LESS_THAN.value:
519517
return self._compare_semantic_versions(target_custom_signal_values[0],
520518
actual_custom_signal_value,
521519
lambda r: r < 0)
522-
if custom_signal_operator == CustomSignalOperator.SEMANTIC_VERSION_LESS_EQUAL:
520+
if custom_signal_operator == CustomSignalOperator.SEMANTIC_VERSION_LESS_EQUAL.value:
523521
return self._compare_semantic_versions(target_custom_signal_values[0],
524522
actual_custom_signal_value,
525523
lambda r: r <= 0)
526-
if custom_signal_operator == CustomSignalOperator.SEMANTIC_VERSION_EQUAL:
524+
if custom_signal_operator == CustomSignalOperator.SEMANTIC_VERSION_EQUAL.value:
527525
return self._compare_semantic_versions(target_custom_signal_values[0],
528526
actual_custom_signal_value,
529527
lambda r: r == 0)
530-
if custom_signal_operator == CustomSignalOperator.SEMANTIC_VERSION_NOT_EQUAL:
528+
if custom_signal_operator == CustomSignalOperator.SEMANTIC_VERSION_NOT_EQUAL.value:
531529
return self._compare_semantic_versions(target_custom_signal_values[0],
532530
actual_custom_signal_value,
533531
lambda r: r != 0)
534-
if custom_signal_operator == CustomSignalOperator.SEMANTIC_VERSION_GREATER_THAN:
532+
if custom_signal_operator == CustomSignalOperator.SEMANTIC_VERSION_GREATER_THAN.value:
535533
return self._compare_semantic_versions(target_custom_signal_values[0],
536534
actual_custom_signal_value,
537535
lambda r: r > 0)
538-
if custom_signal_operator == CustomSignalOperator.SEMANTIC_VERSION_GREATER_EQUAL:
536+
if custom_signal_operator == CustomSignalOperator.SEMANTIC_VERSION_GREATER_EQUAL.value:
539537
return self._compare_semantic_versions(target_custom_signal_values[0],
540538
actual_custom_signal_value,
541539
lambda r: r >= 0)
@@ -589,25 +587,27 @@ def _compare_semantic_versions(self, target_value, actual_value, predicate_fn) -
589587
return self._compare_versions(str(actual_value),
590588
str(target_value), predicate_fn)
591589

592-
def _compare_versions(self, version1, version2, predicate_fn) -> bool:
590+
def _compare_versions(self, sem_version_1, sem_version_2, predicate_fn) -> bool:
593591
"""Compares two semantic version strings.
594592
595593
Args:
596-
version1: The first semantic version string.
597-
version2: The second semantic version string.
598-
predicate_fn: A function that takes an integer and returns a boolean.
594+
sem_version_1: The first semantic version string.
595+
sem_version_2: The second semantic version string.
596+
predicate_fn: A function that takes an integer and returns a boolean.
599597
600598
Returns:
601599
bool: The result of the predicate function.
602600
"""
603601
try:
604-
v1_parts = [int(part) for part in version1.split('.')]
605-
v2_parts = [int(part) for part in version2.split('.')]
602+
v1_parts = [int(part) for part in sem_version_1.split('.')]
603+
v2_parts = [int(part) for part in sem_version_2.split('.')]
606604
max_length = max(len(v1_parts), len(v2_parts))
607605
v1_parts.extend([0] * (max_length - len(v1_parts)))
608606
v2_parts.extend([0] * (max_length - len(v2_parts)))
609607

610608
for part1, part2 in zip(v1_parts, v2_parts):
609+
if any((part1 < 0, part2 < 0)):
610+
raise ValueError
611611
if part1 < part2:
612612
return predicate_fn(-1)
613613
if part1 > part2:
@@ -674,7 +674,7 @@ def as_string(self) -> str:
674674
"""Returns the value as a string."""
675675
if self.source == 'static':
676676
return self.DEFAULT_VALUE_FOR_STRING
677-
return self.value
677+
return str(self.value)
678678

679679
def as_boolean(self) -> bool:
680680
"""Returns the value as a boolean."""
@@ -686,13 +686,19 @@ def as_int(self) -> float:
686686
"""Returns the value as a number."""
687687
if self.source == 'static':
688688
return self.DEFAULT_VALUE_FOR_INTEGER
689-
return self.value
689+
try:
690+
return int(self.value)
691+
except ValueError:
692+
return self.DEFAULT_VALUE_FOR_INTEGER
690693

691694
def as_float(self) -> float:
692695
"""Returns the value as a number."""
693696
if self.source == 'static':
694697
return self.DEFAULT_VALUE_FOR_FLOAT_NUMBER
695-
return float(self.value)
698+
try:
699+
return float(self.value)
700+
except ValueError:
701+
return self.DEFAULT_VALUE_FOR_FLOAT_NUMBER
696702

697703
def get_source(self) -> ValueSource:
698704
"""Returns the source of the value."""

0 commit comments

Comments
 (0)