Skip to content

Commit ebd2cd7

Browse files
committed
fix: map-environment-name-and-tests
1 parent 698c628 commit ebd2cd7

File tree

3 files changed

+305
-1
lines changed

3 files changed

+305
-1
lines changed

src/engine_eval/mappers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub fn environment_to_context(environment: Environment) -> EngineEvaluationConte
2121
let mut ctx = EngineEvaluationContext {
2222
environment: EnvironmentContext {
2323
key: environment.api_key.clone(),
24-
name: environment.api_key.clone(),
24+
name: environment.name.clone(),
2525
},
2626
features: HashMap::new(),
2727
segments: HashMap::new(),

src/environments/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub mod builders;
1111
pub struct Environment {
1212
pub id: u32,
1313
pub api_key: String,
14+
pub name: String,
1415
pub project: projects::Project,
1516
pub feature_states: Vec<features::FeatureState>,
1617

tests/mappers_test.rs

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
use flagsmith_flag_engine::engine_eval::{
2+
context::{ConditionOperator, ConditionValue, SegmentRuleType, SegmentSource},
3+
environment_to_context,
4+
};
5+
use flagsmith_flag_engine::environments::Environment;
6+
7+
fn get_environment_fixture() -> &'static str {
8+
r#"{
9+
"api_key": "test_key",
10+
"name": "Test Environment",
11+
"project": {
12+
"name": "Test project",
13+
"organisation": {
14+
"feature_analytics": false,
15+
"name": "Test Org",
16+
"id": 1,
17+
"persist_trait_data": true,
18+
"stop_serving_flags": false
19+
},
20+
"id": 1,
21+
"hide_disabled_flags": false,
22+
"segments": [
23+
{
24+
"id": 1,
25+
"name": "Test segment",
26+
"rules": [
27+
{
28+
"type": "ALL",
29+
"rules": [
30+
{
31+
"type": "ALL",
32+
"rules": [],
33+
"conditions": [
34+
{
35+
"operator": "EQUAL",
36+
"property_": "foo",
37+
"value": "bar"
38+
}
39+
]
40+
}
41+
],
42+
"conditions": []
43+
}
44+
],
45+
"feature_states": []
46+
}
47+
]
48+
},
49+
"segment_overrides": [],
50+
"id": 1,
51+
"feature_states": [
52+
{
53+
"multivariate_feature_state_values": [],
54+
"feature_state_value": "some-value",
55+
"id": 1,
56+
"featurestate_uuid": "00000000-0000-0000-0000-000000000000",
57+
"feature": {
58+
"name": "some_feature",
59+
"type": "STANDARD",
60+
"id": 1
61+
},
62+
"segment_id": null,
63+
"enabled": true
64+
},
65+
{
66+
"feature_state_value": "default_value",
67+
"django_id": 2,
68+
"featurestate_uuid": "11111111-1111-1111-1111-111111111111",
69+
"feature": {
70+
"name": "mv_feature_with_ids",
71+
"type": "MULTIVARIATE",
72+
"id": 2
73+
},
74+
"segment_id": null,
75+
"enabled": true,
76+
"multivariate_feature_state_values": [
77+
{
78+
"id": 100,
79+
"multivariate_feature_option": {
80+
"id": 10,
81+
"value": "variant_a"
82+
},
83+
"mv_fs_value_uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
84+
"percentage_allocation": 30.0
85+
},
86+
{
87+
"id": 200,
88+
"multivariate_feature_option": {
89+
"id": 20,
90+
"value": "variant_b"
91+
},
92+
"mv_fs_value_uuid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
93+
"percentage_allocation": 70.0
94+
}
95+
]
96+
},
97+
{
98+
"feature_state_value": "fallback_value",
99+
"django_id": 3,
100+
"featurestate_uuid": "22222222-2222-2222-2222-222222222222",
101+
"feature": {
102+
"name": "mv_feature_without_ids",
103+
"type": "MULTIVARIATE",
104+
"id": 3
105+
},
106+
"segment_id": null,
107+
"enabled": false,
108+
"multivariate_feature_state_values": [
109+
{
110+
"multivariate_feature_option": {
111+
"id": 40,
112+
"value": "option_y"
113+
},
114+
"mv_fs_value_uuid": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
115+
"percentage_allocation": 50.0
116+
},
117+
{
118+
"multivariate_feature_option": {
119+
"id": 30,
120+
"value": "option_x"
121+
},
122+
"mv_fs_value_uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
123+
"percentage_allocation": 25.0
124+
},
125+
{
126+
"multivariate_feature_option": {
127+
"id": 50,
128+
"value": "option_z"
129+
},
130+
"mv_fs_value_uuid": "zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz",
131+
"percentage_allocation": 25.0
132+
}
133+
]
134+
}
135+
],
136+
"identity_overrides": [
137+
{
138+
"identifier": "overridden-id",
139+
"identity_uuid": "0f21cde8-63c5-4e50-baca-87897fa6cd01",
140+
"created_date": "2019-08-27T14:53:45.698555Z",
141+
"updated_at": "2023-07-14T16:12:00.000000",
142+
"environment_api_key": "test_key",
143+
"identity_features": [
144+
{
145+
"id": 1,
146+
"feature": {
147+
"id": 1,
148+
"name": "some_feature",
149+
"type": "STANDARD"
150+
},
151+
"featurestate_uuid": "1bddb9a5-7e59-42c6-9be9-625fa369749f",
152+
"feature_state_value": "some-overridden-value",
153+
"enabled": false,
154+
"django_id": null,
155+
"environment": 1,
156+
"identity": null,
157+
"feature_segment": null
158+
}
159+
]
160+
}
161+
]
162+
}"#
163+
}
164+
165+
#[test]
166+
fn test_environment_to_context_produces_evaluation_context() {
167+
let json = get_environment_fixture();
168+
let environment: Environment = serde_json::from_str(json).expect("Failed to parse environment");
169+
170+
let context = environment_to_context(environment);
171+
172+
// Verify environment context
173+
assert_eq!(context.environment.key, "test_key");
174+
assert_eq!(context.environment.name, "Test Environment");
175+
assert!(context.identity.is_none());
176+
assert_eq!(context.segments.len(), 2);
177+
178+
// Verify API segment
179+
assert!(context.segments.contains_key("1"));
180+
let api_segment = context.segments.get("1").unwrap();
181+
assert_eq!(api_segment.key, "1");
182+
assert_eq!(api_segment.name, "Test segment");
183+
assert_eq!(api_segment.rules.len(), 1);
184+
assert!(api_segment.overrides.is_empty());
185+
assert_eq!(api_segment.metadata.source, SegmentSource::Api);
186+
assert_eq!(api_segment.metadata.segment_id, Some(1));
187+
188+
// Verify segment rule structure
189+
assert_eq!(api_segment.rules[0].rule_type, SegmentRuleType::All);
190+
assert!(api_segment.rules[0].conditions.is_empty());
191+
assert_eq!(api_segment.rules[0].rules.len(), 1);
192+
193+
assert_eq!(api_segment.rules[0].rules[0].rule_type, SegmentRuleType::All);
194+
assert_eq!(api_segment.rules[0].rules[0].conditions.len(), 1);
195+
assert!(api_segment.rules[0].rules[0].rules.is_empty());
196+
197+
assert_eq!(api_segment.rules[0].rules[0].conditions[0].property, "foo");
198+
assert_eq!(
199+
api_segment.rules[0].rules[0].conditions[0].operator,
200+
ConditionOperator::Equal
201+
);
202+
assert_eq!(
203+
api_segment.rules[0].rules[0].conditions[0].value.as_string(),
204+
"bar"
205+
);
206+
207+
// Verify identity override segment exists
208+
let override_segments: Vec<_> = context
209+
.segments
210+
.iter()
211+
.filter(|(_, s)| s.metadata.source == SegmentSource::IdentityOverride)
212+
.collect();
213+
assert_eq!(override_segments.len(), 1);
214+
215+
let (_, override_segment) = override_segments[0];
216+
assert_eq!(override_segment.key, "");
217+
assert_eq!(override_segment.name, "identity_overrides");
218+
assert_eq!(override_segment.rules.len(), 1);
219+
assert_eq!(override_segment.overrides.len(), 1);
220+
221+
assert_eq!(override_segment.rules[0].rule_type, SegmentRuleType::All);
222+
assert_eq!(override_segment.rules[0].conditions.len(), 1);
223+
assert!(override_segment.rules[0].rules.is_empty());
224+
225+
assert_eq!(
226+
override_segment.rules[0].conditions[0].property,
227+
"$.identity.identifier"
228+
);
229+
assert_eq!(
230+
override_segment.rules[0].conditions[0].operator,
231+
ConditionOperator::In
232+
);
233+
match &override_segment.rules[0].conditions[0].value {
234+
ConditionValue::Multiple(identifiers) => {
235+
assert_eq!(identifiers, &vec!["overridden-id".to_string()]);
236+
}
237+
_ => panic!("Expected Multiple condition value"),
238+
}
239+
240+
assert_eq!(override_segment.overrides[0].key, "");
241+
assert_eq!(override_segment.overrides[0].name, "some_feature");
242+
assert!(!override_segment.overrides[0].enabled);
243+
assert_eq!(
244+
override_segment.overrides[0].value.value,
245+
"some-overridden-value"
246+
);
247+
assert_eq!(override_segment.overrides[0].priority, Some(f64::NEG_INFINITY));
248+
assert!(override_segment.overrides[0].variants.is_empty());
249+
assert_eq!(override_segment.overrides[0].metadata.feature_id, 1);
250+
251+
// Verify features
252+
assert_eq!(context.features.len(), 3);
253+
254+
// Verify some_feature
255+
assert!(context.features.contains_key("some_feature"));
256+
let some_feature = context.features.get("some_feature").unwrap();
257+
assert_eq!(some_feature.key, "00000000-0000-0000-0000-000000000000");
258+
assert_eq!(some_feature.name, "some_feature");
259+
assert!(some_feature.enabled);
260+
assert_eq!(some_feature.value.value, "some-value");
261+
assert!(some_feature.priority.is_none());
262+
assert!(some_feature.variants.is_empty());
263+
assert_eq!(some_feature.metadata.feature_id, 1);
264+
265+
// Verify multivariate feature with IDs
266+
assert!(context.features.contains_key("mv_feature_with_ids"));
267+
let mv_feature_with_ids = context.features.get("mv_feature_with_ids").unwrap();
268+
assert_eq!(mv_feature_with_ids.key, "2");
269+
assert_eq!(mv_feature_with_ids.name, "mv_feature_with_ids");
270+
assert!(mv_feature_with_ids.enabled);
271+
assert_eq!(mv_feature_with_ids.value.value, "default_value");
272+
assert!(mv_feature_with_ids.priority.is_none());
273+
assert_eq!(mv_feature_with_ids.variants.len(), 2);
274+
assert_eq!(mv_feature_with_ids.metadata.feature_id, 2);
275+
276+
// Verify variants
277+
assert_eq!(mv_feature_with_ids.variants[0].value.value, "variant_a");
278+
assert_eq!(mv_feature_with_ids.variants[0].weight, 30.0);
279+
280+
assert_eq!(mv_feature_with_ids.variants[1].value.value, "variant_b");
281+
assert_eq!(mv_feature_with_ids.variants[1].weight, 70.0);
282+
283+
// Verify multivariate feature without IDs
284+
assert!(context.features.contains_key("mv_feature_without_ids"));
285+
let mv_feature_without_ids = context.features.get("mv_feature_without_ids").unwrap();
286+
assert_eq!(mv_feature_without_ids.key, "3");
287+
assert_eq!(mv_feature_without_ids.name, "mv_feature_without_ids");
288+
assert!(!mv_feature_without_ids.enabled);
289+
assert_eq!(mv_feature_without_ids.value.value, "fallback_value");
290+
assert!(mv_feature_without_ids.priority.is_none());
291+
assert_eq!(mv_feature_without_ids.variants.len(), 3);
292+
assert_eq!(mv_feature_without_ids.metadata.feature_id, 3);
293+
294+
// Verify variants preserve order from input
295+
assert_eq!(mv_feature_without_ids.variants[0].value.value, "option_y");
296+
assert_eq!(mv_feature_without_ids.variants[0].weight, 50.0);
297+
298+
assert_eq!(mv_feature_without_ids.variants[1].value.value, "option_x");
299+
assert_eq!(mv_feature_without_ids.variants[1].weight, 25.0);
300+
301+
assert_eq!(mv_feature_without_ids.variants[2].value.value, "option_z");
302+
assert_eq!(mv_feature_without_ids.variants[2].weight, 25.0);
303+
}

0 commit comments

Comments
 (0)