Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
4 */
6 /* General MAR File Download Tests */
8 const INC_CONTRACT_ID = "@mozilla.org/network/incremental-download;1";
10 var gIncrementalDownloadClassID, gIncOldFactory;
11 // gIncrementalDownloadErrorType is used to loop through each of the connection
12 // error types in the Mock incremental downloader.
13 var gIncrementalDownloadErrorType = 0;
15 var gNextRunFunc;
16 var gExpectedStatusResult;
18 function run_test() {
19 setupTestCommon();
21 logTestInfo("testing mar downloads, mar hash verification, and " +
22 "mar download interrupted recovery");
24 Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, false);
25 // The HTTP server is only used for the mar file downloads since it is slow
26 start_httpserver();
27 setUpdateURLOverride(gURLData + "update.xml");
28 // The mock XMLHttpRequest is MUCH faster
29 overrideXHR(callHandleEvent);
30 standardInit();
31 do_execute_soon(run_test_pt1);
32 }
34 // The HttpServer must be stopped before calling do_test_finished
35 function finish_test() {
36 stop_httpserver(doTestFinish);
37 }
39 function end_test() {
40 cleanupMockIncrementalDownload();
41 }
43 // Callback function used by the custom XMLHttpRequest implementation to
44 // call the nsIDOMEventListener's handleEvent method for onload.
45 function callHandleEvent() {
46 gXHR.status = 400;
47 gXHR.responseText = gResponseBody;
48 try {
49 var parser = AUS_Cc["@mozilla.org/xmlextras/domparser;1"].
50 createInstance(AUS_Ci.nsIDOMParser);
51 gXHR.responseXML = parser.parseFromString(gResponseBody, "application/xml");
52 } catch (e) {
53 }
54 var e = { target: gXHR };
55 gXHR.onload(e);
56 }
58 // Helper function for testing mar downloads that have the correct size
59 // specified in the update xml.
60 function run_test_helper_pt1(aMsg, aExpectedStatusResult, aNextRunFunc) {
61 gUpdates = null;
62 gUpdateCount = null;
63 gStatusResult = null;
64 gCheckFunc = check_test_helper_pt1_1;
65 gNextRunFunc = aNextRunFunc;
66 gExpectedStatusResult = aExpectedStatusResult;
67 logTestInfo(aMsg, Components.stack.caller);
68 gUpdateChecker.checkForUpdates(updateCheckListener, true);
69 }
71 function check_test_helper_pt1_1() {
72 do_check_eq(gUpdateCount, 1);
73 gCheckFunc = check_test_helper_pt1_2;
74 var bestUpdate = gAUS.selectUpdate(gUpdates, gUpdateCount);
75 var state = gAUS.downloadUpdate(bestUpdate, false);
76 if (state == STATE_NONE || state == STATE_FAILED)
77 do_throw("nsIApplicationUpdateService:downloadUpdate returned " + state);
78 gAUS.addDownloadListener(downloadListener);
79 }
81 function check_test_helper_pt1_2() {
82 do_check_eq(gStatusResult, gExpectedStatusResult);
83 gAUS.removeDownloadListener(downloadListener);
84 gNextRunFunc();
85 }
87 function setResponseBody(aHashFunction, aHashValue, aSize) {
88 var patches = getRemotePatchString(null, null,
89 aHashFunction, aHashValue, aSize);
90 var updates = getRemoteUpdateString(patches);
91 gResponseBody = getRemoteUpdatesXMLString(updates);
92 }
94 var newFactory = {
95 createInstance: function(aOuter, aIID) {
96 if (aOuter)
97 throw Components.results.NS_ERROR_NO_AGGREGATION;
98 return new IncrementalDownload().QueryInterface(aIID);
99 },
100 lockFactory: function(aLock) {
101 throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
102 },
103 QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIFactory])
104 };
106 function initMockIncrementalDownload() {
107 var registrar = AUS_Cm.QueryInterface(AUS_Ci.nsIComponentRegistrar);
108 gIncrementalDownloadClassID = registrar.contractIDToCID(INC_CONTRACT_ID);
109 gIncOldFactory = AUS_Cm.getClassObject(AUS_Cc[INC_CONTRACT_ID],
110 AUS_Ci.nsIFactory);
111 registrar.unregisterFactory(gIncrementalDownloadClassID, gIncOldFactory);
112 var components = [IncrementalDownload];
113 registrar.registerFactory(gIncrementalDownloadClassID, "",
114 INC_CONTRACT_ID, newFactory);
115 }
117 function cleanupMockIncrementalDownload() {
118 if (gIncOldFactory) {
119 var registrar = AUS_Cm.QueryInterface(AUS_Ci.nsIComponentRegistrar);
120 registrar.unregisterFactory(gIncrementalDownloadClassID, newFactory);
121 registrar.registerFactory(gIncrementalDownloadClassID, "",
122 INC_CONTRACT_ID, gIncOldFactory);
123 }
124 gIncOldFactory = null;
125 }
127 /* This Mock incremental downloader is used to verify that connection
128 * interrupts work correctly in updater code. The implementation of
129 * the mock incremental downloader is very simple, it simply copies
130 * the file to the destination location.
131 */
133 function IncrementalDownload() {
134 this.wrappedJSObject = this;
135 }
137 IncrementalDownload.prototype = {
138 QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIIncrementalDownload]),
140 /* nsIIncrementalDownload */
141 init: function(uri, file, chunkSize, intervalInSeconds) {
142 this._destination = file;
143 this._URI = uri;
144 this._finalURI = uri;
145 },
147 start: function(observer, ctxt) {
148 var tm = Components.classes["@mozilla.org/thread-manager;1"].
149 getService(AUS_Ci.nsIThreadManager);
150 // Do the actual operation async to give a chance for observers
151 // to add themselves.
152 tm.mainThread.dispatch(function() {
153 this._observer = observer.QueryInterface(AUS_Ci.nsIRequestObserver);
154 this._ctxt = ctxt;
155 this._observer.onStartRequest(this, this.ctxt);
156 let mar = getTestDirFile(FILE_SIMPLE_MAR);
157 mar.copyTo(this._destination.parent, this._destination.leafName);
158 var status = AUS_Cr.NS_OK
159 switch (gIncrementalDownloadErrorType++) {
160 case 0:
161 status = AUS_Cr.NS_ERROR_NET_RESET;
162 break;
163 case 1:
164 status = AUS_Cr.NS_ERROR_CONNECTION_REFUSED;
165 break;
166 case 2:
167 status = AUS_Cr.NS_ERROR_NET_RESET;
168 break;
169 case 3:
170 status = AUS_Cr.NS_OK;
171 break;
172 case 4:
173 status = AUS_Cr.NS_ERROR_OFFLINE;
174 // After we report offline, we want to eventually show offline
175 // status being changed to online.
176 var tm = Components.classes["@mozilla.org/thread-manager;1"].
177 getService(AUS_Ci.nsIThreadManager);
178 tm.mainThread.dispatch(function() {
179 Services.obs.notifyObservers(gAUS,
180 "network:offline-status-changed",
181 "online");
182 }, AUS_Ci.nsIThread.DISPATCH_NORMAL);
183 break;
184 }
185 this._observer.onStopRequest(this, this._ctxt, status);
186 }.bind(this), AUS_Ci.nsIThread.DISPATCH_NORMAL);
187 },
189 get URI() {
190 return this._URI;
191 },
193 get currentSize() {
194 throw AUS_Cr.NS_ERROR_NOT_IMPLEMENTED;
195 },
197 get destination() {
198 return this._destination;
199 },
201 get finalURI() {
202 return this._finalURI;
203 },
205 get totalSize() {
206 throw AUS_Cr.NS_ERROR_NOT_IMPLEMENTED;
207 },
209 /* nsIRequest */
210 cancel: function(aStatus) {
211 throw AUS_Cr.NS_ERROR_NOT_IMPLEMENTED;
212 },
213 suspend: function() {
214 throw AUS_Cr.NS_ERROR_NOT_IMPLEMENTED;
215 },
216 isPending: function() {
217 throw AUS_Cr.NS_ERROR_NOT_IMPLEMENTED;
218 },
219 _loadFlags: 0,
220 get loadFlags() {
221 return this._loadFlags;
222 },
223 set loadFlags(val) {
224 this._loadFlags = val;
225 },
227 _loadGroup: null,
228 get loadGroup() {
229 return this._loadGroup;
230 },
231 set loadGroup(val) {
232 this._loadGroup = val;
233 },
235 _name: "",
236 get name() {
237 return this._name;
238 },
240 _status: 0,
241 get status() {
242 return this._status;
243 }
244 }
246 // Test disconnecting during an update
247 function run_test_pt1() {
248 initMockIncrementalDownload();
249 setResponseBody("MD5", MD5_HASH_SIMPLE_MAR);
250 run_test_helper_pt1("mar download with connection interruption",
251 AUS_Cr.NS_OK, run_test_pt2);
252 }
254 // Test disconnecting during an update
255 function run_test_pt2() {
256 gIncrementalDownloadErrorType = 0;
257 Services.prefs.setIntPref(PREF_APP_UPDATE_SOCKET_ERRORS, 2);
258 Services.prefs.setIntPref(PREF_APP_UPDATE_RETRY_TIMEOUT, 0);
259 setResponseBody("MD5", MD5_HASH_SIMPLE_MAR);
261 var expectedResult;
262 if (IS_TOOLKIT_GONK) {
263 // Gonk treats interrupted downloads differently. For gonk, if the state
264 // is pending, this means that the download has completed and only the
265 // staging needs to occur. So gonk will skip the download portion which
266 // results in an NS_OK return.
267 expectedResult = AUS_Cr.NS_OK;
268 } else {
269 expectedResult = AUS_Cr.NS_ERROR_NET_RESET;
270 }
271 run_test_helper_pt1("mar download with connection interruption without recovery",
272 expectedResult, run_test_pt3);
273 }
275 // Test entering offline mode while downloading
276 function run_test_pt3() {
277 gIncrementalDownloadErrorType = 4;
278 setResponseBody("MD5", MD5_HASH_SIMPLE_MAR);
279 run_test_helper_pt1("mar download with offline mode",
280 AUS_Cr.NS_OK, finish_test);
281 }