fn test_sync_via_bridge()

in components/tabs/src/sync/bridge.rs [142:281]


    fn test_sync_via_bridge() {
        env_logger::try_init().ok();

        let store = Arc::new(TabsStore::new_with_mem_path("test-bridge_incoming"));

        // Set some local tabs for our device.
        let my_tabs = vec![
            RemoteTab {
                title: "my first tab".to_string(),
                url_history: vec!["http://1.com".to_string()],
                last_used: 2,
                ..Default::default()
            },
            RemoteTab {
                title: "my second tab".to_string(),
                url_history: vec!["http://2.com".to_string()],
                last_used: 1,
                ..Default::default()
            },
        ];
        store.set_local_tabs(my_tabs.clone());

        let bridge = store.bridged_engine();

        let client_data = ClientData {
            local_client_id: "my-device".to_string(),
            recent_clients: HashMap::from([
                (
                    "my-device".to_string(),
                    RemoteClient {
                        fxa_device_id: None,
                        device_name: "my device".to_string(),
                        device_type: sync15::DeviceType::Unknown,
                    },
                ),
                (
                    "device-no-tabs".to_string(),
                    RemoteClient {
                        fxa_device_id: None,
                        device_name: "device with no tabs".to_string(),
                        device_type: DeviceType::Unknown,
                    },
                ),
                (
                    "device-with-a-tab".to_string(),
                    RemoteClient {
                        fxa_device_id: None,
                        device_name: "device with a tab".to_string(),
                        device_type: DeviceType::Unknown,
                    },
                ),
            ]),
        };
        bridge
            .prepare_for_sync(&serde_json::to_string(&client_data).unwrap())
            .expect("should work");

        let records = vec![
            // my-device should be ignored by sync - here it is acting as what our engine last
            // wrote, but the actual tabs in our store we set above are what should be used.
            json!({
                "id": "my-device",
                "clientName": "my device",
                "tabs": [{
                    "title": "the title",
                    "urlHistory": [
                        "https://mozilla.org/"
                    ],
                    "icon": "https://mozilla.org/icon",
                    "lastUsed": 1643764207
                }]
            }),
            json!({
                "id": "device-no-tabs",
                "clientName": "device with no tabs",
                "tabs": [],
            }),
            json!({
                "id": "device-with-a-tab",
                "clientName": "device with a tab",
                "tabs": [{
                    "title": "the title",
                    "urlHistory": [
                        "https://mozilla.org/"
                    ],
                    "icon": "https://mozilla.org/icon",
                    "lastUsed": 1643764207
                }]
            }),
            // This has the main payload as OK but the tabs part invalid.
            json!({
                "id": "device-with-invalid-tab",
                "clientName": "device with a tab",
                "tabs": [{
                    "foo": "bar",
                }]
            }),
            // We want this to be a valid payload but an invalid tab - so it needs an ID.
            json!({
                "id": "invalid-tab",
                "foo": "bar"
            }),
        ];

        let mut incoming = Vec::new();
        for record in records {
            // Annoyingly we can't use `IncomingEnvelope` directly as it intentionally doesn't
            // support Serialize - so need to use explicit json.
            let envelope = json!({
                "id": record.get("id"),
                "modified": 0,
                "payload": serde_json::to_string(&record).unwrap(),
            });
            incoming.push(serde_json::to_string(&envelope).unwrap());
        }

        bridge.store_incoming(incoming).expect("should store");

        let out = bridge.apply().expect("should apply");

        assert_eq!(out.len(), 1);
        let ours = serde_json::from_str::<serde_json::Value>(&out[0]).unwrap();
        // As above, can't use `OutgoingEnvelope` as it doesn't Deserialize.
        // First, convert my_tabs from the local `RemoteTab` to the Sync specific `TabsRecord`
        let expected_tabs: Vec<TabsRecordTab> =
            my_tabs.into_iter().map(|t| t.to_record_tab()).collect();
        let expected = json!({
            "id": "my-device".to_string(),
            "payload": json!({
                "id": "my-device".to_string(),
                "clientName": "my device",
                "tabs": serde_json::to_value(expected_tabs).unwrap(),
            }).to_string(),
            "ttl": TABS_CLIENT_TTL,
        });

        assert_eq!(ours, expected);
        bridge.set_uploaded(1234, vec![]).unwrap();
        assert_eq!(bridge.last_sync().unwrap(), 1234);
    }