Skip to content

Commit ab95ed9

Browse files
committed
TEMP
1 parent 1c3fbba commit ab95ed9

File tree

5 files changed

+134
-21
lines changed

5 files changed

+134
-21
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/auto_update/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ workspace.workspace = true
3333
which.workspace = true
3434

3535
[dev-dependencies]
36+
clock= { workspace = true, "features" = ["test-support"] }
3637
gpui = { workspace = true, "features" = ["test-support"] }

crates/auto_update/src/auto_update.rs

Lines changed: 125 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use anyhow::{Context as _, Result};
22
use client::Client;
3-
use db::RELEASE_CHANNEL;
43
use db::kvp::KEY_VALUE_STORE;
54
use gpui::{
65
App, AppContext as _, AsyncApp, BackgroundExecutor, Context, Entity, Global, SemanticVersion,
@@ -57,7 +56,7 @@ pub struct AssetQuery<'a> {
5756
is_staff: Option<bool>,
5857
}
5958

60-
#[derive(Clone)]
59+
#[derive(Clone, Debug)]
6160
pub enum AutoUpdateStatus {
6261
Idle,
6362
Checking,
@@ -67,6 +66,29 @@ pub enum AutoUpdateStatus {
6766
Errored { error: Arc<anyhow::Error> },
6867
}
6968

69+
impl PartialEq for AutoUpdateStatus {
70+
fn eq(&self, other: &Self) -> bool {
71+
match (self, other) {
72+
(AutoUpdateStatus::Idle, AutoUpdateStatus::Idle) => true,
73+
(AutoUpdateStatus::Checking, AutoUpdateStatus::Checking) => true,
74+
(
75+
AutoUpdateStatus::Downloading { version: v1 },
76+
AutoUpdateStatus::Downloading { version: v2 },
77+
) => v1 == v2,
78+
(
79+
AutoUpdateStatus::Installing { version: v1 },
80+
AutoUpdateStatus::Installing { version: v2 },
81+
) => v1 == v2,
82+
(
83+
AutoUpdateStatus::Updated { version: v1 },
84+
AutoUpdateStatus::Updated { version: v2 },
85+
) => v1 == v2,
86+
(AutoUpdateStatus::Errored { .. }, AutoUpdateStatus::Errored { .. }) => true, // Compare errors by existence, not content
87+
_ => false,
88+
}
89+
}
90+
}
91+
7092
impl AutoUpdateStatus {
7193
pub fn is_updated(&self) -> bool {
7294
matches!(self, Self::Updated { .. })
@@ -76,12 +98,12 @@ impl AutoUpdateStatus {
7698
pub struct AutoUpdater {
7799
status: AutoUpdateStatus,
78100
current_version: SemanticVersion,
79-
http_client: Arc<HttpClientWithUrl>,
101+
client: Arc<Client>,
80102
pending_poll: Option<Task<Option<()>>>,
81103
quit_subscription: Option<gpui::Subscription>,
82104
}
83105

84-
#[derive(Deserialize, Clone, Debug)]
106+
#[derive(Deserialize, Serialize, Clone, Debug)]
85107
pub struct ReleaseAsset {
86108
pub version: String,
87109
pub url: String,
@@ -138,7 +160,7 @@ struct GlobalAutoUpdate(Option<Entity<AutoUpdater>>);
138160

139161
impl Global for GlobalAutoUpdate {}
140162

141-
pub fn init(http_client: Arc<HttpClientWithUrl>, cx: &mut App) {
163+
pub fn init(client: Arc<Client>, cx: &mut App) {
142164
AutoUpdateSetting::register(cx);
143165

144166
cx.observe_new(|workspace: &mut Workspace, _window, _cx| {
@@ -152,7 +174,7 @@ pub fn init(http_client: Arc<HttpClientWithUrl>, cx: &mut App) {
152174

153175
let version = release_channel::AppVersion::global(cx);
154176
let auto_updater = cx.new(|cx| {
155-
let updater = AutoUpdater::new(version, http_client, cx);
177+
let updater = AutoUpdater::new(version, client, cx);
156178

157179
let poll_for_updates = ReleaseChannel::try_global(cx)
158180
.map(|channel| channel.poll_for_updates())
@@ -236,7 +258,7 @@ pub fn view_release_notes(_: &ViewReleaseNotes, cx: &mut App) -> Option<()> {
236258
let current_version = auto_updater.current_version;
237259
let release_channel = release_channel.dev_name();
238260
let path = format!("/releases/{release_channel}/{current_version}");
239-
let url = &auto_updater.http_client.build_url(&path);
261+
let url = &auto_updater.client.http_client().build_url(&path);
240262
cx.open_url(url);
241263
}
242264
ReleaseChannel::Nightly => {
@@ -299,11 +321,7 @@ impl AutoUpdater {
299321
cx.default_global::<GlobalAutoUpdate>().0.clone()
300322
}
301323

302-
fn new(
303-
current_version: SemanticVersion,
304-
http_client: Arc<HttpClientWithUrl>,
305-
cx: &mut Context<Self>,
306-
) -> Self {
324+
fn new(current_version: SemanticVersion, client: Arc<Client>, cx: &mut Context<Self>) -> Self {
307325
// On windows, executable files cannot be overwritten while they are
308326
// running, so we must wait to overwrite the application until quitting
309327
// or restarting. When quitting the app, we spawn the auto update helper
@@ -324,13 +342,14 @@ impl AutoUpdater {
324342
Self {
325343
status: AutoUpdateStatus::Idle,
326344
current_version,
327-
http_client,
345+
client,
328346
pending_poll: None,
329347
quit_subscription,
330348
}
331349
}
332350

333351
pub fn start_polling(&self, cx: &mut Context<Self>) -> Task<Result<()>> {
352+
dbg!("start polling");
334353
cx.spawn(async move |this, cx| {
335354
#[cfg(target_os = "windows")]
336355
{
@@ -351,6 +370,7 @@ impl AutoUpdater {
351370

352371
pub fn poll(&mut self, check_type: UpdateCheckType, cx: &mut Context<Self>) {
353372
if self.pending_poll.is_some() {
373+
dbg!("return");
354374
return;
355375
}
356376

@@ -435,7 +455,7 @@ impl AutoUpdater {
435455
let version_path = platform_dir.join(format!("{}.gz", release.version));
436456
smol::fs::create_dir_all(&platform_dir).await.ok();
437457

438-
let client = this.read_with(cx, |this, _| this.http_client.clone())?;
458+
let client = this.read_with(cx, |this, _| this.client.http_client())?;
439459

440460
if smol::fs::metadata(&version_path).await.is_err() {
441461
log::info!(
@@ -479,10 +499,10 @@ impl AutoUpdater {
479499
arch: &str,
480500
cx: &mut AsyncApp,
481501
) -> Result<ReleaseAsset> {
482-
let client = this.read_with(cx, |this, _| this.http_client.clone())?;
502+
let client = this.read_with(cx, |this, _| this.client.clone())?;
483503

484504
let (system_id, metrics_id, is_staff) = cx.update(|cx| {
485-
let telemetry = Client::global(cx).telemetry().clone();
505+
let telemetry = client.telemetry().clone();
486506
if telemetry.metrics_enabled() {
487507
(
488508
telemetry.system_id(),
@@ -499,9 +519,10 @@ impl AutoUpdater {
499519
} else {
500520
"latest".to_string()
501521
};
522+
let http_client = client.http_client();
502523

503524
let path = format!("/releases/{}/{}/asset", release_channel.dev_name(), version,);
504-
let url = client.build_zed_cloud_url_with_query(
525+
let url = http_client.build_zed_cloud_url_with_query(
505526
&path,
506527
AssetQuery {
507528
os,
@@ -513,7 +534,9 @@ impl AutoUpdater {
513534
},
514535
)?;
515536

516-
let mut response = client.get(url.as_str(), Default::default(), true).await?;
537+
let mut response = http_client
538+
.get(url.as_str(), Default::default(), true)
539+
.await?;
517540
let mut body = Vec::new();
518541
response.body_mut().read_to_end(&mut body).await?;
519542

@@ -535,7 +558,7 @@ impl AutoUpdater {
535558
let (client, installed_version, previous_status, release_channel) =
536559
this.read_with(cx, |this, cx| {
537560
(
538-
this.http_client.clone(),
561+
this.client.http_client(),
539562
this.current_version,
540563
this.status.clone(),
541564
ReleaseChannel::try_global(cx).unwrap_or(ReleaseChannel::Stable),
@@ -555,7 +578,7 @@ impl AutoUpdater {
555578
let fetched_version = fetched_release_data.clone().version;
556579
let app_commit_sha = cx.update(|cx| AppCommitSha::try_global(cx).map(|sha| sha.full()));
557580
let newer_version = Self::check_if_fetched_version_is_newer(
558-
*RELEASE_CHANNEL,
581+
release_channel,
559582
app_commit_sha,
560583
installed_version,
561584
fetched_version,
@@ -955,8 +978,12 @@ pub async fn finalize_auto_update_on_quit() {
955978

956979
#[cfg(test)]
957980
mod tests {
981+
use client::Client;
982+
use clock::FakeSystemClock;
958983
use gpui::TestAppContext;
984+
use http_client::FakeHttpClient;
959985
use settings::default_settings;
986+
use std::sync::Arc;
960987

961988
use super::*;
962989

@@ -976,6 +1003,84 @@ mod tests {
9761003
});
9771004
}
9781005

1006+
#[gpui::test]
1007+
async fn test_auto_update_end_to_end(cx: &mut TestAppContext) {
1008+
cx.update(|cx| {
1009+
settings::init(cx);
1010+
1011+
let current_version = SemanticVersion::new(1, 0, 0);
1012+
release_channel::init_test(current_version, ReleaseChannel::Stable, cx);
1013+
1014+
client::init_settings(cx);
1015+
let clock = Arc::new(FakeSystemClock::new());
1016+
let fake_client_http = FakeHttpClient::with_404_response();
1017+
let client = Client::new(clock, fake_client_http, cx);
1018+
crate::init(client, cx);
1019+
});
1020+
1021+
let auto_updater = cx.update(|cx| AutoUpdater::get(cx).expect("auto updater should exist"));
1022+
1023+
cx.background_executor.run_until_parked();
1024+
1025+
// Verify initial state
1026+
auto_updater.read_with(cx, |updater, _| {
1027+
assert_eq!(updater.status(), AutoUpdateStatus::Idle);
1028+
assert_eq!(updater.current_version(), SemanticVersion::new(1, 0, 0));
1029+
});
1030+
1031+
// Trigger manual update check
1032+
auto_updater.update(cx, |updater, cx| {
1033+
updater.poll(UpdateCheckType::Manual, cx);
1034+
});
1035+
1036+
// Let the initial state change propagate
1037+
1038+
// Verify it transitions to Checking state
1039+
let status = auto_updater.read_with(cx, |updater, _| updater.status());
1040+
1041+
assert_eq!(status, AutoUpdateStatus::Checking);
1042+
1043+
// Let the async update process continue
1044+
cx.background_executor.run_until_parked();
1045+
1046+
// The update should progress through states and eventually either:
1047+
// - Reach AutoUpdateStatus::Updated if mocking is complete
1048+
// - Reach AutoUpdateStatus::Errored when download/install fails (expected in test)
1049+
let final_status = auto_updater.read_with(cx, |updater, _| updater.status());
1050+
1051+
match final_status {
1052+
AutoUpdateStatus::Updated { version } => {
1053+
// If somehow the update completed successfully
1054+
match version {
1055+
VersionCheckType::Semantic(v) => {
1056+
assert_eq!(v, SemanticVersion::new(1, 0, 1));
1057+
}
1058+
_ => panic!("Expected semantic version for stable release"),
1059+
}
1060+
}
1061+
AutoUpdateStatus::Errored { .. } => {
1062+
// This is expected because we can't actually download/install in tests
1063+
// The important thing is that it attempted the update process
1064+
// and went through the checking phase successfully
1065+
}
1066+
AutoUpdateStatus::Downloading { version } => {
1067+
// The update got stuck in downloading state due to our 404 mock
1068+
match version {
1069+
VersionCheckType::Semantic(v) => {
1070+
assert_eq!(v, SemanticVersion::new(1, 0, 1));
1071+
}
1072+
_ => panic!("Expected semantic version for stable release"),
1073+
}
1074+
}
1075+
other => {
1076+
panic!(
1077+
"Expected Updated, Errored, or Downloading state after update attempt, got: {:?}",
1078+
other
1079+
);
1080+
}
1081+
}
1082+
}
1083+
9791084
#[test]
9801085
fn test_stable_does_not_update_when_fetched_version_is_not_higher() {
9811086
let release_channel = ReleaseChannel::Stable;

crates/release_channel/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ pub fn init(app_version: SemanticVersion, cx: &mut App) {
126126
cx.set_global(GlobalReleaseChannel(*RELEASE_CHANNEL))
127127
}
128128

129+
/// Initializes the release channel for tests that rely on fake release channel.
130+
pub fn init_test(app_version: SemanticVersion, release_channel: ReleaseChannel, cx: &mut App) {
131+
cx.set_global(GlobalAppVersion(app_version));
132+
cx.set_global(GlobalReleaseChannel(release_channel))
133+
}
134+
129135
impl ReleaseChannel {
130136
/// Returns the global [`ReleaseChannel`].
131137
pub fn global(cx: &App) -> Self {

crates/zed/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ pub fn main() {
538538
});
539539
AppState::set_global(Arc::downgrade(&app_state), cx);
540540

541-
auto_update::init(client.http_client(), cx);
541+
auto_update::init(client, cx);
542542
dap_adapters::init(cx);
543543
auto_update_ui::init(cx);
544544
reliability::init(

0 commit comments

Comments
 (0)