Skip to content

Commit

Permalink
fix: Wildcard token refreshing. (#330)
Browse files Browse the repository at this point in the history
* fix: Wildcard token refreshing.

Previously our refreshing algorithm assumed that we always had at least
one project with an explicit name for deciding what to keep. When in
reality we could have a wildcard token (*) for updating. This means that
we should just return the update as our new set of data for this token.

Added another test with a wildcard token to verify that we do indeed
only keep the update.

In addition, added a filter for unique feature names to what we're
keeping to avoid mixing multiple features of the same name.
  • Loading branch information
Christopher Kolstad authored Nov 9, 2023
1 parent c5fdf1d commit 48e6498
Showing 1 changed file with 64 additions and 16 deletions.
80 changes: 64 additions & 16 deletions server/src/http/feature_refresher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use std::{sync::Arc, time::Duration};
use actix_web::http::header::EntityTag;
use chrono::Utc;
use dashmap::DashMap;
use tracing::log::trace;
use tracing::{debug, warn};
use unleash_types::client_features::Segment;
use unleash_types::client_metrics::ClientApplication;
Expand Down Expand Up @@ -80,16 +79,20 @@ fn update_projects_from_feature_update(
vec![]
} else {
let projects_to_update = &token.projects;
let mut to_keep: Vec<ClientFeature> = original
.iter()
.filter(|toggle| {
let p = toggle.project.clone().unwrap_or_else(|| "default".into());
!projects_to_update.contains(&p)
})
.cloned()
.collect();
to_keep.extend(updated.iter().cloned());
to_keep
if projects_to_update.contains(&"*".into()) {
updated.into()
} else {
let mut to_keep: Vec<ClientFeature> = original
.iter()
.filter(|toggle| {
let p = toggle.project.clone().unwrap_or_else(|| "default".into());
!projects_to_update.contains(&p)
})
.cloned()
.collect();
to_keep.extend(updated.iter().cloned());
to_keep
}
}
}

Expand Down Expand Up @@ -321,11 +324,6 @@ impl FeatureRefresher {
})
.await;

trace!(
"Made a request to unleash for features and received the following: {:#?}",
features_result
);

match features_result {
Ok(feature_response) => match feature_response {
ClientFeaturesResponse::NoUpdate(tag) => {
Expand Down Expand Up @@ -1284,4 +1282,54 @@ mod tests {
1
);
}

#[test]
pub fn if_token_is_wildcard_our_entire_cache_is_replaced_by_update() {
let features = vec![
ClientFeature {
name: "my.first.toggle.in.default".to_string(),
feature_type: Some("release".into()),
description: None,
created_at: None,
last_seen_at: None,
enabled: true,
stale: None,
impression_data: None,
project: Some("default".into()),
strategies: None,
variants: None,
dependencies: None,
},
ClientFeature {
name: "my.second.toggle.in.testproject".to_string(),
feature_type: Some("release".into()),
description: None,
created_at: None,
last_seen_at: None,
enabled: false,
stale: None,
impression_data: None,
project: Some("testproject".into()),
strategies: None,
variants: None,
dependencies: None,
},
];
let edge_token = EdgeToken {
token: "".to_string(),
token_type: Some(TokenType::Client),
environment: None,
projects: vec![String::from("*")],
status: TokenValidationStatus::Validated,
};
let update: Vec<ClientFeature> = features
.clone()
.iter()
.filter(|t| t.project == Some("default".into()))
.cloned()
.collect();
let updated = super::update_projects_from_feature_update(&edge_token, &features, &update);
assert_eq!(updated.len(), 1);
assert!(updated.iter().all(|f| f.project == Some("default".into())))
}
}

0 comments on commit 48e6498

Please sign in to comment.