diff --git a/.github/workflows/sdk-spec.yml b/.github/workflows/sdk-spec.yml index 1f19dbb..98cd4cf 100644 --- a/.github/workflows/sdk-spec.yml +++ b/.github/workflows/sdk-spec.yml @@ -11,7 +11,8 @@ permissions: jobs: sdk-spec: # Keep the ref in `uses:` and `spec-ref` in sync. - uses: Flagsmith/sdk-spec/.github/workflows/run-spec.yml@v0.3.0 + uses: Flagsmith/sdk-spec/.github/workflows/run-spec.yml@v0.7.0 with: - spec-ref: v0.3.0 + spec-ref: v0.7.0 language: rust + tags: core or local-evaluation diff --git a/Cargo.lock b/Cargo.lock index 0226541..12374da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -656,10 +656,11 @@ dependencies = [ [[package]] name = "flagsmith-flag-engine" version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882468fdaa8c6fba69c5d473f8d2c7fe25686a775a77e5d029d1768d8aa895ae" +source = "git+https://github.com/Flagsmith/flagsmith-rust-flag-engine?rev=92e19652b656f489769bdd62187a440f594a3c73#92e19652b656f489769bdd62187a440f594a3c73" dependencies = [ "chrono", + "indexmap", + "jsonpath-rust", "md-5", "num-bigint", "num-traits", @@ -667,7 +668,6 @@ dependencies = [ "semver", "serde", "serde_json", - "serde_json_path", "sha2", "uuid", ] @@ -1174,15 +1174,8 @@ checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", "hashbrown", -] - -[[package]] -name = "inventory" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4f0c30c76f2f4ccee3fe55a2435f691ca00c0e4bd87abe4f4a851b1d4dac39b" -dependencies = [ - "rustversion", + "serde", + "serde_core", ] [[package]] @@ -1302,6 +1295,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonpath-rust" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c4668c489390e66d586fe2238ee8568473f7ac1607b411342f787c5e1bedd7" +dependencies = [ + "pest", + "pest_derive", + "regex", + "serde_json", + "thiserror 2.0.20", +] + [[package]] name = "kv-log-macro" version = "1.0.7" @@ -1449,12 +1455,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "mio" version = "1.2.2" @@ -1481,16 +1481,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "num-bigint" version = "0.4.8" @@ -1584,6 +1574,59 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pest" +version = "2.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8db75153506001cb36ed924f08cadc862eb3f8c4d0d534139f29074769d7660" +dependencies = [ + "memchr", + "pest_stack_guard", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20aa17e11fb35664b67d5214a0afac57a360d231b6ec53d6eba0700b27d933b4" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626ec5afccf44ccbfeb2b232316510bb55b4bf34d891afcb0fb07d2b17d7fe9d" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "pest_meta" +version = "2.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3f45b6caa65c1b08186832745159c2529994146340a7bf44168095469720f5d" +dependencies = [ + "pest", +] + +[[package]] +name = "pest_stack_guard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97e6cd2217057fa86b6eaa512917e58089d875b957a31e35e7ab729977e0a5f2" +dependencies = [ + "psm", + "stacker", +] + [[package]] name = "petgraph" version = "0.6.5" @@ -1696,6 +1739,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "psm" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" +dependencies = [ + "cc", +] + [[package]] name = "quinn" version = "0.11.11" @@ -2117,56 +2169,6 @@ dependencies = [ "zmij", ] -[[package]] -name = "serde_json_path" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b992cea3194eea663ba99a042d61cea4bd1872da37021af56f6a37e0359b9d33" -dependencies = [ - "inventory", - "nom", - "regex", - "serde", - "serde_json", - "serde_json_path_core", - "serde_json_path_macros", - "thiserror 2.0.20", -] - -[[package]] -name = "serde_json_path_core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde67d8dfe7d4967b5a95e247d4148368ddd1e753e500adb34b3ffe40c6bc1bc" -dependencies = [ - "inventory", - "serde", - "serde_json", - "thiserror 2.0.20", -] - -[[package]] -name = "serde_json_path_macros" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "517acfa7f77ddaf5c43d5f119c44a683774e130b4247b7d3210f8924506cfac8" -dependencies = [ - "inventory", - "serde_json_path_core", - "serde_json_path_macros_internal", -] - -[[package]] -name = "serde_json_path_macros_internal" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aafbefbe175fa9bf03ca83ef89beecff7d2a95aaacd5732325b90ac8c3bd7b90" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "serde_regex" version = "1.2.0" @@ -2290,6 +2292,19 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "stacker" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707f49d46706bacf8a2b00d51dace3f9de527c13eec3778f570c411f89e69967" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.61.2", +] + [[package]] name = "string_cache" version = "0.8.9" @@ -2617,6 +2632,12 @@ version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "unicode-ident" version = "1.0.24" diff --git a/Cargo.toml b/Cargo.toml index 9993773..b807315 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ url = "2.1" chrono = { version = "0.4" } log = "0.4" flume = "0.10.14" -flagsmith-flag-engine = "0.6.1" +flagsmith-flag-engine = { git = "https://github.com/Flagsmith/flagsmith-rust-flag-engine", rev = "92e19652b656f489769bdd62187a440f594a3c73" } [dev-dependencies] httpmock = "0.6" diff --git a/benchmarks/Cargo.lock b/benchmarks/Cargo.lock index d258636..7f94ecf 100644 --- a/benchmarks/Cargo.lock +++ b/benchmarks/Cargo.lock @@ -796,10 +796,11 @@ dependencies = [ [[package]] name = "flagsmith-flag-engine" version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882468fdaa8c6fba69c5d473f8d2c7fe25686a775a77e5d029d1768d8aa895ae" +source = "git+https://github.com/Flagsmith/flagsmith-rust-flag-engine?rev=92e19652b656f489769bdd62187a440f594a3c73#92e19652b656f489769bdd62187a440f594a3c73" dependencies = [ "chrono", + "indexmap", + "jsonpath-rust", "md-5", "num-bigint", "num-traits", @@ -807,7 +808,6 @@ dependencies = [ "semver", "serde", "serde_json", - "serde_json_path", "sha2", "uuid", ] @@ -1320,15 +1320,8 @@ checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", "hashbrown", -] - -[[package]] -name = "inventory" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4f0c30c76f2f4ccee3fe55a2435f691ca00c0e4bd87abe4f4a851b1d4dac39b" -dependencies = [ - "rustversion", + "serde", + "serde_core", ] [[package]] @@ -1457,6 +1450,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonpath-rust" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c4668c489390e66d586fe2238ee8568473f7ac1607b411342f787c5e1bedd7" +dependencies = [ + "pest", + "pest_derive", + "regex", + "serde_json", + "thiserror 2.0.20", +] + [[package]] name = "kv-log-macro" version = "1.0.7" @@ -1604,12 +1610,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "mio" version = "1.2.2" @@ -1648,16 +1648,6 @@ dependencies = [ "libc", ] -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "num-bigint" version = "0.4.8" @@ -1751,6 +1741,59 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pest" +version = "2.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8db75153506001cb36ed924f08cadc862eb3f8c4d0d534139f29074769d7660" +dependencies = [ + "memchr", + "pest_stack_guard", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20aa17e11fb35664b67d5214a0afac57a360d231b6ec53d6eba0700b27d933b4" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626ec5afccf44ccbfeb2b232316510bb55b4bf34d891afcb0fb07d2b17d7fe9d" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "pest_meta" +version = "2.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3f45b6caa65c1b08186832745159c2529994146340a7bf44168095469720f5d" +dependencies = [ + "pest", +] + +[[package]] +name = "pest_stack_guard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97e6cd2217057fa86b6eaa512917e58089d875b957a31e35e7ab729977e0a5f2" +dependencies = [ + "psm", + "stacker", +] + [[package]] name = "petgraph" version = "0.6.5" @@ -1872,6 +1915,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "psm" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" +dependencies = [ + "cc", +] + [[package]] name = "quinn" version = "0.11.11" @@ -2286,56 +2338,6 @@ dependencies = [ "zmij", ] -[[package]] -name = "serde_json_path" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b992cea3194eea663ba99a042d61cea4bd1872da37021af56f6a37e0359b9d33" -dependencies = [ - "inventory", - "nom", - "regex", - "serde", - "serde_json", - "serde_json_path_core", - "serde_json_path_macros", - "thiserror 2.0.20", -] - -[[package]] -name = "serde_json_path_core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde67d8dfe7d4967b5a95e247d4148368ddd1e753e500adb34b3ffe40c6bc1bc" -dependencies = [ - "inventory", - "serde", - "serde_json", - "thiserror 2.0.20", -] - -[[package]] -name = "serde_json_path_macros" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "517acfa7f77ddaf5c43d5f119c44a683774e130b4247b7d3210f8924506cfac8" -dependencies = [ - "inventory", - "serde_json_path_core", - "serde_json_path_macros_internal", -] - -[[package]] -name = "serde_json_path_macros_internal" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aafbefbe175fa9bf03ca83ef89beecff7d2a95aaacd5732325b90ac8c3bd7b90" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "serde_regex" version = "1.2.0" @@ -2459,6 +2461,19 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "stacker" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707f49d46706bacf8a2b00d51dace3f9de527c13eec3778f570c411f89e69967" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.61.2", +] + [[package]] name = "statrs" version = "0.18.0" @@ -2825,6 +2840,12 @@ version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "unicode-ident" version = "1.0.24" diff --git a/benchmarks/Cargo.toml b/benchmarks/Cargo.toml index ee0a64c..b5d1c80 100644 --- a/benchmarks/Cargo.toml +++ b/benchmarks/Cargo.toml @@ -6,7 +6,7 @@ publish = false [dev-dependencies] flagsmith = { path = ".." } -flagsmith-flag-engine = "0.6.1" +flagsmith-flag-engine = { git = "https://github.com/Flagsmith/flagsmith-rust-flag-engine", rev = "92e19652b656f489769bdd62187a440f594a3c73" } httpmock = "0.6" divan = { package = "codspeed-divan-compat", version = "6.0.0" } diff --git a/sdk-spec/Cargo.toml b/sdk-spec/Cargo.toml index 3b43581..0054510 100644 --- a/sdk-spec/Cargo.toml +++ b/sdk-spec/Cargo.toml @@ -10,5 +10,5 @@ path = "steps.rs" [dependencies] flagsmith = { path = ".." } -flagsmith-flag-engine = "0.6.1" +flagsmith-flag-engine = { git = "https://github.com/Flagsmith/flagsmith-rust-flag-engine", rev = "92e19652b656f489769bdd62187a440f594a3c73" } serde = { version = "1.0", features = ["derive"] } diff --git a/sdk-spec/steps.rs b/sdk-spec/steps.rs index 52321ce..4eb4033 100644 --- a/sdk-spec/steps.rs +++ b/sdk-spec/steps.rs @@ -38,6 +38,16 @@ pub fn create_client(environment_key: String, api_url: String) -> Flagsmith { Flagsmith::new(environment_key, options) } +// Create the SDK client with local evaluation +pub fn create_client_with_local_evaluation(environment_key: String, api_url: String) -> Flagsmith { + let options = FlagsmithOptions { + api_url, + enable_local_evaluation: true, + ..Default::default() + }; + Flagsmith::new(environment_key, options) +} + // When the application gets the environment flags pub fn get_environment_flags(flagsmith: &Flagsmith) -> Result, Error> { flagsmith.get_environment_flags().map(as_spec_flags) diff --git a/src/flagsmith/mod.rs b/src/flagsmith/mod.rs index 80f7038..c9c2edf 100644 --- a/src/flagsmith/mod.rs +++ b/src/flagsmith/mod.rs @@ -3,7 +3,8 @@ use self::models::{Flag, Flags}; use super::error; use flagsmith_flag_engine::engine::get_evaluation_result; use flagsmith_flag_engine::engine_eval::{ - add_identity_to_context, environment_to_context, EngineEvaluationContext, SegmentSource, + add_identity_to_context, environment_to_context, remove_identity_from_context, + EngineEvaluationContext, SegmentSource, }; use flagsmith_flag_engine::environments::Environment; use flagsmith_flag_engine::identities::Trait; @@ -12,7 +13,6 @@ use log::debug; use models::SDKTrait; use reqwest::header::{self, HeaderMap}; use serde_json::json; -use std::collections::HashMap; use std::sync::mpsc::{self, SyncSender, TryRecvError}; use std::sync::{Arc, Mutex}; use std::{thread, time::Duration}; @@ -76,6 +76,7 @@ pub struct Flagsmith { struct DataStore { environment: Option, evaluation_context: Option, + identity_free_evaluation_context: Option, } impl Flagsmith { @@ -133,6 +134,7 @@ impl Flagsmith { let ds = Arc::new(Mutex::new(DataStore { environment: None, evaluation_context: None, + identity_free_evaluation_context: None, })); let refresh_lock = Arc::new(Mutex::new(())); let (tx, rx) = mpsc::sync_channel::(1); @@ -160,6 +162,8 @@ impl Flagsmith { // Create evaluation context from offline environment let eval_context = environment_to_context(environment.clone()); + data.identity_free_evaluation_context = + Some(remove_identity_from_context(&eval_context)); data.evaluation_context = Some(eval_context); data.environment = Some(environment); @@ -207,7 +211,7 @@ impl Flagsmith { // waits on the network for another caller. { let data = self.datastore.lock().unwrap(); - if let Some(eval_context) = data.evaluation_context.as_ref() { + if let Some(eval_context) = data.identity_free_evaluation_context.as_ref() { return Ok(self.get_environment_flags_from_document(eval_context)); } } @@ -317,14 +321,7 @@ impl Flagsmith { &self, eval_context: &EngineEvaluationContext, ) -> models::Flags { - // Clear segments and identity for environment evaluation - let environment_eval_ctx = EngineEvaluationContext { - environment: eval_context.environment.clone(), - features: eval_context.features.clone(), - segments: HashMap::new(), - identity: None, - }; - let result = get_evaluation_result(&environment_eval_ctx); + let result = get_evaluation_result(eval_context); return models::Flags::from_evaluation_result( &result, self.analytics_processor.clone(), @@ -448,7 +445,9 @@ fn update_environment( .unwrap_or_else(|poisoned| poisoned.into_inner()); let environment = get_environment_from_api(client, environment_url.clone())?; let eval_context = environment_to_context(environment.clone()); + let identity_free_eval_context = remove_identity_from_context(&eval_context); let mut data = datastore.lock().unwrap(); + data.identity_free_evaluation_context = Some(identity_free_eval_context); data.evaluation_context = Some(eval_context); data.environment = Some(environment); return Ok(()); diff --git a/tests/fixtures/mod.rs b/tests/fixtures/mod.rs index 765a364..2cb0d63 100644 --- a/tests/fixtures/mod.rs +++ b/tests/fixtures/mod.rs @@ -58,7 +58,7 @@ pub fn environment_json_with_context_value_override() -> serde_json::Value { "rules": [], "conditions": [{ "operator": "EQUAL", - "property": "$.environment.name", + "property_": "$.environment.name", "value": "Test Environment" }] }] diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 5698b26..d432164 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -1,3 +1,5 @@ +#![allow(non_snake_case)] + use flagsmith::flagsmith::models::SDKTrait; use flagsmith::flagsmith::offline_handler; use flagsmith::{Flagsmith, FlagsmithOptions}; @@ -92,11 +94,11 @@ fn test_get_environment_flags_uses_local_environment_when_available( } #[rstest] -fn test_get_environment_flags_ignores_segment_overrides( +fn test_get_environment_flags__local_evaluation_with_segment_reading_environment__returns_segment_override( mock_server: MockServer, environment_json_with_context_value_override: serde_json::Value, ) { - // Given: a document with a segment override that would match the environment + // Given let api_mock = mock_server.mock(|when, then| { when.method(GET) .path("/api/v1/environment-document/") @@ -118,8 +120,8 @@ fn test_get_environment_flags_ignores_segment_overrides( .get_feature_value_as_string(fixtures::FEATURE_1_NAME) .unwrap(); - // Then: should return environment default value - assert_eq!(flag_value, fixtures::FEATURE_1_STR_VALUE); + // Then + assert_eq!(flag_value, SEGMENT_OVERRIDE_VALUE); api_mock.assert(); }