tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_BackupService_scheduler.js (11079B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 https://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const SCHEDULED_BACKUPS_ENABLED_PREF_NAME = "browser.backup.scheduled.enabled";
      7 const IDLE_THRESHOLD_SECONDS_PREF_NAME =
      8  "browser.backup.scheduled.idle-threshold-seconds";
      9 const LAST_BACKUP_TIMESTAMP_PREF_NAME =
     10  "browser.backup.scheduled.last-backup-timestamp";
     11 const MINIMUM_TIME_BETWEEN_BACKUPS_SECONDS_PREF_NAME =
     12  "browser.backup.scheduled.minimum-time-between-backups-seconds";
     13 
     14 /**
     15 * This is a very thin nsIUserIdleService implementation that doesn't do much,
     16 * but with sinon we can stub out some parts of it to make sure that the
     17 * BackupService uses it in the way we expect.
     18 */
     19 let idleService = {
     20  QueryInterface: ChromeUtils.generateQI(["nsIUserIdleService"]),
     21  idleTime: 19999,
     22  disabled: true,
     23  addIdleObserver() {},
     24  removeIdleObserver() {},
     25 };
     26 
     27 add_setup(() => {
     28  let fakeIdleServiceCID = MockRegistrar.register(
     29    "@mozilla.org/widget/useridleservice;1",
     30    idleService
     31  );
     32 
     33  Services.prefs.setBoolPref(SCHEDULED_BACKUPS_ENABLED_PREF_NAME, true);
     34 
     35  // We'll pretend that our threshold between backups is 20 seconds.
     36  Services.prefs.setIntPref(MINIMUM_TIME_BETWEEN_BACKUPS_SECONDS_PREF_NAME, 20);
     37 
     38  registerCleanupFunction(() => {
     39    MockRegistrar.unregister(fakeIdleServiceCID);
     40    Services.prefs.clearUserPref(SCHEDULED_BACKUPS_ENABLED_PREF_NAME);
     41    Services.prefs.clearUserPref(
     42      MINIMUM_TIME_BETWEEN_BACKUPS_SECONDS_PREF_NAME
     43    );
     44  });
     45 
     46  // Set the startup time to zero so we only need to worry about it in its
     47  // test. (Approximately, make sure Firefox starts 'long before' each test
     48  // runs.)
     49  sinon.stub(BackupService.prototype, "_startupTimeUnixSeconds").get(() => 0);
     50 });
     51 
     52 /**
     53 * Tests that calling initBackupScheduler registers a callback with the
     54 * nsIUserIdleService.
     55 */
     56 add_task(async function test_init_uninitBackupScheduler() {
     57  let bs = new BackupService();
     58  let sandbox = sinon.createSandbox();
     59  sandbox.stub(idleService, "addIdleObserver");
     60  sandbox.stub(idleService, "removeIdleObserver");
     61 
     62  bs.initBackupScheduler();
     63  Assert.ok(
     64    idleService.addIdleObserver.calledOnce,
     65    "addIdleObserver was called"
     66  );
     67  Assert.ok(
     68    idleService.addIdleObserver.firstCall.args[0] instanceof Ci.nsIObserver,
     69    "The first argument to addIdleObserver was an nsIObserver"
     70  );
     71  const THRESHOLD_SECONDS = Services.prefs.getIntPref(
     72    IDLE_THRESHOLD_SECONDS_PREF_NAME
     73  );
     74  Assert.equal(
     75    idleService.addIdleObserver.firstCall.args[1],
     76    THRESHOLD_SECONDS,
     77    "The idle threshold preference value was passed as the second argument."
     78  );
     79  Assert.ok(
     80    idleService.removeIdleObserver.notCalled,
     81    "removeIdleObserver has not been called yet."
     82  );
     83 
     84  // Hold a reference to what addIdleObserver was called with as its first
     85  // argument, so we can compare it against what's passed to removeIdleObserver.
     86  let addObserverArg = idleService.addIdleObserver.firstCall.args[0];
     87 
     88  // We want to make sure that uninitBackupScheduler doesn't call this again,
     89  // so reset its call history.
     90  idleService.addIdleObserver.resetHistory();
     91 
     92  // Now, let's pretend that the preference for the idle threshold changed
     93  // before we could uninit the backup scheduler. We should ensure that this
     94  // change is _not_ reflected whenever deregistration of the idle callback
     95  // occurs, since it wouldn't match the registration arguments.
     96  Services.prefs.setIntPref(
     97    IDLE_THRESHOLD_SECONDS_PREF_NAME,
     98    THRESHOLD_SECONDS + 5
     99  );
    100 
    101  bs.uninitBackupScheduler();
    102  Assert.ok(
    103    idleService.addIdleObserver.notCalled,
    104    "addIdleObserver was not called again."
    105  );
    106  Assert.ok(
    107    idleService.removeIdleObserver.calledOnce,
    108    "removeIdleObserver was called once."
    109  );
    110  Assert.ok(
    111    idleService.removeIdleObserver.firstCall.args[0] instanceof Ci.nsIObserver,
    112    "The first argument to addIdleObserver was an nsIObserver"
    113  );
    114  Assert.equal(
    115    idleService.removeIdleObserver.firstCall.args[0],
    116    addObserverArg,
    117    "The first argument to addIdleObserver matches the first argument to removeIdleObserver"
    118  );
    119  Assert.equal(
    120    idleService.removeIdleObserver.firstCall.args[1],
    121    THRESHOLD_SECONDS,
    122    "The original idle threshold preference value was passed as the second argument."
    123  );
    124 
    125  sandbox.restore();
    126  Services.prefs.clearUserPref(IDLE_THRESHOLD_SECONDS_PREF_NAME);
    127 });
    128 
    129 /**
    130 * Tests that calling BackupService.onObserve with the "idle" notification
    131 * causes the BackupService.onIdle method to be called.
    132 */
    133 add_task(async function test_BackupService_onObserve_idle() {
    134  let bs = new BackupService();
    135  let sandbox = sinon.createSandbox();
    136  sandbox.stub(bs, "onIdle");
    137 
    138  // The subject for the idle notification is always the idle service itself.
    139  bs.onObserve(idleService, "idle");
    140  Assert.ok(bs.onIdle.calledOnce, "BackupService.onIdle was called.");
    141 
    142  sandbox.restore();
    143 });
    144 
    145 /**
    146 * Tests that calling BackupService.onObserve with the
    147 * "quit-application-granted" notification causes the
    148 * BackupService.uninitBackupScheduler method to be called.
    149 */
    150 add_task(
    151  async function test_BackupService_onObserve_quit_application_granted() {
    152    let bs = new BackupService();
    153    let sandbox = sinon.createSandbox();
    154    sandbox.stub(bs, "uninitBackupScheduler");
    155 
    156    // The subject for the quit-application-granted notification is null.
    157    bs.onObserve(null, "quit-application-granted");
    158    Assert.ok(
    159      bs.uninitBackupScheduler.calledOnce,
    160      "BackupService.uninitBackupScheduler was called."
    161    );
    162 
    163    sandbox.restore();
    164  }
    165 );
    166 
    167 /**
    168 * Tests that calling onIdle when a backup has never occurred causes a backup to
    169 * get scheduled.
    170 */
    171 add_task(async function test_BackupService_idle_no_backup_exists() {
    172  // Make sure no last backup timestamp is recorded.
    173  Services.prefs.clearUserPref(LAST_BACKUP_TIMESTAMP_PREF_NAME);
    174 
    175  let bs = new BackupService();
    176  let sandbox = sinon.createSandbox();
    177  sandbox.stub(bs, "createBackupOnIdleDispatch");
    178 
    179  bs.initBackupScheduler();
    180  Assert.equal(
    181    bs.state.lastBackupDate,
    182    null,
    183    "State should have null for lastBackupDate"
    184  );
    185 
    186  bs.onIdle();
    187  Assert.ok(
    188    bs.createBackupOnIdleDispatch.calledOnce,
    189    "BackupService.createBackupOnIdleDispatch was called."
    190  );
    191  Assert.equal(
    192    bs.createBackupOnIdleDispatch.firstCall.args[0].reason,
    193    "idle",
    194    "Recorded that the backup was caused by being idle."
    195  );
    196 
    197  sandbox.restore();
    198 });
    199 
    200 /**
    201 * Tests that calling onIdle when a backup has occurred recently does not cause
    202 * a backup to get scheduled.
    203 */
    204 add_task(async function test_BackupService_idle_not_expired_backup() {
    205  // Let's calculate a Date that's five seconds ago.
    206  let fiveSecondsAgo = Date.now() - 5000; /* 5 seconds in milliseconds */
    207  let lastBackupPrefValue = Math.floor(fiveSecondsAgo / 1000);
    208  Services.prefs.setIntPref(
    209    LAST_BACKUP_TIMESTAMP_PREF_NAME,
    210    lastBackupPrefValue
    211  );
    212 
    213  let bs = new BackupService();
    214  let sandbox = sinon.createSandbox();
    215  bs.initBackupScheduler();
    216  Assert.equal(
    217    bs.state.lastBackupDate,
    218    lastBackupPrefValue,
    219    "State should have cached lastBackupDate"
    220  );
    221 
    222  sandbox.stub(bs, "createBackupOnIdleDispatch");
    223 
    224  bs.onIdle();
    225  Assert.ok(
    226    bs.createBackupOnIdleDispatch.notCalled,
    227    "BackupService.createBackupOnIdleDispatch was not called."
    228  );
    229 
    230  sandbox.restore();
    231 });
    232 
    233 /**
    234 * Tests that calling onIdle when a backup has occurred, but after the threshold
    235 * does cause a backup to get scheduled
    236 */
    237 add_task(async function test_BackupService_idle_expired_backup() {
    238  // Let's calculate a Date that's twenty five seconds ago.
    239  let twentyFiveSecondsAgo =
    240    Date.now() - 25000; /* 25 seconds in milliseconds */
    241  let lastBackupPrefValue = Math.floor(twentyFiveSecondsAgo / 1000);
    242 
    243  Services.prefs.setIntPref(
    244    LAST_BACKUP_TIMESTAMP_PREF_NAME,
    245    lastBackupPrefValue
    246  );
    247 
    248  let bs = new BackupService();
    249  let sandbox = sinon.createSandbox();
    250  bs.initBackupScheduler();
    251  Assert.equal(
    252    bs.state.lastBackupDate,
    253    lastBackupPrefValue,
    254    "State should have cached lastBackupDate"
    255  );
    256 
    257  sandbox.stub(bs, "createBackupOnIdleDispatch");
    258 
    259  bs.onIdle();
    260  Assert.ok(
    261    bs.createBackupOnIdleDispatch.calledOnce,
    262    "BackupService.createBackupOnIdleDispatch was called."
    263  );
    264  Assert.equal(
    265    bs.createBackupOnIdleDispatch.firstCall.args[0].reason,
    266    "idle",
    267    "Recorded that the backup was caused by being idle."
    268  );
    269 
    270  sandbox.restore();
    271 });
    272 
    273 /**
    274 * Tests that calling onIdle when a backup occurred in the future somehow causes
    275 * a backup to get scheduled.
    276 */
    277 add_task(async function test_BackupService_idle_time_travel() {
    278  // Let's calculate a Date that's twenty-five seconds in the future.
    279  let twentyFiveSecondsFromNow =
    280    Date.now() + 25000; /* 25 seconds in milliseconds */
    281  let lastBackupPrefValue = Math.floor(twentyFiveSecondsFromNow / 1000);
    282 
    283  Services.prefs.setIntPref(
    284    LAST_BACKUP_TIMESTAMP_PREF_NAME,
    285    lastBackupPrefValue
    286  );
    287 
    288  let bs = new BackupService();
    289  let sandbox = sinon.createSandbox();
    290  bs.initBackupScheduler();
    291  Assert.equal(
    292    bs.state.lastBackupDate,
    293    lastBackupPrefValue,
    294    "State should have cached lastBackupDate"
    295  );
    296 
    297  sandbox.stub(bs, "createBackupOnIdleDispatch");
    298 
    299  bs.onIdle();
    300  Assert.ok(
    301    bs.createBackupOnIdleDispatch.calledOnce,
    302    "BackupService.createBackupOnIdleDispatch was called."
    303  );
    304  Assert.equal(
    305    bs.createBackupOnIdleDispatch.firstCall.args[0].reason,
    306    "idle",
    307    "Recorded that the backup was caused by being idle."
    308  );
    309  Assert.equal(
    310    bs.state.lastBackupDate,
    311    null,
    312    "Should have cleared the last backup date."
    313  );
    314 
    315  sandbox.restore();
    316 });
    317 
    318 /**
    319 * Tests that calling onIdle when a backup has occurred after the threshold
    320 * yet before Firefox started indicates to telemetry that the backup was
    321 * missed.
    322 */
    323 add_task(async function test_BackupService_idle_expired_backup() {
    324  // Let's calculate a Date that's twenty five seconds ago.
    325  let twentyFiveSecondsAgo = Date.now() - 25000;
    326  let lastBackupPrefValue = Math.floor(twentyFiveSecondsAgo / 1000);
    327 
    328  Services.prefs.setIntPref(
    329    LAST_BACKUP_TIMESTAMP_PREF_NAME,
    330    lastBackupPrefValue
    331  );
    332 
    333  let bs = new BackupService();
    334  let sandbox = sinon.createSandbox();
    335 
    336  // This needs to be greater than
    337  //   LAST_BACKUP_TIMESTAMP_PREF_NAME + MINIMUM_TIME_BETWEEN_BACKUPS_SECONDS_PREF_NAME
    338  // and less than the current time.
    339  let twentySecondsAgo = Math.floor(twentyFiveSecondsAgo + 21);
    340  sandbox.stub(bs, "_startupTimeUnixSeconds").get(() => twentySecondsAgo);
    341 
    342  bs.initBackupScheduler();
    343  Assert.equal(
    344    bs.state.lastBackupDate,
    345    lastBackupPrefValue,
    346    "State should have cached lastBackupDate"
    347  );
    348 
    349  sandbox.stub(bs, "createBackupOnIdleDispatch");
    350 
    351  bs.onIdle();
    352  Assert.ok(
    353    bs.createBackupOnIdleDispatch.calledOnce,
    354    "BackupService.createBackupOnIdleDispatch was called."
    355  );
    356  Assert.equal(
    357    bs.createBackupOnIdleDispatch.firstCall.args[0].reason,
    358    "missed",
    359    "Recorded that the backup was caused by missing the deadline."
    360  );
    361 
    362  sandbox.restore();
    363 });