def test_can_convert_to_json_dict():
    state = FeatureFlagsState(True)
    flag1 = { 'key': 'key1', 'version': 100, 'offVariation': 0, 'variations': [ 'value1' ], 'trackEvents': False }
    flag2 = { 'key': 'key2', 'version': 200, 'offVariation': 1, 'variations': [ 'x', 'value2' ], 'trackEvents': True, 'debugEventsUntilDate': 1000 }
    state.add_flag(flag1, 'value1', 0, None, False)
    state.add_flag(flag2, 'value2', 1, None, False)

    result = state.to_json_dict()
    assert result == {
        'key1': 'value1',
        'key2': 'value2',
        '$flagsState': {
            'key1': {
                'variation': 0,
                'version': 100
            },
            'key2': {
                'variation': 1,
                'version': 200,
                'trackEvents': True,
                'debugEventsUntilDate': 1000
            }
        },
        '$valid': True
    }
def test_can_convert_to_values_map():
    state = FeatureFlagsState(True)
    flag1 = {'key': 'key1'}
    flag2 = {'key': 'key2'}
    state.add_flag(flag1, 'value1', 0, None, False)
    state.add_flag(flag2, 'value2', 1, None, False)
    assert state.to_values_map() == {'key1': 'value1', 'key2': 'value2'}
def test_can_convert_to_values_map():
    state = FeatureFlagsState(True)
    flag1 = { 'key': 'key1' }
    flag2 = { 'key': 'key2' }
    state.add_flag(flag1, 'value1', 0, None, False)
    state.add_flag(flag2, 'value2', 1, None, False)
    assert state.to_values_map() == { 'key1': 'value1', 'key2': 'value2' }
def test_can_serialize_with_jsonpickle():
    state = FeatureFlagsState(True)
    flag1 = { 'key': 'key1', 'version': 100, 'offVariation': 0, 'variations': [ 'value1' ], 'trackEvents': False }
    flag2 = { 'key': 'key2', 'version': 200, 'offVariation': 1, 'variations': [ 'x', 'value2' ], 'trackEvents': True, 'debugEventsUntilDate': 1000 }
    state.add_flag(flag1, 'value1', 0, None, False)
    state.add_flag(flag2, 'value2', 1, None, False)

    obj = state.to_json_dict()
    str = jsonpickle.encode(state, unpicklable=False)
    assert json.loads(str) == obj
def test_can_convert_to_json_string():
    state = FeatureFlagsState(True)
    flag1 = { 'key': 'key1', 'version': 100, 'offVariation': 0, 'variations': [ 'value1' ], 'trackEvents': False }
    flag2 = { 'key': 'key2', 'version': 200, 'offVariation': 1, 'variations': [ 'x', 'value2' ], 'trackEvents': True, 'debugEventsUntilDate': 1000 }
    state.add_flag(flag1, 'value1', 0, None, False)
    state.add_flag(flag2, 'value2', 1, None, False)

    obj = state.to_json_dict()
    str = state.to_json_string()
    assert json.loads(str) == obj
Exemple #6
0
    def all_flags_state(self, user, **kwargs):
        """Returns an object that encapsulates the state of all feature flags for a given user,
        including the flag values and also metadata that can be used on the front end. 
        
        This method does not send analytics events back to LaunchDarkly.

        :param dict user: the end user requesting the feature flags
        :param kwargs: optional parameters affecting how the state is computed: set
          `client_side_only=True` to limit it to only flags that are marked for use with the
          client-side SDK (by default, all flags are included); set `with_reasons=True` to
          include evaluation reasons in the state (see `variation_detail`)
        :return: a FeatureFlagsState object (will never be None; its 'valid' property will be False
          if the client is offline, has not been initialized, or the user is None or has no key)
        :rtype: FeatureFlagsState
        """
        if self._config.offline:
            log.warn("all_flags_state() called, but client is in offline mode. Returning empty state")
            return FeatureFlagsState(False)

        if not self.is_initialized():
            if self._store.initialized:
                log.warn("all_flags_state() called before client has finished initializing! Using last known values from feature store")
            else:
                log.warn("all_flags_state() called before client has finished initializing! Feature store unavailable - returning empty state")
                return FeatureFlagsState(False)

        if user is None or user.get('key') is None:
            log.warn("User or user key is None when calling all_flags_state(). Returning empty state.")
            return FeatureFlagsState(False)
        
        state = FeatureFlagsState(True)
        client_only = kwargs.get('client_side_only', False)
        with_reasons = kwargs.get('with_reasons', False)
        try:
            flags_map = self._store.all(FEATURES, lambda x: x)
        except Exception as e:
            log.error("Unable to read flags for all_flag_state: %s" % e)
            return FeatureFlagsState(False)
        
        for key, flag in flags_map.items():
            if client_only and not flag.get('clientSide', False):
                continue
            try:
                detail = evaluate(flag, user, self._store, False).detail
                state.add_flag(flag, detail.value, detail.variation_index,
                    detail.reason if with_reasons else None)
            except Exception as e:
                log.error("Error evaluating flag \"%s\" in all_flags_state: %s" % (key, e))
                log.debug(traceback.format_exc())
                reason = {'kind': 'ERROR', 'errorKind': 'EXCEPTION'}
                state.add_flag(flag, None, None, reason if with_reasons else None)
        
        return state
