Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/rust/remote_settings/src/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 5 kB image not shown  

Quelle  cache.rs   Sprache: unbekannt

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use crate::RemoteSettingsResponse;
use std::collections::HashSet;

/// Merge a cached RemoteSettingsResponse and a newly downloaded one to get a merged response
///
/// cached is a previously downloaded remote settings response (possibly run through merge_cache_and_response).
/// new is a newly downloaded remote settings response (with `_expected` set to the last_modified
/// time of the cached response).
///
/// This will merge the records from both responses, handle deletions/tombstones, and return a
/// response that has:
///   - The newest `last_modified_date`
///   - A record list containing the newest version of all live records.  Deleted records will not
///     be present in this list.
///
/// If everything is working properly, the returned value will exactly match what the server would
/// have returned if there was no `_expected` param.
pub fn merge_cache_and_response(
    cached: RemoteSettingsResponse,
    new: RemoteSettingsResponse,
) -> RemoteSettingsResponse {
    let new_record_ids = new
        .records
        .iter()
        .map(|r| r.id.as_str())
        .collect::<HashSet<&str>>();
    // Start with any cached records that don't appear in new.
    let mut records = cached
        .records
        .into_iter()
        .filter(|r| !new_record_ids.contains(r.id.as_str()))
        // deleted should always be false, check it just in case
        .filter(|r| !r.deleted)
        .collect::<Vec<_>>();
    // Add all (non-deleted) records from new
    records.extend(new.records.into_iter().filter(|r| !r.deleted));

    RemoteSettingsResponse {
        last_modified: new.last_modified,
        records,
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::{RemoteSettingsRecord, RsJsonObject};

    // Quick way to generate the fields data for our mock records
    fn fields(data: &str) -> RsJsonObject {
        let mut map = serde_json::Map::new();
        map.insert("data".into(), data.into());
        map
    }

    #[test]
    fn test_combine_cache_and_response() {
        let cached_response = RemoteSettingsResponse {
            last_modified: 1000,
            records: vec![
                RemoteSettingsRecord {
                    id: "a".into(),
                    last_modified: 100,
                    deleted: false,
                    attachment: None,
                    fields: fields("a"),
                },
                RemoteSettingsRecord {
                    id: "b".into(),
                    last_modified: 200,
                    deleted: false,
                    attachment: None,
                    fields: fields("b"),
                },
                RemoteSettingsRecord {
                    id: "c".into(),
                    last_modified: 300,
                    deleted: false,
                    attachment: None,
                    fields: fields("c"),
                },
            ],
        };
        let new_response = RemoteSettingsResponse {
            last_modified: 2000,
            records: vec![
                // d is new
                RemoteSettingsRecord {
                    id: "d".into(),
                    last_modified: 1300,
                    deleted: false,
                    attachment: None,
                    fields: fields("d"),
                },
                // b was deleted
                RemoteSettingsRecord {
                    id: "b".into(),
                    last_modified: 1200,
                    deleted: true,
                    attachment: None,
                    fields: RsJsonObject::new(),
                },
                // a was updated
                RemoteSettingsRecord {
                    id: "a".into(),
                    last_modified: 1100,
                    deleted: false,
                    attachment: None,
                    fields: fields("a-with-new-data"),
                },
                // c was not modified, so it's not present in the new response
            ],
        };
        let mut merged = merge_cache_and_response(cached_response, new_response);
        // Sort the records to make the assertion easier
        merged.records.sort_by_key(|r| r.id.clone());
        assert_eq!(
            merged,
            RemoteSettingsResponse {
                last_modified: 2000,
                records: vec![
                    // a was updated
                    RemoteSettingsRecord {
                        id: "a".into(),
                        last_modified: 1100,
                        deleted: false,
                        attachment: None,
                        fields: fields("a-with-new-data"),
                    },
                    RemoteSettingsRecord {
                        id: "c".into(),
                        last_modified: 300,
                        deleted: false,
                        attachment: None,
                        fields: fields("c"),
                    },
                    RemoteSettingsRecord {
                        id: "d".into(),
                        last_modified: 1300,
                        deleted: false,
                        attachment: None,
                        fields: fields("d"),
                    },
                ],
            }
        );
    }
}

[ Dauer der Verarbeitung: 0.33 Sekunden  (vorverarbeitet)  ]