Add SystemClock
(#8239)
This PR adds a `SystemClock` trait for abstracting away the system clock. This allows us to swap out the real system clock with a `FakeSystemClock` in the tests, thus allowing the fake passage of time. We're using this in `Telemetry` to better mock the clock for testing purposes. Release Notes: - N/A
This commit is contained in:
parent
cc8e3c2286
commit
0de8672044
16 changed files with 213 additions and 55 deletions
|
@ -2,6 +2,7 @@ mod event_coalescer;
|
|||
|
||||
use crate::TelemetrySettings;
|
||||
use chrono::{DateTime, Utc};
|
||||
use clock::SystemClock;
|
||||
use futures::Future;
|
||||
use gpui::{AppContext, AppMetadata, BackgroundExecutor, Task};
|
||||
use once_cell::sync::Lazy;
|
||||
|
@ -24,6 +25,7 @@ use util::TryFutureExt;
|
|||
use self::event_coalescer::EventCoalescer;
|
||||
|
||||
pub struct Telemetry {
|
||||
clock: Arc<dyn SystemClock>,
|
||||
http_client: Arc<ZedHttpClient>,
|
||||
executor: BackgroundExecutor,
|
||||
state: Arc<Mutex<TelemetryState>>,
|
||||
|
@ -156,7 +158,11 @@ static ZED_CLIENT_CHECKSUM_SEED: Lazy<Option<Vec<u8>>> = Lazy::new(|| {
|
|||
});
|
||||
|
||||
impl Telemetry {
|
||||
pub fn new(client: Arc<ZedHttpClient>, cx: &mut AppContext) -> Arc<Self> {
|
||||
pub fn new(
|
||||
clock: Arc<dyn SystemClock>,
|
||||
client: Arc<ZedHttpClient>,
|
||||
cx: &mut AppContext,
|
||||
) -> Arc<Self> {
|
||||
let release_channel =
|
||||
ReleaseChannel::try_global(cx).map(|release_channel| release_channel.display_name());
|
||||
|
||||
|
@ -205,6 +211,7 @@ impl Telemetry {
|
|||
|
||||
// TODO: Replace all hardware stuff with nested SystemSpecs json
|
||||
let this = Arc::new(Self {
|
||||
clock,
|
||||
http_client: client,
|
||||
executor: cx.background_executor().clone(),
|
||||
state,
|
||||
|
@ -317,7 +324,8 @@ impl Telemetry {
|
|||
operation,
|
||||
copilot_enabled,
|
||||
copilot_enabled_for_language,
|
||||
milliseconds_since_first_event: self.milliseconds_since_first_event(Utc::now()),
|
||||
milliseconds_since_first_event: self
|
||||
.milliseconds_since_first_event(self.clock.utc_now()),
|
||||
};
|
||||
|
||||
self.report_event(event)
|
||||
|
@ -333,7 +341,8 @@ impl Telemetry {
|
|||
suggestion_id,
|
||||
suggestion_accepted,
|
||||
file_extension,
|
||||
milliseconds_since_first_event: self.milliseconds_since_first_event(Utc::now()),
|
||||
milliseconds_since_first_event: self
|
||||
.milliseconds_since_first_event(self.clock.utc_now()),
|
||||
};
|
||||
|
||||
self.report_event(event)
|
||||
|
@ -349,7 +358,8 @@ impl Telemetry {
|
|||
conversation_id,
|
||||
kind,
|
||||
model,
|
||||
milliseconds_since_first_event: self.milliseconds_since_first_event(Utc::now()),
|
||||
milliseconds_since_first_event: self
|
||||
.milliseconds_since_first_event(self.clock.utc_now()),
|
||||
};
|
||||
|
||||
self.report_event(event)
|
||||
|
@ -365,7 +375,8 @@ impl Telemetry {
|
|||
operation,
|
||||
room_id,
|
||||
channel_id,
|
||||
milliseconds_since_first_event: self.milliseconds_since_first_event(Utc::now()),
|
||||
milliseconds_since_first_event: self
|
||||
.milliseconds_since_first_event(self.clock.utc_now()),
|
||||
};
|
||||
|
||||
self.report_event(event)
|
||||
|
@ -375,7 +386,8 @@ impl Telemetry {
|
|||
let event = Event::Cpu {
|
||||
usage_as_percentage,
|
||||
core_count,
|
||||
milliseconds_since_first_event: self.milliseconds_since_first_event(Utc::now()),
|
||||
milliseconds_since_first_event: self
|
||||
.milliseconds_since_first_event(self.clock.utc_now()),
|
||||
};
|
||||
|
||||
self.report_event(event)
|
||||
|
@ -389,24 +401,18 @@ impl Telemetry {
|
|||
let event = Event::Memory {
|
||||
memory_in_bytes,
|
||||
virtual_memory_in_bytes,
|
||||
milliseconds_since_first_event: self.milliseconds_since_first_event(Utc::now()),
|
||||
milliseconds_since_first_event: self
|
||||
.milliseconds_since_first_event(self.clock.utc_now()),
|
||||
};
|
||||
|
||||
self.report_event(event)
|
||||
}
|
||||
|
||||
pub fn report_app_event(self: &Arc<Self>, operation: String) {
|
||||
self.report_app_event_with_date_time(operation, Utc::now());
|
||||
}
|
||||
|
||||
fn report_app_event_with_date_time(
|
||||
self: &Arc<Self>,
|
||||
operation: String,
|
||||
date_time: DateTime<Utc>,
|
||||
) -> Event {
|
||||
pub fn report_app_event(self: &Arc<Self>, operation: String) -> Event {
|
||||
let event = Event::App {
|
||||
operation,
|
||||
milliseconds_since_first_event: self.milliseconds_since_first_event(date_time),
|
||||
milliseconds_since_first_event: self
|
||||
.milliseconds_since_first_event(self.clock.utc_now()),
|
||||
};
|
||||
|
||||
self.report_event(event.clone());
|
||||
|
@ -418,7 +424,8 @@ impl Telemetry {
|
|||
let event = Event::Setting {
|
||||
setting,
|
||||
value,
|
||||
milliseconds_since_first_event: self.milliseconds_since_first_event(Utc::now()),
|
||||
milliseconds_since_first_event: self
|
||||
.milliseconds_since_first_event(self.clock.utc_now()),
|
||||
};
|
||||
|
||||
self.report_event(event)
|
||||
|
@ -433,7 +440,8 @@ impl Telemetry {
|
|||
let event = Event::Edit {
|
||||
duration: end.timestamp_millis() - start.timestamp_millis(),
|
||||
environment,
|
||||
milliseconds_since_first_event: self.milliseconds_since_first_event(Utc::now()),
|
||||
milliseconds_since_first_event: self
|
||||
.milliseconds_since_first_event(self.clock.utc_now()),
|
||||
};
|
||||
|
||||
self.report_event(event);
|
||||
|
@ -444,7 +452,8 @@ impl Telemetry {
|
|||
let event = Event::Action {
|
||||
source,
|
||||
action,
|
||||
milliseconds_since_first_event: self.milliseconds_since_first_event(Utc::now()),
|
||||
milliseconds_since_first_event: self
|
||||
.milliseconds_since_first_event(self.clock.utc_now()),
|
||||
};
|
||||
|
||||
self.report_event(event)
|
||||
|
@ -590,29 +599,32 @@ impl Telemetry {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use chrono::TimeZone;
|
||||
use clock::FakeSystemClock;
|
||||
use gpui::TestAppContext;
|
||||
use util::http::FakeHttpClient;
|
||||
|
||||
#[gpui::test]
|
||||
fn test_telemetry_flush_on_max_queue_size(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
let clock = Arc::new(FakeSystemClock::new(
|
||||
Utc.with_ymd_and_hms(1990, 4, 12, 12, 0, 0).unwrap(),
|
||||
));
|
||||
let http = FakeHttpClient::with_200_response();
|
||||
let installation_id = Some("installation_id".to_string());
|
||||
let session_id = "session_id".to_string();
|
||||
|
||||
cx.update(|cx| {
|
||||
let telemetry = Telemetry::new(http, cx);
|
||||
let telemetry = Telemetry::new(clock.clone(), http, cx);
|
||||
|
||||
telemetry.state.lock().max_queue_size = 4;
|
||||
telemetry.start(installation_id, session_id, cx);
|
||||
|
||||
assert!(is_empty_state(&telemetry));
|
||||
|
||||
let first_date_time = Utc.with_ymd_and_hms(1990, 4, 12, 12, 0, 0).unwrap();
|
||||
let first_date_time = clock.utc_now();
|
||||
let operation = "test".to_string();
|
||||
|
||||
let event =
|
||||
telemetry.report_app_event_with_date_time(operation.clone(), first_date_time);
|
||||
let event = telemetry.report_app_event(operation.clone());
|
||||
assert_eq!(
|
||||
event,
|
||||
Event::App {
|
||||
|
@ -627,9 +639,9 @@ mod tests {
|
|||
Some(first_date_time)
|
||||
);
|
||||
|
||||
let mut date_time = first_date_time + chrono::Duration::milliseconds(100);
|
||||
clock.advance(chrono::Duration::milliseconds(100));
|
||||
|
||||
let event = telemetry.report_app_event_with_date_time(operation.clone(), date_time);
|
||||
let event = telemetry.report_app_event(operation.clone());
|
||||
assert_eq!(
|
||||
event,
|
||||
Event::App {
|
||||
|
@ -644,9 +656,9 @@ mod tests {
|
|||
Some(first_date_time)
|
||||
);
|
||||
|
||||
date_time += chrono::Duration::milliseconds(100);
|
||||
clock.advance(chrono::Duration::milliseconds(100));
|
||||
|
||||
let event = telemetry.report_app_event_with_date_time(operation.clone(), date_time);
|
||||
let event = telemetry.report_app_event(operation.clone());
|
||||
assert_eq!(
|
||||
event,
|
||||
Event::App {
|
||||
|
@ -661,10 +673,10 @@ mod tests {
|
|||
Some(first_date_time)
|
||||
);
|
||||
|
||||
date_time += chrono::Duration::milliseconds(100);
|
||||
clock.advance(chrono::Duration::milliseconds(100));
|
||||
|
||||
// Adding a 4th event should cause a flush
|
||||
let event = telemetry.report_app_event_with_date_time(operation.clone(), date_time);
|
||||
let event = telemetry.report_app_event(operation.clone());
|
||||
assert_eq!(
|
||||
event,
|
||||
Event::App {
|
||||
|
@ -680,22 +692,24 @@ mod tests {
|
|||
#[gpui::test]
|
||||
async fn test_connection_timeout(executor: BackgroundExecutor, cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
let clock = Arc::new(FakeSystemClock::new(
|
||||
Utc.with_ymd_and_hms(1990, 4, 12, 12, 0, 0).unwrap(),
|
||||
));
|
||||
let http = FakeHttpClient::with_200_response();
|
||||
let installation_id = Some("installation_id".to_string());
|
||||
let session_id = "session_id".to_string();
|
||||
|
||||
cx.update(|cx| {
|
||||
let telemetry = Telemetry::new(http, cx);
|
||||
let telemetry = Telemetry::new(clock.clone(), http, cx);
|
||||
telemetry.state.lock().max_queue_size = 4;
|
||||
telemetry.start(installation_id, session_id, cx);
|
||||
|
||||
assert!(is_empty_state(&telemetry));
|
||||
|
||||
let first_date_time = Utc.with_ymd_and_hms(1990, 4, 12, 12, 0, 0).unwrap();
|
||||
let first_date_time = clock.utc_now();
|
||||
let operation = "test".to_string();
|
||||
|
||||
let event =
|
||||
telemetry.report_app_event_with_date_time(operation.clone(), first_date_time);
|
||||
let event = telemetry.report_app_event(operation.clone());
|
||||
assert_eq!(
|
||||
event,
|
||||
Event::App {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue