Skip to content

Commit bec79a4

Browse files
authored
fix: update current_boot_patch to always return currently running patch (#202)
* fix: don't return true from isNewPatchAvailableForDownload if the new patch will not be installed * fix: update current_boot_patch to always return currently running patch * add C api tests * add extra test check
1 parent 7c559c0 commit bec79a4

File tree

3 files changed

+129
-15
lines changed

3 files changed

+129
-15
lines changed

library/src/c_api/mod.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,73 @@ mod test {
503503
assert_eq!(new, expected_new);
504504
}
505505

506+
#[serial]
507+
#[test]
508+
fn current_boot_patch_set_after_reporting_launch_start() {
509+
testing_reset_config();
510+
let tmp_dir = TempDir::new("example").unwrap();
511+
512+
// Generated by `string_patch "hello world" "hello tests"`
513+
let base = "hello world";
514+
let apk_path = tmp_dir.path().join("base.apk");
515+
write_fake_apk(apk_path.to_str().unwrap(), base.as_bytes());
516+
let fake_libapp_path = tmp_dir.path().join("lib/arch/ignored.so");
517+
let c_params = parameters(&tmp_dir, fake_libapp_path.to_str().unwrap());
518+
// app_id is required or shorebird_init will fail.
519+
let c_yaml = c_string("app_id: foo");
520+
assert!(shorebird_init(&c_params, FileCallbacks::new(), c_yaml));
521+
free_c_string(c_yaml);
522+
free_parameters(c_params);
523+
524+
// set up the network hooks to return a patch.
525+
testing_set_network_hooks(
526+
|_url, _request| {
527+
// Generated by `string_patch "hello world" "hello tests"`
528+
let hash = "bb8f1d041a5cdc259055afe9617136799543e0a7a86f86db82f8c1fadbd8cc45";
529+
Ok(PatchCheckResponse {
530+
patch_available: true,
531+
patch: Some(crate::Patch {
532+
number: 1,
533+
hash: hash.to_owned(),
534+
download_url: "ignored".to_owned(),
535+
hash_signature: None,
536+
}),
537+
rolled_back_patch_numbers: None,
538+
})
539+
},
540+
|_url| {
541+
// Generated by `string_patch "hello world" "hello tests"`
542+
let patch_bytes: Vec<u8> = vec![
543+
40, 181, 47, 253, 0, 128, 177, 0, 0, 223, 177, 0, 0, 0, 16, 0, 0, 6, 0, 0, 0,
544+
0, 0, 0, 5, 116, 101, 115, 116, 115, 0,
545+
];
546+
Ok(patch_bytes)
547+
},
548+
|_url, _event| Ok(()),
549+
);
550+
551+
// Ensure we start with no current patch
552+
assert_eq!(shorebird_current_boot_patch_number(), 0);
553+
554+
// There is an update available.
555+
assert!(shorebird_check_for_update());
556+
// Go ahead and do the update.
557+
shorebird_update();
558+
559+
// Ensure we have not yet updated the current patch.
560+
assert_eq!(shorebird_current_boot_patch_number(), 0);
561+
562+
shorebird_report_launch_start();
563+
564+
// After reporting a launch start, the next boot patch should be the current patch.
565+
assert_eq!(shorebird_current_boot_patch_number(), 1);
566+
567+
shorebird_report_launch_success();
568+
569+
// After reporting a launch success, the current patch number should not have changed.
570+
assert_eq!(shorebird_current_boot_patch_number(), 1);
571+
}
572+
506573
#[serial]
507574
#[test]
508575
fn forgot_init() {

library/src/cache/updater_state.rs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,14 +171,22 @@ impl UpdaterState {
171171
self.patch_manager.currently_booting_patch()
172172
}
173173

174-
/// This is the current patch that is running.
174+
/// The last patch that was successfully booted (e.g., for which we record_boot_success was
175+
/// called).
175176
/// Will be None if:
176177
/// - There was no good patch at time of boot.
177178
/// - The updater has been initialized but no boot recorded yet.
178-
pub fn current_boot_patch(&self) -> Option<PatchInfo> {
179+
pub fn last_successfully_booted_patch(&self) -> Option<PatchInfo> {
179180
self.patch_manager.last_successfully_booted_patch()
180181
}
181182

183+
/// This is the current patch that is running.
184+
pub fn current_boot_patch(&self) -> Option<PatchInfo> {
185+
self.patch_manager
186+
.currently_booting_patch()
187+
.or(self.patch_manager.last_successfully_booted_patch())
188+
}
189+
182190
/// This is the patch that will be used for the next boot.
183191
/// Will be None if:
184192
/// - There has never been a patch selected.
@@ -346,14 +354,45 @@ mod tests {
346354
}
347355

348356
#[test]
349-
fn current_boot_patch_forwards_from_patch_manager() {
357+
fn last_successfully_booted_patch_forwards_from_patch_manager() {
350358
let tmp_dir = TempDir::new("example").unwrap();
351359
let patch = fake_patch(&tmp_dir, 1);
352360
let mut mock_manage_patches = MockManagePatches::new();
353361
mock_manage_patches
354362
.expect_last_successfully_booted_patch()
355363
.return_const(Some(patch.clone()));
356364
let state = test_state(&tmp_dir, mock_manage_patches);
365+
assert_eq!(state.last_successfully_booted_patch(), Some(patch));
366+
}
367+
368+
#[test]
369+
fn current_boot_patch_returns_currently_booting_patch_if_present() {
370+
let tmp_dir = TempDir::new("example").unwrap();
371+
let patch1 = fake_patch(&tmp_dir, 1);
372+
let patch2 = fake_patch(&tmp_dir, 2);
373+
let mut mock_manage_patches = MockManagePatches::new();
374+
mock_manage_patches
375+
.expect_last_successfully_booted_patch()
376+
.return_const(Some(patch1.clone()));
377+
mock_manage_patches
378+
.expect_currently_booting_patch()
379+
.return_const(Some(patch2.clone()));
380+
let state = test_state(&tmp_dir, mock_manage_patches);
381+
assert_eq!(state.current_boot_patch(), Some(patch2));
382+
}
383+
384+
#[test]
385+
fn current_boot_patch_returns_last_successfully_booted_patch_if_no_patch_is_booting() {
386+
let tmp_dir = TempDir::new("example").unwrap();
387+
let patch = fake_patch(&tmp_dir, 1);
388+
let mut mock_manage_patches = MockManagePatches::new();
389+
mock_manage_patches
390+
.expect_last_successfully_booted_patch()
391+
.return_const(Some(patch.clone()));
392+
mock_manage_patches
393+
.expect_currently_booting_patch()
394+
.return_const(None);
395+
let state = test_state(&tmp_dir, mock_manage_patches);
357396
assert_eq!(state.current_boot_patch(), Some(patch));
358397
}
359398

library/src/updater.rs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -521,11 +521,6 @@ pub fn next_boot_patch() -> anyhow::Result<Option<PatchInfo>> {
521521
/// The patch that was last successfully booted. If we're booting a patch for the first time, this
522522
/// will be the previous patch (or None, if there was no previous patch) until the boot is
523523
/// reported as successful.
524-
///
525-
/// TODO: This should always return the currently running patch, even if it has not been marked as
526-
/// good or bad. Presently, users of the shorebird_code_push package will never get the wrong
527-
/// patch number from this function because a launch will have been reported to be either a
528-
/// success or a failure before they can call this function.
529524
pub fn current_boot_patch() -> anyhow::Result<Option<PatchInfo>> {
530525
with_state(|state| Ok(state.current_boot_patch()))
531526
}
@@ -591,13 +586,17 @@ pub fn report_launch_success() -> anyhow::Result<()> {
591586
None => return Ok(()),
592587
};
593588

594-
let maybe_previous_boot_patch = state.current_boot_patch();
589+
// Get the last successfully booted patch before we record the boot success.
590+
let maybe_previous_boot_patch = state.last_successfully_booted_patch();
595591

596592
state.record_boot_success()?;
597593

598-
if let (Some(previous_boot_patch), Some(current_boot_patch)) =
599-
(maybe_previous_boot_patch, state.current_boot_patch())
600-
{
594+
// Check whether last_successfully_booted_patch has changed. If so, we should report a
595+
// PatchInstallSuccess event.
596+
if let (Some(previous_boot_patch), Some(current_boot_patch)) = (
597+
maybe_previous_boot_patch,
598+
state.last_successfully_booted_patch(),
599+
) {
601600
// If we had previously booted from a patch and it has the same number as the
602601
// patch we just booted from, then we shouldn't report a patch install.
603602
if previous_boot_patch.number == current_boot_patch.number {
@@ -1050,7 +1049,10 @@ mod tests {
10501049
&config.release_version,
10511050
config.patch_public_key.as_deref(),
10521051
);
1053-
assert_eq!(state.current_boot_patch().unwrap().number, patch_number);
1052+
assert_eq!(
1053+
state.last_successfully_booted_patch().unwrap().number,
1054+
patch_number
1055+
);
10541056
Ok(())
10551057
})
10561058
.unwrap();
@@ -1331,7 +1333,10 @@ mod rollback_tests {
13311333
report_launch_success()?;
13321334

13331335
with_mut_state(|state| {
1334-
assert_eq!(state.current_boot_patch().map(|p| p.number), Some(1));
1336+
assert_eq!(
1337+
state.last_successfully_booted_patch().map(|p| p.number),
1338+
Some(1)
1339+
);
13351340
assert_eq!(state.next_boot_patch().map(|p| p.number), Some(1));
13361341
Ok(())
13371342
})?;
@@ -1432,7 +1437,10 @@ mod rollback_tests {
14321437
report_launch_success()?;
14331438

14341439
with_mut_state(|state| {
1435-
assert_eq!(state.current_boot_patch().map(|p| p.number), Some(2));
1440+
assert_eq!(
1441+
state.last_successfully_booted_patch().map(|p| p.number),
1442+
Some(2)
1443+
);
14361444
assert_eq!(state.next_boot_patch().map(|p| p.number), Some(2));
14371445
Ok(())
14381446
})?;

0 commit comments

Comments
 (0)