Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,34 @@ env:
CARGO_TERM_COLOR: always

jobs:
build:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- run: cargo fmt --all -- --check

test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
- run: cargo test --all-features --workspace

msrv:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Get MSRV from package metadata
id: msrv
run: grep rust-version Cargo.toml | cut -d'"' -f2 | sed 's/^/version=/' >> $GITHUB_OUTPUT
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ steps.msrv.outputs.version }}
components: rustfmt, clippy

- name: check crates
run: cargo check --all-features
11 changes: 4 additions & 7 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,9 @@ pub enum ErrorKind {
FlagsmithClientError,
FlagsmithAPIError,
}
impl Error{
pub fn new(kind: ErrorKind, msg: String) -> Error{
Error{
kind,
msg
}
impl Error {
pub fn new(kind: ErrorKind, msg: String) -> Error {
Error { kind, msg }
}
}
impl fmt::Display for Error {
Expand All @@ -46,7 +43,7 @@ impl From<reqwest::Error> for Error {
}
}

impl From<serde_json::Error> for Error {
impl From<serde_json::Error> for Error {
fn from(e: serde_json::Error) -> Self {
Error::new(ErrorKind::FlagsmithAPIError, e.to_string())
}
Expand Down
53 changes: 35 additions & 18 deletions src/flagsmith/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,10 @@ impl Flagsmith {
if flagsmith.options.enable_local_evaluation {
// Update environment once...
if let Err(e) = update_environment(&client, &ds, &environment_url) {
log::warn!("Failed to fetch environment on initialization: {}. Will retry in background.", e);
log::warn!(
"Failed to fetch environment on initialization: {}. Will retry in background.",
e
);
}

// ...and continue updating in the background
Expand All @@ -183,7 +186,10 @@ impl Flagsmith {
}
thread::sleep(Duration::from_millis(environment_refresh_interval_mills));
if let Err(e) = update_environment(&client, &ds, &environment_url) {
log::warn!("Failed to update environment: {}. Will retry on next interval.", e);
log::warn!(
"Failed to update environment: {}. Will retry on next interval.",
e
);
}
});
}
Expand Down Expand Up @@ -230,11 +236,7 @@ impl Flagsmith {
if data.evaluation_context.is_some() {
let eval_context = data.evaluation_context.as_ref().unwrap();
let engine_traits: Vec<Trait> = traits.into_iter().map(|t| t.into()).collect();
return self.get_identity_flags_from_document(
eval_context,
identifier,
engine_traits,
);
return self.get_identity_flags_from_document(eval_context, identifier, engine_traits);
}
return self.default_handler_if_err(self.get_identity_flags_from_api(
identifier,
Expand Down Expand Up @@ -265,9 +267,7 @@ impl Flagsmith {
let segments: Vec<Segment> = result
.segments
.iter()
.filter(|seg_result| {
seg_result.metadata.source == SegmentSource::Api
})
.filter(|seg_result| seg_result.metadata.source == SegmentSource::Api)
.map(|seg_result| Segment {
id: seg_result.metadata.segment_id.unwrap_or(0) as u32,
name: seg_result.name.clone(),
Expand Down Expand Up @@ -299,7 +299,10 @@ impl Flagsmith {
}
}
}
fn get_environment_flags_from_document(&self, eval_context: &EngineEvaluationContext) -> models::Flags {
fn get_environment_flags_from_document(
&self,
eval_context: &EngineEvaluationContext,
) -> models::Flags {
// Clear segments and identity for environment evaluation
let environment_eval_ctx = EngineEvaluationContext {
environment: eval_context.environment.clone(),
Expand Down Expand Up @@ -411,10 +414,7 @@ fn update_environment(
environment_url: &String,
) -> Result<(), error::Error> {
let mut data = datastore.lock().unwrap();
let environment = Some(get_environment_from_api(
&client,
environment_url.clone(),
)?);
let environment = Some(get_environment_from_api(&client, environment_url.clone())?);

let eval_context = environment_to_context(environment.as_ref().unwrap().clone());
data.evaluation_context = Some(eval_context);
Expand Down Expand Up @@ -553,7 +553,10 @@ mod tests {
let version = user_agent.strip_prefix("flagsmith-rust-sdk/").unwrap();

// During cargo test, CARGO_PKG_VERSION is always set, so we should never get "unknown"
assert_ne!(version, "unknown", "Version should not be 'unknown' during cargo test");
assert_ne!(
version, "unknown",
"Version should not be 'unknown' during cargo test"
);

// Version should contain numbers (semantic versioning: e.g., "2.0.0")
assert!(
Expand Down Expand Up @@ -653,8 +656,22 @@ mod tests {
// Then
let flags = _flagsmith.get_environment_flags();
let identity_flags = _flagsmith.get_identity_flags("overridden-id", None, None);
assert_eq!(flags.unwrap().get_feature_value_as_string("some_feature").unwrap().to_owned(), "some-value");
assert_eq!(identity_flags.unwrap().get_feature_value_as_string("some_feature").unwrap().to_owned(), "some-overridden-value");
assert_eq!(
flags
.unwrap()
.get_feature_value_as_string("some_feature")
.unwrap()
.to_owned(),
"some-value"
);
assert_eq!(
identity_flags
.unwrap()
.get_feature_value_as_string("some_feature")
.unwrap()
.to_owned(),
"some-overridden-value"
);
}

#[test]
Expand Down
3 changes: 1 addition & 2 deletions src/flagsmith/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,7 @@ mod tests {
#[test]
fn can_create_flag_from_feature_state() {
// Given
let feature_state: FeatureState =
serde_json::from_str(FEATURE_STATE_JSON_STRING).unwrap();
let feature_state: FeatureState = serde_json::from_str(FEATURE_STATE_JSON_STRING).unwrap();
// When
let flag = Flag::from_feature_state(feature_state.clone(), None);
// Then
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub mod flagsmith;
pub mod error;
pub use crate::flagsmith::{Flagsmith, FlagsmithOptions};
pub mod flagsmith;
pub use crate::flagsmith::models::Flag;
pub use crate::flagsmith::{Flagsmith, FlagsmithOptions};
6 changes: 4 additions & 2 deletions tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,6 @@ fn test_get_identity_flags_calls_api_when_no_local_environment_with_transient_id
api_mock.assert();
}


#[rstest]
fn test_default_flag_is_not_used_when_environment_flags_returned(
mock_server: MockServer,
Expand Down Expand Up @@ -819,6 +818,9 @@ fn test_get_identity_segments_filters_identity_override_segments(local_eval_flag

// Then - should only return API segments with source "api",
assert_eq!(segments.len(), 1, "Should only return API-sourced segments");
assert_eq!(segments[0].name, "Test Segment", "Should return the matching API segment");
assert_eq!(
segments[0].name, "Test Segment",
"Should return the matching API segment"
);
assert_eq!(segments[0].id, 1, "Should have correct segment ID");
}
Loading