| | use std::time::Duration; |
| |
|
| | use super::*; |
| | use crate::chat::{ |
| | Chat, create_broadcast, create_group, create_group_unencrypted, get_chat_contacts, |
| | }; |
| | use crate::mimeparser::SystemMessage; |
| | use crate::qr::check_qr; |
| | use crate::securejoin::{get_securejoin_qr, join_securejoin, join_securejoin_with_ux_info}; |
| | use crate::test_utils::{TestContext, TestContextManager, get_chat_msg}; |
| | use crate::tools::SystemTime; |
| | use pretty_assertions::assert_eq; |
| | use serde_json::{Number, Value}; |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_maybe_send_stats() -> Result<()> { |
| | let alice = &TestContext::new_alice().await; |
| |
|
| | |
| | |
| | alice |
| | .set_config_internal(Config::StatsSending, Some("1")) |
| | .await?; |
| |
|
| | let chat_id = maybe_send_stats(alice).await?.unwrap(); |
| | let msg = get_chat_msg(alice, chat_id, 0, 2).await; |
| | assert_eq!(msg.get_info_type(), SystemMessage::ChatE2ee); |
| |
|
| | let chat = Chat::load_from_db(alice, chat_id).await?; |
| | assert!(chat.is_encrypted(alice).await?); |
| | let contacts = get_chat_contacts(alice, chat_id).await?; |
| | assert_eq!(contacts.len(), 1); |
| | let contact = Contact::get_by_id(alice, contacts[0]).await?; |
| | assert!(contact.is_verified(alice).await?); |
| |
|
| | let msg = get_chat_msg(alice, chat_id, 1, 2).await; |
| | assert_eq!(msg.get_filename().unwrap(), "statistics.txt"); |
| |
|
| | let stats = tokio::fs::read(msg.get_file(alice).unwrap()).await?; |
| | let stats = std::str::from_utf8(&stats)?; |
| | println!("\nEmpty account:\n{stats}\n"); |
| | assert!(stats.contains(r#""contact_stats": []"#)); |
| |
|
| | let r: serde_json::Value = serde_json::from_str(stats)?; |
| | assert_eq!( |
| | r.get("contact_stats").unwrap(), |
| | &serde_json::Value::Array(vec![]) |
| | ); |
| | assert_eq!(r.get("core_version").unwrap(), DC_VERSION_STR); |
| |
|
| | assert_eq!(maybe_send_stats(alice).await?, None); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_rewound_time() -> Result<()> { |
| | let alice = &TestContext::new_alice().await; |
| | alice.set_config_bool(Config::StatsSending, true).await?; |
| |
|
| | |
| | |
| | assert!(maybe_send_stats(alice).await?.is_none()); |
| | let sent = alice.pop_sent_msg().await; |
| | assert_eq!( |
| | sent.load_from_db().await.get_filename().unwrap(), |
| | "statistics.txt" |
| | ); |
| |
|
| | const EIGHT_DAYS: Duration = Duration::from_secs(3600 * 24 * 14); |
| | SystemTime::shift(EIGHT_DAYS); |
| |
|
| | maybe_send_stats(alice).await?.unwrap(); |
| |
|
| | |
| | SystemTime::shift_back(EIGHT_DAYS); |
| |
|
| | assert!(maybe_send_stats(alice).await?.is_none()); |
| |
|
| | |
| | SystemTime::shift(EIGHT_DAYS); |
| | maybe_send_stats(alice).await?.unwrap(); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_stats_one_contact() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| | alice.set_config_bool(Config::StatsSending, true).await?; |
| |
|
| | let stats = get_stats(alice).await?; |
| | let r: serde_json::Value = serde_json::from_str(&stats)?; |
| |
|
| | tcm.send_recv_accept(bob, alice, "Hi!").await; |
| |
|
| | let stats = get_stats(alice).await?; |
| | println!("\nWith Bob:\n{stats}\n"); |
| | let r2: serde_json::Value = serde_json::from_str(&stats)?; |
| |
|
| | assert_eq!( |
| | r.get("key_create_timestamps").unwrap(), |
| | r2.get("key_create_timestamps").unwrap() |
| | ); |
| | assert_eq!(r.get("stats_id").unwrap(), r2.get("stats_id").unwrap()); |
| | let contact_stats = r2.get("contact_stats").unwrap().as_array().unwrap(); |
| | assert_eq!(contact_stats.len(), 1); |
| | let contact_info = &contact_stats[0]; |
| | assert!(contact_info.get("bot").is_none()); |
| | assert_eq!( |
| | contact_info.get("direct_chat").unwrap(), |
| | &serde_json::Value::Bool(true) |
| | ); |
| | assert!(contact_info.get("transitive_chain").is_none(),); |
| | assert_eq!( |
| | contact_info.get("verified").unwrap(), |
| | &serde_json::Value::String("Opportunistic".to_string()) |
| | ); |
| | assert_eq!( |
| | contact_info.get("new").unwrap(), |
| | &serde_json::Value::Bool(true) |
| | ); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_message_stats() -> Result<()> { |
| | #[track_caller] |
| | fn check_stats(stats: &str, expected: &BTreeMap<Chattype, MessageStats>) { |
| | let actual: serde_json::Value = serde_json::from_str(stats).unwrap(); |
| | let actual = &actual["message_stats"]; |
| |
|
| | let expected = serde_json::to_string_pretty(&expected).unwrap(); |
| | let expected: serde_json::Value = serde_json::from_str(&expected).unwrap(); |
| |
|
| | assert_eq!(actual, &expected); |
| | } |
| |
|
| | async fn update_get_stats(context: &Context) -> String { |
| | update_message_stats(context).await.unwrap(); |
| | get_stats(context).await.unwrap() |
| | } |
| |
|
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| | |
| | alice |
| | .set_config_internal(Config::StatsSending, Some("1")) |
| | .await?; |
| | let email_chat = alice.create_email_chat(bob).await; |
| | let encrypted_chat = alice.create_chat(bob).await; |
| |
|
| | let mut expected: BTreeMap<Chattype, MessageStats> = BTreeMap::from_iter([ |
| | (Chattype::Single, MessageStats::default()), |
| | (Chattype::Group, MessageStats::default()), |
| | (Chattype::OutBroadcast, MessageStats::default()), |
| | ]); |
| |
|
| | check_stats(&update_get_stats(alice).await, &expected); |
| |
|
| | alice.send_text(email_chat.id, "foo").await; |
| | expected.get_mut(&Chattype::Single).unwrap().unencrypted += 1; |
| | check_stats(&update_get_stats(alice).await, &expected); |
| |
|
| | alice.send_text(encrypted_chat.id, "foo").await; |
| | expected |
| | .get_mut(&Chattype::Single) |
| | .unwrap() |
| | .unverified_encrypted += 1; |
| | check_stats(&update_get_stats(alice).await, &expected); |
| |
|
| | alice.send_text(encrypted_chat.id, "foo").await; |
| | expected |
| | .get_mut(&Chattype::Single) |
| | .unwrap() |
| | .unverified_encrypted += 1; |
| | check_stats(&update_get_stats(alice).await, &expected); |
| |
|
| | let group = alice.create_group_with_members("Pizza", &[bob]).await; |
| | alice.send_text(group, "foo").await; |
| | expected |
| | .get_mut(&Chattype::Group) |
| | .unwrap() |
| | .unverified_encrypted += 1; |
| | check_stats(&update_get_stats(alice).await, &expected); |
| |
|
| | tcm.execute_securejoin(alice, bob).await; |
| | check_stats(&update_get_stats(alice).await, &expected); |
| |
|
| | alice.send_text(alice.get_self_chat().await.id, "foo").await; |
| | expected.get_mut(&Chattype::Single).unwrap().only_to_self += 1; |
| | check_stats(&update_get_stats(alice).await, &expected); |
| |
|
| | let empty_group = create_group(alice, "Notes").await?; |
| | alice.send_text(empty_group, "foo").await; |
| | expected.get_mut(&Chattype::Group).unwrap().only_to_self += 1; |
| | check_stats(&update_get_stats(alice).await, &expected); |
| |
|
| | let empty_unencrypted = create_group_unencrypted(alice, "Email thread").await?; |
| | alice.send_text(empty_unencrypted, "foo").await; |
| | expected.get_mut(&Chattype::Group).unwrap().only_to_self += 1; |
| | check_stats(&update_get_stats(alice).await, &expected); |
| |
|
| | let group = alice.create_group_with_members("Pizza 2", &[bob]).await; |
| | alice.send_text(group, "foo").await; |
| | expected.get_mut(&Chattype::Group).unwrap().verified += 1; |
| | check_stats(&update_get_stats(alice).await, &expected); |
| |
|
| | let empty_broadcast = create_broadcast(alice, "Channel".to_string()).await?; |
| | alice.send_text(empty_broadcast, "foo").await; |
| | expected |
| | .get_mut(&Chattype::OutBroadcast) |
| | .unwrap() |
| | .only_to_self += 1; |
| | check_stats(&update_get_stats(alice).await, &expected); |
| |
|
| | |
| | let rcvd = tcm.send_recv(bob, alice, "bar").await; |
| | check_stats(&update_get_stats(alice).await, &expected); |
| |
|
| | |
| | crate::reaction::send_reaction(alice, rcvd.id, "👍") |
| | .await |
| | .unwrap(); |
| | check_stats(&update_get_stats(alice).await, &expected); |
| |
|
| | let before_sending = get_stats(alice).await.unwrap(); |
| |
|
| | let stats = send_and_read_stats(alice).await; |
| | |
| | assert_eq!(before_sending, stats); |
| |
|
| | |
| | SystemTime::shift(Duration::from_secs(8 * 24 * 3600)); |
| |
|
| | let stats = send_and_read_stats(alice).await; |
| | assert_eq!(before_sending, stats); |
| |
|
| | check_stats(&stats, &expected); |
| |
|
| | SystemTime::shift(Duration::from_secs(8 * 24 * 3600)); |
| | tcm.send_recv(alice, bob, "Hi").await; |
| | expected.get_mut(&Chattype::Single).unwrap().verified += 1; |
| | update_message_stats(alice).await?; |
| | update_message_stats(alice).await?; |
| | tcm.send_recv(alice, bob, "Hi").await; |
| | expected.get_mut(&Chattype::Single).unwrap().verified += 1; |
| | tcm.send_recv(alice, bob, "Hi").await; |
| | expected.get_mut(&Chattype::Single).unwrap().verified += 1; |
| |
|
| | check_stats(&send_and_read_stats(alice).await, &expected); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | async fn send_and_read_stats(context: &TestContext) -> String { |
| | let chat_id = maybe_send_stats(context).await.unwrap().unwrap(); |
| | let msg = context.get_last_msg_in(chat_id).await; |
| | assert_eq!(msg.get_filename().unwrap(), "statistics.txt"); |
| |
|
| | let stats = tokio::fs::read(msg.get_file(context).unwrap()) |
| | .await |
| | .unwrap(); |
| | String::from_utf8(stats).unwrap() |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_stats_securejoin_sources() -> Result<()> { |
| | async fn check_stats(context: &TestContext, expected: &SecurejoinSources) { |
| | let stats = get_stats(context).await.unwrap(); |
| | let actual: serde_json::Value = serde_json::from_str(&stats).unwrap(); |
| | let actual = &actual["securejoin_sources"]; |
| |
|
| | let expected = serde_json::to_string_pretty(&expected).unwrap(); |
| | let expected: serde_json::Value = serde_json::from_str(&expected).unwrap(); |
| |
|
| | assert_eq!(actual, &expected); |
| | } |
| |
|
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| | alice.set_config_bool(Config::StatsSending, true).await?; |
| |
|
| | let mut expected = SecurejoinSources { |
| | unknown: 0, |
| | external_link: 0, |
| | internal_link: 0, |
| | clipboard: 0, |
| | image_loaded: 0, |
| | scan: 0, |
| | }; |
| |
|
| | check_stats(alice, &expected).await; |
| |
|
| | let qr = get_securejoin_qr(bob, None).await?; |
| |
|
| | join_securejoin(alice, &qr).await?; |
| | expected.unknown += 1; |
| | check_stats(alice, &expected).await; |
| |
|
| | join_securejoin(alice, &qr).await?; |
| | expected.unknown += 1; |
| | check_stats(alice, &expected).await; |
| |
|
| | join_securejoin_with_ux_info(alice, &qr, Some(SecurejoinSource::Clipboard), None).await?; |
| | expected.clipboard += 1; |
| | check_stats(alice, &expected).await; |
| |
|
| | join_securejoin_with_ux_info(alice, &qr, Some(SecurejoinSource::ExternalLink), None).await?; |
| | expected.external_link += 1; |
| | check_stats(alice, &expected).await; |
| |
|
| | join_securejoin_with_ux_info(alice, &qr, Some(SecurejoinSource::InternalLink), None).await?; |
| | expected.internal_link += 1; |
| | check_stats(alice, &expected).await; |
| |
|
| | join_securejoin_with_ux_info(alice, &qr, Some(SecurejoinSource::ImageLoaded), None).await?; |
| | expected.image_loaded += 1; |
| | check_stats(alice, &expected).await; |
| |
|
| | join_securejoin_with_ux_info(alice, &qr, Some(SecurejoinSource::Scan), None).await?; |
| | expected.scan += 1; |
| | check_stats(alice, &expected).await; |
| |
|
| | join_securejoin_with_ux_info(alice, &qr, Some(SecurejoinSource::Clipboard), None).await?; |
| | expected.clipboard += 1; |
| | check_stats(alice, &expected).await; |
| |
|
| | join_securejoin_with_ux_info(alice, &qr, Some(SecurejoinSource::Clipboard), None).await?; |
| | expected.clipboard += 1; |
| | check_stats(alice, &expected).await; |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_stats_securejoin_uipaths() -> Result<()> { |
| | async fn check_stats(context: &TestContext, expected: &SecurejoinUiPaths) { |
| | let stats = get_stats(context).await.unwrap(); |
| | let actual: serde_json::Value = serde_json::from_str(&stats).unwrap(); |
| | let actual = &actual["securejoin_uipaths"]; |
| |
|
| | let expected = serde_json::to_string_pretty(&expected).unwrap(); |
| | let expected: serde_json::Value = serde_json::from_str(&expected).unwrap(); |
| |
|
| | assert_eq!(actual, &expected); |
| | } |
| |
|
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| | alice.set_config_bool(Config::StatsSending, true).await?; |
| |
|
| | let mut expected = SecurejoinUiPaths { |
| | other: 0, |
| | qr_icon: 0, |
| | new_contact: 0, |
| | }; |
| |
|
| | check_stats(alice, &expected).await; |
| |
|
| | let qr = get_securejoin_qr(bob, None).await?; |
| |
|
| | join_securejoin(alice, &qr).await?; |
| | expected.other += 1; |
| | check_stats(alice, &expected).await; |
| |
|
| | join_securejoin(alice, &qr).await?; |
| | expected.other += 1; |
| | check_stats(alice, &expected).await; |
| |
|
| | join_securejoin_with_ux_info(alice, &qr, None, Some(SecurejoinUiPath::NewContact)).await?; |
| | expected.new_contact += 1; |
| | check_stats(alice, &expected).await; |
| |
|
| | join_securejoin_with_ux_info(alice, &qr, None, Some(SecurejoinUiPath::NewContact)).await?; |
| | expected.new_contact += 1; |
| | check_stats(alice, &expected).await; |
| |
|
| | join_securejoin_with_ux_info(alice, &qr, None, Some(SecurejoinUiPath::QrIcon)).await?; |
| | expected.qr_icon += 1; |
| | check_stats(alice, &expected).await; |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_stats_securejoin_invites() -> Result<()> { |
| | async fn check_stats(context: &TestContext, expected: &[JoinedInvite]) { |
| | let stats = get_stats(context).await.unwrap(); |
| | let actual: serde_json::Value = serde_json::from_str(&stats).unwrap(); |
| | let actual = &actual["securejoin_invites"]; |
| |
|
| | let expected = serde_json::to_string_pretty(&expected).unwrap(); |
| | let expected: serde_json::Value = serde_json::from_str(&expected).unwrap(); |
| |
|
| | assert_eq!(actual, &expected); |
| | } |
| |
|
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| | let charlie = &tcm.charlie().await; |
| | alice.set_config_bool(Config::StatsSending, true).await?; |
| | let _first_sent_stats = alice.pop_sent_msg().await; |
| |
|
| | let mut expected = vec![]; |
| |
|
| | check_stats(alice, &expected).await; |
| |
|
| | let qr = get_securejoin_qr(bob, None).await?; |
| |
|
| | |
| | check_qr(alice, &qr).await?; |
| | tcm.exec_securejoin_qr(alice, bob, &qr).await; |
| | expected.push(JoinedInvite { |
| | already_existed: false, |
| | already_verified: false, |
| | typ: "contact".to_string(), |
| | }); |
| | check_stats(alice, &expected).await; |
| |
|
| | check_qr(alice, &qr).await?; |
| | tcm.exec_securejoin_qr(alice, bob, &qr).await; |
| | expected.push(JoinedInvite { |
| | already_existed: true, |
| | already_verified: true, |
| | typ: "contact".to_string(), |
| | }); |
| | check_stats(alice, &expected).await; |
| |
|
| | let group_id = create_group(bob, "Group chat").await?; |
| | let qr = get_securejoin_qr(bob, Some(group_id)).await?; |
| |
|
| | check_qr(alice, &qr).await?; |
| | tcm.exec_securejoin_qr(alice, bob, &qr).await; |
| | expected.push(JoinedInvite { |
| | already_existed: true, |
| | already_verified: true, |
| | typ: "group".to_string(), |
| | }); |
| | check_stats(alice, &expected).await; |
| |
|
| | |
| | alice.add_or_lookup_contact(charlie).await; |
| | let group_id = create_group(charlie, "Group chat 2").await?; |
| | let qr = get_securejoin_qr(charlie, Some(group_id)).await?; |
| |
|
| | check_qr(alice, &qr).await?; |
| | tcm.exec_securejoin_qr(alice, bob, &qr).await; |
| | expected.push(JoinedInvite { |
| | already_existed: true, |
| | already_verified: false, |
| | typ: "group".to_string(), |
| | }); |
| | check_stats(alice, &expected).await; |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_stats_is_chatmail() -> Result<()> { |
| | let alice = &TestContext::new_alice().await; |
| | alice.set_config_bool(Config::StatsSending, true).await?; |
| |
|
| | let r = get_stats(alice).await?; |
| | let r: serde_json::Value = serde_json::from_str(&r)?; |
| | assert_eq!(r.get("is_chatmail").unwrap().as_bool().unwrap(), false); |
| |
|
| | alice.set_config_bool(Config::IsChatmail, true).await?; |
| |
|
| | let r = get_stats(alice).await?; |
| | let r: serde_json::Value = serde_json::from_str(&r)?; |
| | assert_eq!(r.get("is_chatmail").unwrap().as_bool().unwrap(), true); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_stats_key_creation_timestamp() -> Result<()> { |
| | |
| | const ALICE_KEY_CREATION_TIME: u128 = 1582855645; |
| |
|
| | let alice = &TestContext::new_alice().await; |
| | alice.set_config_bool(Config::StatsSending, true).await?; |
| |
|
| | let r = get_stats(alice).await?; |
| | let r: serde_json::Value = serde_json::from_str(&r)?; |
| | let key_create_timestamps = r.get("key_create_timestamps").unwrap().as_array().unwrap(); |
| | assert_eq!( |
| | key_create_timestamps, |
| | &vec![Value::Number( |
| | Number::from_u128(ALICE_KEY_CREATION_TIME).unwrap() |
| | )] |
| | ); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_stats_enable_disable_timestamps() -> Result<()> { |
| | async fn get_timestamps(context: &TestContext) -> (Vec<i64>, Vec<i64>) { |
| | let stats = get_stats(context).await.unwrap(); |
| | let stats: serde_json::Value = serde_json::from_str(&stats).unwrap(); |
| | let enabled_ts = &stats["sending_enabled_timestamps"]; |
| | let disabled_ts = &stats["sending_disabled_timestamps"]; |
| |
|
| | let enabled_ts = enabled_ts |
| | .as_array() |
| | .unwrap() |
| | .iter() |
| | .map(|v| v.as_i64().unwrap()) |
| | .collect(); |
| | let disabled_ts = disabled_ts |
| | .as_array() |
| | .unwrap() |
| | .iter() |
| | .map(|v| v.as_i64().unwrap()) |
| | .collect(); |
| |
|
| | (enabled_ts, disabled_ts) |
| | } |
| |
|
| | let alice = &TestContext::new_alice().await; |
| |
|
| | |
| | let enabled_min = time(); |
| | alice.set_config_bool(Config::StatsSending, true).await?; |
| | let enabled_max = time(); |
| |
|
| | let (enabled_ts, disabled_ts) = get_timestamps(alice).await; |
| |
|
| | |
| | assert_eq!(enabled_ts.len(), 1); |
| | assert!(enabled_ts[0] >= enabled_min); |
| | assert!(enabled_ts[0] <= enabled_max); |
| |
|
| | assert!(disabled_ts.is_empty()); |
| |
|
| | |
| | alice.set_config_bool(Config::StatsSending, true).await?; |
| | SystemTime::shift(Duration::from_secs(10)); |
| | alice.set_config_bool(Config::StatsSending, true).await?; |
| | assert_eq!( |
| | get_timestamps(alice).await, |
| | (enabled_ts.clone(), disabled_ts.clone()) |
| | ); |
| |
|
| | |
| | let disabled_min = time(); |
| | alice.set_config_bool(Config::StatsSending, false).await?; |
| | let disabled_max = time(); |
| |
|
| | let (new_enabled_ts, new_disabled_ts) = get_timestamps(alice).await; |
| |
|
| | assert_eq!(new_enabled_ts, enabled_ts); |
| |
|
| | |
| | assert_eq!(new_disabled_ts.len(), 1); |
| | assert!(new_disabled_ts[0] >= disabled_min); |
| | assert!(new_disabled_ts[0] <= disabled_max); |
| |
|
| | |
| | assert_ne!(new_disabled_ts[0], enabled_ts[0]); |
| |
|
| | |
| | SystemTime::shift(Duration::from_secs(10)); |
| | let enabled_min = time(); |
| | alice.set_config_bool(Config::StatsSending, true).await?; |
| | let enabled_max = time(); |
| |
|
| | let (newer_enabled_ts, newer_disabled_ts) = get_timestamps(alice).await; |
| |
|
| | |
| | assert_eq!(newer_disabled_ts, new_disabled_ts); |
| |
|
| | |
| | assert_eq!(newer_enabled_ts.len(), 2); |
| | assert!(newer_enabled_ts[1] >= enabled_min); |
| | assert!(newer_enabled_ts[1] <= enabled_max); |
| | assert_eq!(newer_enabled_ts[0], new_enabled_ts[0]); |
| |
|
| | |
| | assert_ne!(newer_disabled_ts[0], newer_enabled_ts[1]); |
| |
|
| | Ok(()) |
| | } |
| |
|