|
18 | 18 | import pytest
|
19 | 19 | import firebase_admin
|
20 | 20 | from firebase_admin.remote_config import (
|
| 21 | + CustomSignalOperator, |
21 | 22 | PercentConditionOperator,
|
22 | 23 | _REMOTE_CONFIG_ATTRIBUTE,
|
23 | 24 | _RemoteConfigService,
|
|
66 | 67 | 'version': VERSION_INFO,
|
67 | 68 | }
|
68 | 69 |
|
| 70 | +SEMENTIC_VERSION_LESS_THAN_TRUE = [CustomSignalOperator.SEMANTIC_VERSION_LESS_THAN.value, ['12.1.3.444'], '12.1.3.443', True] |
| 71 | +SEMENTIC_VERSION_EQUAL_TRUE = [CustomSignalOperator.SEMANTIC_VERSION_EQUAL.value, ['12.1.3.444'], '12.1.3.444', True] |
| 72 | +SEMANTIC_VERSION_GREATER_THAN_FALSE = [CustomSignalOperator.SEMANTIC_VERSION_LESS_THAN.value, ['12.1.3.4'], '12.1.3.4', False] |
| 73 | +SEMANTIC_VERSION_INVALID_FORMAT_STRING = [CustomSignalOperator.SEMANTIC_VERSION_LESS_THAN.value, ['12.1.3.444'], '12.1.3.abc', False] |
| 74 | +SEMANTIC_VERSION_INVALID_FORMAT_NEGATIVE_INTEGER = [CustomSignalOperator.SEMANTIC_VERSION_LESS_THAN.value, ['12.1.3.444'], '12.1.3.-2', False] |
| 75 | + |
69 | 76 | class TestEvaluate:
|
70 | 77 | @classmethod
|
71 | 78 | def setup_class(cls):
|
@@ -360,7 +367,7 @@ def test_evaluate_unknown_operator_to_false(self):
|
360 | 367 | 'andCondition': {
|
361 | 368 | 'conditions': [{
|
362 | 369 | 'percent': {
|
363 |
| - 'percentOperator': PercentConditionOperator.UNKNOWN |
| 370 | + 'percentOperator': PercentConditionOperator.UNKNOWN.value |
364 | 371 | }
|
365 | 372 | }],
|
366 | 373 | }
|
@@ -402,7 +409,7 @@ def test_evaluate_less_or_equal_to_max_to_true(self):
|
402 | 409 | 'andCondition': {
|
403 | 410 | 'conditions': [{
|
404 | 411 | 'percent': {
|
405 |
| - 'percentOperator': PercentConditionOperator.LESS_OR_EQUAL, |
| 412 | + 'percentOperator': PercentConditionOperator.LESS_OR_EQUAL.value, |
406 | 413 | 'seed': 'abcdef',
|
407 | 414 | 'microPercent': 100_000_000
|
408 | 415 | }
|
@@ -446,7 +453,7 @@ def test_evaluate_undefined_micropercent_to_false(self):
|
446 | 453 | 'andCondition': {
|
447 | 454 | 'conditions': [{
|
448 | 455 | 'percent': {
|
449 |
| - 'percentOperator': PercentConditionOperator.LESS_OR_EQUAL, |
| 456 | + 'percentOperator': PercentConditionOperator.LESS_OR_EQUAL.value, |
450 | 457 | # Leaves microPercent undefined
|
451 | 458 | }
|
452 | 459 | }],
|
@@ -489,7 +496,7 @@ def test_evaluate_undefined_micropercentrange_to_false(self):
|
489 | 496 | 'andCondition': {
|
490 | 497 | 'conditions': [{
|
491 | 498 | 'percent': {
|
492 |
| - 'percentOperator': PercentConditionOperator.BETWEEN, |
| 499 | + 'percentOperator': PercentConditionOperator.BETWEEN.value, |
493 | 500 | # Leaves microPercent undefined
|
494 | 501 | }
|
495 | 502 | }],
|
@@ -532,7 +539,7 @@ def test_evaluate_between_min_max_to_true(self):
|
532 | 539 | 'andCondition': {
|
533 | 540 | 'conditions': [{
|
534 | 541 | 'percent': {
|
535 |
| - 'percentOperator': PercentConditionOperator.BETWEEN, |
| 542 | + 'percentOperator': PercentConditionOperator.BETWEEN.value, |
536 | 543 | 'seed': 'abcdef',
|
537 | 544 | 'microPercentRange': {
|
538 | 545 | 'microPercentLowerBound': 0,
|
@@ -579,7 +586,7 @@ def test_evaluate_between_equal_bounds_to_false(self):
|
579 | 586 | 'andCondition': {
|
580 | 587 | 'conditions': [{
|
581 | 588 | 'percent': {
|
582 |
| - 'percentOperator': PercentConditionOperator.BETWEEN, |
| 589 | + 'percentOperator': PercentConditionOperator.BETWEEN.value, |
583 | 590 | 'seed': 'abcdef',
|
584 | 591 | 'microPercentRange': {
|
585 | 592 | 'microPercentLowerBound': 50000000,
|
@@ -626,7 +633,7 @@ def test_evaluate_less_or_equal_to_approx(self):
|
626 | 633 | 'andCondition': {
|
627 | 634 | 'conditions': [{
|
628 | 635 | 'percent': {
|
629 |
| - 'percentOperator': PercentConditionOperator.LESS_OR_EQUAL, |
| 636 | + 'percentOperator': PercentConditionOperator.LESS_OR_EQUAL.value, |
630 | 637 | 'seed': 'abcdef',
|
631 | 638 | 'microPercent': 10_000_000 # 10%
|
632 | 639 | }
|
@@ -656,7 +663,7 @@ def test_evaluate_between_approx(self):
|
656 | 663 | 'andCondition': {
|
657 | 664 | 'conditions': [{
|
658 | 665 | 'percent': {
|
659 |
| - 'percentOperator': PercentConditionOperator.BETWEEN, |
| 666 | + 'percentOperator': PercentConditionOperator.BETWEEN.value, |
660 | 667 | 'seed': 'abcdef',
|
661 | 668 | 'microPercentRange': {
|
662 | 669 | 'microPercentLowerBound': 40_000_000,
|
@@ -689,7 +696,7 @@ def test_evaluate_between_interquartile_range_accuracy(self):
|
689 | 696 | 'andCondition': {
|
690 | 697 | 'conditions': [{
|
691 | 698 | 'percent': {
|
692 |
| - 'percentOperator': PercentConditionOperator.BETWEEN, |
| 699 | + 'percentOperator': PercentConditionOperator.BETWEEN.value, |
693 | 700 | 'seed': 'abcdef',
|
694 | 701 | 'microPercentRange': {
|
695 | 702 | 'microPercentLowerBound': 25_000_000,
|
@@ -750,6 +757,59 @@ def evaluate_random_assignments(self, condition, num_of_assignments, mock_app, d
|
750 | 757 |
|
751 | 758 | return eval_true_count
|
752 | 759 |
|
| 760 | + @pytest.mark.parametrize('custom_signal_opearator, target_custom_signal_value, actual_custom_signal_value, parameter_value', |
| 761 | + [ |
| 762 | + SEMENTIC_VERSION_LESS_THAN_TRUE, |
| 763 | + SEMANTIC_VERSION_GREATER_THAN_FALSE, |
| 764 | + SEMENTIC_VERSION_EQUAL_TRUE, |
| 765 | + SEMANTIC_VERSION_INVALID_FORMAT_NEGATIVE_INTEGER, |
| 766 | + SEMANTIC_VERSION_INVALID_FORMAT_STRING |
| 767 | + ]) |
| 768 | + def test_evaluate_custom_signal_semantic_version(self, custom_signal_opearator, |
| 769 | + target_custom_signal_value, actual_custom_signal_value, parameter_value): |
| 770 | + app = firebase_admin.get_app() |
| 771 | + condition = { |
| 772 | + 'name': 'is_true', |
| 773 | + 'condition': { |
| 774 | + 'orCondition': { |
| 775 | + 'conditions': [{ |
| 776 | + 'andCondition': { |
| 777 | + 'conditions': [{ |
| 778 | + 'customSignal': { |
| 779 | + 'customSignalOperator': custom_signal_opearator, |
| 780 | + 'customSignalKey': 'sementic_version_key', |
| 781 | + 'targetCustomSignalValues': target_custom_signal_value |
| 782 | + } |
| 783 | + }], |
| 784 | + } |
| 785 | + }] |
| 786 | + } |
| 787 | + } |
| 788 | + } |
| 789 | + default_config = { |
| 790 | + 'dog_is_cute': True |
| 791 | + } |
| 792 | + template_data = { |
| 793 | + 'conditions': [condition], |
| 794 | + 'parameters': { |
| 795 | + 'is_enabled': { |
| 796 | + 'defaultValue': {'value': 'false'}, |
| 797 | + 'conditionalValues': {'is_true': {'value': 'true'}} |
| 798 | + }, |
| 799 | + }, |
| 800 | + 'parameterGroups':'', |
| 801 | + 'version':'', |
| 802 | + 'etag': '123' |
| 803 | + } |
| 804 | + context = {'randomization_id': '123', 'sementic_version_key': actual_custom_signal_value} |
| 805 | + server_template = remote_config.init_server_template( |
| 806 | + app=app, |
| 807 | + default_config=default_config, |
| 808 | + template_data=ServerTemplateData('etag', template_data) |
| 809 | + ) |
| 810 | + server_config = server_template.evaluate(context) |
| 811 | + assert server_config.get_boolean('is_enabled') == parameter_value |
| 812 | + |
753 | 813 |
|
754 | 814 | class MockAdapter(testutils.MockAdapter):
|
755 | 815 | """A Mock HTTP Adapter that Firebase Remote Config with ETag in header."""
|
|
0 commit comments