Esempio n. 1
0
    def generate_traits(self, trait_data_items, persist=False):
        """
        Given a list of trait data items, validated by TraitSerializerFull, generate
        a list of TraitModel objects for the given identity.

        :param trait_data_items: list of dictionaries validated by TraitSerializerFull
        :param persist: determines whether the traits should be persisted to db
        :return: list of TraitModels
        """
        trait_models = []
        for trait_data_item in trait_data_items:
            trait_key = trait_data_item["trait_key"]
            trait_value = trait_data_item["trait_value"]
            trait_models.append(
                Trait(
                    trait_key=trait_key,
                    identity=self,
                    **Trait.generate_trait_value_data(trait_value),
                )
            )

        if persist:
            Trait.objects.bulk_create(trait_models)

        return trait_models
Esempio n. 2
0
def create_trait_for_identity(
    identity: Identity, trait_key: str, trait_value: typing.Any
):
    trait_value_data = Trait.generate_trait_value_data(trait_value)
    return Trait.objects.create(
        identity=identity, trait_key=trait_key, **trait_value_data
    )
Esempio n. 3
0
 def _make_temporary_trait(self, identity, trait_data):
     print(trait_data)
     return Trait(identity=identity,
                  trait_key=trait_data.get('trait_key'),
                  value_type=trait_data.get('value_type'),
                  boolean_value=trait_data.get('boolean_value'),
                  integer_value=trait_data.get('integer_value'),
                  string_value=trait_data.get('string_value'),
                  float_value=trait_data.get('float_value'))
Esempio n. 4
0
    def test_get_all_feature_states_returns_correct_value_when_traits_passed_manually(
        self, ):
        """
        Verify that when traits are passed manually, then the segments are correctly
        analysed for the identity and the correct value is returned for the feature
        state.
        """
        # Given - an identity with a trait that has an integer value of 10
        trait_key = "trait-key"
        trait_value = 10
        identity = Identity.objects.create(identifier="test-identity",
                                           environment=self.environment)
        trait = Trait(
            identity=identity,
            trait_key=trait_key,
            integer_value=trait_value,
            value_type=INTEGER,
        )

        # and a segment that matches all identities with a trait value greater than or equal to 5
        segment = Segment.objects.create(name="Test segment 1",
                                         project=self.project)
        rule = SegmentRule.objects.create(segment=segment,
                                          type=SegmentRule.ALL_RULE)
        Condition.objects.create(rule=rule,
                                 property=trait_key,
                                 value=5,
                                 operator=GREATER_THAN_INCLUSIVE)

        # and a feature flag
        default_state = False
        feature_flag = Feature.objects.create(project=self.project,
                                              name="test_flag",
                                              default_enabled=default_state)

        # which is overridden by the segment
        enabled_for_segment = not default_state
        feature_segment = FeatureSegment.objects.create(
            feature=feature_flag,
            segment=segment,
            environment=self.environment,
            priority=1,
        )
        FeatureState.objects.create(
            feature=feature_flag,
            feature_segment=feature_segment,
            environment=self.environment,
            enabled=enabled_for_segment,
        )

        # When - we get all feature states for an identity
        feature_states = identity.get_all_feature_states(traits=[trait])

        # Then - the flag is returned with the correct state
        assert len(feature_states) == 1
        assert feature_states[0].enabled == enabled_for_segment
Esempio n. 5
0
    def update_traits(self, trait_data_items):
        """
        Given a list of traits, update any that already exist and create any new ones.
        Return the full list of traits for the given identity after these changes.

        :param trait_data_items: list of dictionaries validated by TraitSerializerFull
        :return: queryset of updated trait models
        """
        current_traits = self.get_all_user_traits()

        new_traits = []
        keys_to_delete = []

        for trait_data_item in trait_data_items:
            trait_key = trait_data_item["trait_key"]
            trait_value = trait_data_item["trait_value"]

            if trait_value is None:
                # build a list of trait keys to delete having been nulled by the
                # input data
                keys_to_delete.append(trait_key)
                continue

            trait_value_data = Trait.generate_trait_value_data(trait_value)

            if current_traits.filter(trait_key=trait_key).exists():
                current_trait = current_traits.get(trait_key=trait_key)
                for attr, value in trait_value_data.items():
                    setattr(current_trait, attr, value)
                current_trait.save()
            else:
                # create a new trait and append it to the list of new traits
                new_traits.append(
                    Trait.objects.create(
                        trait_key=trait_key, identity=self, **trait_value_data
                    )
                )

        # delete the traits that had their keys set to None
        if keys_to_delete:
            current_traits.filter(trait_key__in=keys_to_delete).delete()

        # return the full list of traits for this identity by refreshing from the db
        # TODO: handle this in the above logic to avoid a second hit to the DB
        return self.get_all_user_traits()
Esempio n. 6
0
    def create(self, validated_data):
        identity = self._get_identity(validated_data["identity"]["identifier"])

        trait_key = validated_data["trait_key"]
        trait_value = validated_data["trait_value"]["value"]
        trait_value_type = validated_data["trait_value"]["type"]

        value_key = Trait.get_trait_value_key_name(trait_value_type)

        defaults = {
            value_key: trait_value,
            "value_type": trait_value_type
            if trait_value_type in [FLOAT, INTEGER, BOOLEAN]
            else STRING,
        }

        return Trait.objects.update_or_create(
            identity=identity, trait_key=trait_key, defaults=defaults
        )[0]
Esempio n. 7
0
    def create(self, validated_data):
        identity = self._get_identity(validated_data['identity']['identifier'])

        trait_key = validated_data['trait_key']
        trait_value = validated_data['trait_value']['value']
        trait_value_type = validated_data['trait_value']['type']

        value_key = Trait.get_trait_value_key_name(trait_value_type)

        defaults = {
            value_key:
            trait_value,
            'value_type':
            trait_value_type
            if trait_value_type in [FLOAT, INTEGER, BOOLEAN] else STRING
        }

        return Trait.objects.update_or_create(identity=identity,
                                              trait_key=trait_key,
                                              defaults=defaults)[0]
def test_generate_trait_value_data_for_deserialized_data(
        deserialized_data, expected_data):
    assert Trait.generate_trait_value_data(deserialized_data) == expected_data
def test_generate_trait_value_data_for_value(value, expected_data):
    assert Trait.generate_trait_value_data(value) == expected_data