summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/test/xpcshell/test_metadata_update.js
blob: a87b3f45b11e0b77eeedc59c3d5b3de794fbae26 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Test whether we need to block start-up to check add-on compatibility,
 * based on how long since the last succesful metadata ping.
 * All tests depend on having one add-on installed in the profile
 */


const URI_EXTENSION_UPDATE_DIALOG     = "chrome://mozapps/content/extensions/update.xul";
const PREF_EM_SHOW_MISMATCH_UI        = "extensions.showMismatchUI";

// Constants copied from AddonRepository.jsm
const PREF_METADATA_LASTUPDATE           = "extensions.getAddons.cache.lastUpdate";
const PREF_METADATA_UPDATETHRESHOLD_SEC  = "extensions.getAddons.cache.updateThreshold";
const DEFAULT_METADATA_UPDATETHRESHOLD_SEC = 172800;  // two days

// The test extension uses an insecure update url.
Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
// None of this works without the add-on repository cache
Services.prefs.setBoolPref("extensions.getAddons.cache.enabled", true);

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;

Cu.import("resource://testing-common/httpd.js");
var testserver;

const profileDir = gProfD.clone();
profileDir.append("extensions");

// This will be called to show the compatibility update dialog.
var WindowWatcher = {
  expected: false,
  arguments: null,

  openWindow: function(parent, url, name, features, args) {
    do_check_true(Services.startup.interrupted);
    do_check_eq(url, URI_EXTENSION_UPDATE_DIALOG);
    do_check_true(this.expected);
    this.expected = false;
  },

  QueryInterface: function(iid) {
    if (iid.equals(Ci.nsIWindowWatcher)
     || iid.equals(Ci.nsISupports))
      return this;

    throw Cr.NS_ERROR_NO_INTERFACE;
  }
}

var WindowWatcherFactory = {
  createInstance: function createInstance(outer, iid) {
    if (outer != null)
      throw Components.results.NS_ERROR_NO_AGGREGATION;
    return WindowWatcher.QueryInterface(iid);
  }
};

var registrar = Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
                          "Fake Window Watcher",
                          "@mozilla.org/embedcomp/window-watcher;1", WindowWatcherFactory);

// Return Date.now() in seconds, rounded
function now() {
  return Math.round(Date.now() / 1000);
}

// First time with a new profile, so we don't have a cache.lastUpdate pref
add_task(function* checkFirstMetadata() {
  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");

  Services.prefs.setBoolPref(PREF_EM_SHOW_MISMATCH_UI, true);

  // Create and configure the HTTP server.
  testserver = new HttpServer();
  testserver.registerDirectory("/data/", do_get_file("data"));
  testserver.registerDirectory("/addons/", do_get_file("addons"));
  testserver.start(-1);
  gPort = testserver.identity.primaryPort;
  const BASE_URL  = "http://localhost:" + gPort;
  const GETADDONS_RESULTS = BASE_URL + "/data/test_AddonRepository_cache.xml";
  Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, GETADDONS_RESULTS);

  // Put an add-on in our profile so the metadata check will have something to do
  var min1max2 = {
    id: "min1max2@tests.mozilla.org",
    version: "1.0",
    name: "Test addon compatible with v1->v2",
    targetApplications: [{
      id: "xpcshell@tests.mozilla.org",
      minVersion: "1",
      maxVersion: "2"
    }]
  };
  writeInstallRDFForExtension(min1max2, profileDir);

  startupManager();

  // Make sure that updating metadata for the first time sets the lastUpdate preference
  yield AddonRepository.repopulateCache();
  do_print("Update done, getting last update");
  let lastUpdate = Services.prefs.getIntPref(PREF_METADATA_LASTUPDATE);
  do_check_true(lastUpdate > 0);

  // Make sure updating metadata again updates the preference
  let oldUpdate = lastUpdate - 2 * DEFAULT_METADATA_UPDATETHRESHOLD_SEC;
  Services.prefs.setIntPref(PREF_METADATA_LASTUPDATE, oldUpdate);
  yield AddonRepository.repopulateCache();
  do_check_neq(oldUpdate, Services.prefs.getIntPref(PREF_METADATA_LASTUPDATE));
});

// First upgrade with no lastUpdate pref and no add-ons changing shows UI
add_task(function* upgrade_no_lastupdate() {
  Services.prefs.clearUserPref(PREF_METADATA_LASTUPDATE);

  WindowWatcher.expected = true;
  yield promiseRestartManager("2");
  do_check_false(WindowWatcher.expected);
});

// Upgrade with lastUpdate more than default threshold and no add-ons changing shows UI
add_task(function* upgrade_old_lastupdate() {
  let oldEnough = now() - DEFAULT_METADATA_UPDATETHRESHOLD_SEC - 1000;
  Services.prefs.setIntPref(PREF_METADATA_LASTUPDATE, oldEnough);

  WindowWatcher.expected = true;
  // upgrade, downgrade, it has the same effect on the code path under test
  yield promiseRestartManager("1");
  do_check_false(WindowWatcher.expected);
});

// Upgrade with lastUpdate less than default threshold and no add-ons changing doesn't show
add_task(function* upgrade_young_lastupdate() {
  let notOldEnough = now() - DEFAULT_METADATA_UPDATETHRESHOLD_SEC + 1000;
  Services.prefs.setIntPref(PREF_METADATA_LASTUPDATE, notOldEnough);

  WindowWatcher.expected = false;
  yield promiseRestartManager("2");
  do_check_false(WindowWatcher.expected);
});

// Repeat more-than and less-than but with updateThreshold preference set
// Upgrade with lastUpdate more than pref threshold and no add-ons changing shows UI
const TEST_UPDATETHRESHOLD_SEC = 50000;
add_task(function* upgrade_old_pref_lastupdate() {
  Services.prefs.setIntPref(PREF_METADATA_UPDATETHRESHOLD_SEC, TEST_UPDATETHRESHOLD_SEC);

  let oldEnough = now() - TEST_UPDATETHRESHOLD_SEC - 1000;
  Services.prefs.setIntPref(PREF_METADATA_LASTUPDATE, oldEnough);

  WindowWatcher.expected = true;
  yield promiseRestartManager("1");
  do_check_false(WindowWatcher.expected);
});

// Upgrade with lastUpdate less than pref threshold and no add-ons changing doesn't show
add_task(function* upgrade_young_pref_lastupdate() {
  let notOldEnough = now() - TEST_UPDATETHRESHOLD_SEC + 1000;
  Services.prefs.setIntPref(PREF_METADATA_LASTUPDATE, notOldEnough);

  WindowWatcher.expected = false;
  yield promiseRestartManager("2");
  do_check_false(WindowWatcher.expected);
});



add_task(function* cleanup() {
  return new Promise((resolve, reject) => {
    testserver.stop(resolve);
  });
});

function run_test() {
  run_next_test();
}