def test_can_convert_to_json_dict():
    state = FeatureFlagsState(True)
    flag1 = {
        'key': 'key1',
        'version': 100,
        'offVariation': 0,
        'variations': ['value1'],
        'trackEvents': False
    }
    flag2 = {
        'key': 'key2',
        'version': 200,
        'offVariation': 1,
        'variations': ['x', 'value2'],
        'trackEvents': True,
        'debugEventsUntilDate': 1000
    }
    state.add_flag(flag1, 'value1', 0, None)
    state.add_flag(flag2, 'value2', 1, None)

    result = state.to_json_dict()
    assert result == {
        'key1': 'value1',
        'key2': 'value2',
        '$flagsState': {
            'key1': {
                'variation': 0,
                'version': 100,
                'trackEvents': False
            },
            'key2': {
                'variation': 1,
                'version': 200,
                'trackEvents': True,
                'debugEventsUntilDate': 1000
            }
        },
        '$valid': True
    }
def test_can_serialize_with_jsonpickle():
    state = FeatureFlagsState(True)
    flag1 = {
        'key': 'key1',
        'version': 100,
        'offVariation': 0,
        'variations': ['value1'],
        'trackEvents': False
    }
    flag2 = {
        'key': 'key2',
        'version': 200,
        'offVariation': 1,
        'variations': ['x', 'value2'],
        'trackEvents': True,
        'debugEventsUntilDate': 1000
    }
    state.add_flag(flag1, 'value1', 0, None, False)
    state.add_flag(flag2, 'value2', 1, None, False)

    obj = state.to_json_dict()
    str = jsonpickle.encode(state, unpicklable=False)
    assert json.loads(str) == obj
def test_can_convert_to_json_string():
    state = FeatureFlagsState(True)
    flag1 = {
        'key': 'key1',
        'version': 100,
        'offVariation': 0,
        'variations': ['value1'],
        'trackEvents': False
    }
    flag2 = {
        'key': 'key2',
        'version': 200,
        'offVariation': 1,
        'variations': ['x', 'value2'],
        'trackEvents': True,
        'debugEventsUntilDate': 1000
    }
    state.add_flag(flag1, 'value1', 0, None, False)
    state.add_flag(flag2, 'value2', 1, None, False)

    obj = state.to_json_dict()
    str = state.to_json_string()
    assert json.loads(str) == obj
    def all_flags_state(self, user, **kwargs):
        """Returns an object that encapsulates the state of all feature flags for a given user,
        including the flag values and also metadata that can be used on the front end. See the
        JavaScript SDK Reference Guide on
        `Bootstrapping <https://docs.launchdarkly.com/docs/js-sdk-reference#section-bootstrapping>`_.
        
        This method does not send analytics events back to LaunchDarkly.

        :param dict user: the end user requesting the feature flags
        :param kwargs: optional parameters affecting how the state is computed - see below

        :Keyword Arguments:
          * **client_side_only** (*boolean*) --
            set to True to limit it to only flags that are marked for use with the client-side SDK
            (by default, all flags are included)
          * **with_reasons** (*boolean*) --
            set to True to include evaluation reasons in the state (see :func:`variation_detail()`)
          * **details_only_for_tracked_flags** (*boolean*) --
            set to True to omit any metadata that is normally only used for event generation, such
            as flag versions and evaluation reasons, unless the flag has event tracking or debugging
            turned on

        :return: a FeatureFlagsState object (will never be None; its ``valid`` property will be False
          if the client is offline, has not been initialized, or the user is None or has no key)
        :rtype: FeatureFlagsState
        """
        if self._config.offline:
            log.warn(
                "all_flags_state() called, but client is in offline mode. Returning empty state"
            )
            return FeatureFlagsState(False)

        if not self.is_initialized():
            if self._store.initialized:
                log.warn(
                    "all_flags_state() called before client has finished initializing! Using last known values from feature store"
                )
            else:
                log.warn(
                    "all_flags_state() called before client has finished initializing! Feature store unavailable - returning empty state"
                )
                return FeatureFlagsState(False)

        if user is None or user.get('key') is None:
            log.warn(
                "User or user key is None when calling all_flags_state(). Returning empty state."
            )
            return FeatureFlagsState(False)

        state = FeatureFlagsState(True)
        client_only = kwargs.get('client_side_only', False)
        with_reasons = kwargs.get('with_reasons', False)
        details_only_if_tracked = kwargs.get('details_only_for_tracked_flags',
                                             False)
        try:
            flags_map = self._store.all(FEATURES, lambda x: x)
            if flags_map is None:
                raise ValueError("feature store error")
        except Exception as e:
            log.error("Unable to read flags for all_flag_state: %s" % repr(e))
            return FeatureFlagsState(False)

        for key, flag in flags_map.items():
            if client_only and not flag.get('clientSide', False):
                continue
            try:
                detail = evaluate(flag, user, self._store, False).detail
                state.add_flag(flag, detail.value, detail.variation_index,
                               detail.reason if with_reasons else None,
                               details_only_if_tracked)
            except Exception as e:
                log.error(
                    "Error evaluating flag \"%s\" in all_flags_state: %s" %
                    (key, repr(e)))
                log.debug(traceback.format_exc())
                reason = {'kind': 'ERROR', 'errorKind': 'EXCEPTION'}
                state.add_flag(flag, None, None,
                               reason if with_reasons else None,
                               details_only_if_tracked)

        return state
def test_can_get_flag_value():
    state = FeatureFlagsState(True)
    flag = { 'key': 'key' }
    state.add_flag(flag, 'value', 1, None, False)
    assert state.get_flag_value('key') == 'value'
def test_can_get_flag_value():
    state = FeatureFlagsState(True)
    flag = {'key': 'key'}
    state.add_flag(flag, 'value', 1, None, False)
    assert state.get_flag_value('key') == 'value'