|
1 /* |
|
2 * Test to ensure that image loading/decoding notifications are always |
|
3 * delivered async, and in the order we expect. |
|
4 * |
|
5 * Must be included from a file that has a uri of the image to test defined in |
|
6 * var uri. |
|
7 */ |
|
8 |
|
9 const Cc = Components.classes; |
|
10 const Ci = Components.interfaces; |
|
11 const Cu = Components.utils; |
|
12 const Cr = Components.results; |
|
13 |
|
14 Cu.import("resource://testing-common/httpd.js"); |
|
15 |
|
16 var server = new HttpServer(); |
|
17 server.registerDirectory("/", do_get_file('')); |
|
18 server.registerContentType("sjs", "sjs"); |
|
19 server.start(-1); |
|
20 |
|
21 |
|
22 load('image_load_helpers.js'); |
|
23 |
|
24 var requests = []; |
|
25 |
|
26 // Return a closure that holds on to the listener from the original |
|
27 // imgIRequest, and compares its results to the cloned one. |
|
28 function getCloneStopCallback(original_listener) |
|
29 { |
|
30 return function cloneStop(listener) { |
|
31 do_check_eq(original_listener.state, listener.state); |
|
32 |
|
33 // Sanity check to make sure we didn't accidentally use the same listener |
|
34 // twice. |
|
35 do_check_neq(original_listener, listener); |
|
36 do_test_finished(); |
|
37 } |
|
38 } |
|
39 |
|
40 // Make sure that cloned requests get all the same callbacks as the original, |
|
41 // but they aren't synchronous right now. |
|
42 function checkClone(other_listener, aRequest) |
|
43 { |
|
44 do_test_pending(); |
|
45 |
|
46 // For as long as clone notification is synchronous, we can't test the clone state reliably. |
|
47 var listener = new ImageListener(null, function(foo, bar) { do_test_finished(); } /*getCloneStopCallback(other_listener)*/); |
|
48 listener.synchronous = false; |
|
49 var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) |
|
50 .createScriptedObserver(listener); |
|
51 var clone = aRequest.clone(outer); |
|
52 requests.push(clone); |
|
53 } |
|
54 |
|
55 // Ensure that all the callbacks were called on aRequest. |
|
56 function checkSizeAndLoad(listener, aRequest) |
|
57 { |
|
58 do_check_neq(listener.state & SIZE_AVAILABLE, 0); |
|
59 do_check_neq(listener.state & LOAD_COMPLETE, 0); |
|
60 |
|
61 do_test_finished(); |
|
62 } |
|
63 |
|
64 function secondLoadDone(oldlistener, aRequest) |
|
65 { |
|
66 do_test_pending(); |
|
67 |
|
68 try { |
|
69 var staticrequest = aRequest.getStaticRequest(); |
|
70 |
|
71 // For as long as clone notification is synchronous, we can't test the |
|
72 // clone state reliably. |
|
73 var listener = new ImageListener(null, checkSizeAndLoad); |
|
74 listener.synchronous = false; |
|
75 var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) |
|
76 .createScriptedObserver(listener); |
|
77 var staticrequestclone = staticrequest.clone(outer); |
|
78 requests.push(staticrequestclone); |
|
79 } catch(e) { |
|
80 // We can't create a static request. Most likely the request we started |
|
81 // with didn't load successfully. |
|
82 do_test_finished(); |
|
83 } |
|
84 |
|
85 run_loadImageWithChannel_tests(); |
|
86 |
|
87 do_test_finished(); |
|
88 } |
|
89 |
|
90 // Load the request a second time. This should come from the image cache, and |
|
91 // therefore would be at most risk of being served synchronously. |
|
92 function checkSecondLoad() |
|
93 { |
|
94 do_test_pending(); |
|
95 |
|
96 var listener = new ImageListener(checkClone, secondLoadDone); |
|
97 var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) |
|
98 .createScriptedObserver(listener); |
|
99 requests.push(gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null, null)); |
|
100 listener.synchronous = false; |
|
101 } |
|
102 |
|
103 function firstLoadDone(oldlistener, aRequest) |
|
104 { |
|
105 checkSecondLoad(uri); |
|
106 |
|
107 do_test_finished(); |
|
108 } |
|
109 |
|
110 // Return a closure that allows us to check the stream listener's status when the |
|
111 // image starts loading. |
|
112 function getChannelLoadImageStartCallback(streamlistener) |
|
113 { |
|
114 return function channelLoadStart(imglistener, aRequest) { |
|
115 // We must not have received all status before we get this start callback. |
|
116 // If we have, we've broken people's expectations by delaying events from a |
|
117 // channel we were given. |
|
118 do_check_eq(streamlistener.requestStatus & STOP_REQUEST, 0); |
|
119 |
|
120 checkClone(imglistener, aRequest); |
|
121 } |
|
122 } |
|
123 |
|
124 // Return a closure that allows us to check the stream listener's status when the |
|
125 // image finishes loading. |
|
126 function getChannelLoadImageStopCallback(streamlistener, next) |
|
127 { |
|
128 return function channelLoadStop(imglistener, aRequest) { |
|
129 |
|
130 next(); |
|
131 |
|
132 do_test_finished(); |
|
133 } |
|
134 } |
|
135 |
|
136 // Load the request a second time. This should come from the image cache, and |
|
137 // therefore would be at most risk of being served synchronously. |
|
138 function checkSecondChannelLoad() |
|
139 { |
|
140 do_test_pending(); |
|
141 |
|
142 var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); |
|
143 var channel = ioService.newChannelFromURI(uri); |
|
144 var channellistener = new ChannelListener(); |
|
145 channel.asyncOpen(channellistener, null); |
|
146 |
|
147 var listener = new ImageListener(getChannelLoadImageStartCallback(channellistener), |
|
148 getChannelLoadImageStopCallback(channellistener, |
|
149 all_done_callback)); |
|
150 var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) |
|
151 .createScriptedObserver(listener); |
|
152 var outlistener = {}; |
|
153 requests.push(gCurrentLoader.loadImageWithChannelXPCOM(channel, outer, null, outlistener)); |
|
154 channellistener.outputListener = outlistener.value; |
|
155 |
|
156 listener.synchronous = false; |
|
157 } |
|
158 |
|
159 function run_loadImageWithChannel_tests() |
|
160 { |
|
161 // To ensure we're testing what we expect to, create a new loader and cache. |
|
162 gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader); |
|
163 |
|
164 do_test_pending(); |
|
165 |
|
166 var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); |
|
167 var channel = ioService.newChannelFromURI(uri); |
|
168 var channellistener = new ChannelListener(); |
|
169 channel.asyncOpen(channellistener, null); |
|
170 |
|
171 var listener = new ImageListener(getChannelLoadImageStartCallback(channellistener), |
|
172 getChannelLoadImageStopCallback(channellistener, |
|
173 checkSecondChannelLoad)); |
|
174 var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) |
|
175 .createScriptedObserver(listener); |
|
176 var outlistener = {}; |
|
177 requests.push(gCurrentLoader.loadImageWithChannelXPCOM(channel, outer, null, outlistener)); |
|
178 channellistener.outputListener = outlistener.value; |
|
179 |
|
180 listener.synchronous = false; |
|
181 } |
|
182 |
|
183 function all_done_callback() |
|
184 { |
|
185 server.stop(function() { do_test_finished(); }); |
|
186 } |
|
187 |
|
188 function startImageCallback(otherCb) |
|
189 { |
|
190 return function(listener, request) |
|
191 { |
|
192 // Make sure we can load the same image immediately out of the cache. |
|
193 do_test_pending(); |
|
194 var listener2 = new ImageListener(null, function(foo, bar) { do_test_finished(); }); |
|
195 var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) |
|
196 .createScriptedObserver(listener2); |
|
197 requests.push(gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null, null)); |
|
198 listener2.synchronous = false; |
|
199 |
|
200 // Now that we've started another load, chain to the callback. |
|
201 otherCb(listener, request); |
|
202 } |
|
203 } |
|
204 |
|
205 var gCurrentLoader; |
|
206 |
|
207 function cleanup() |
|
208 { |
|
209 for (var i = 0; i < requests.length; ++i) { |
|
210 requests[i].cancelAndForgetObserver(0); |
|
211 } |
|
212 } |
|
213 |
|
214 function run_test() |
|
215 { |
|
216 do_register_cleanup(cleanup); |
|
217 |
|
218 gCurrentLoader = Cc["@mozilla.org/image/loader;1"].createInstance(Ci.imgILoader); |
|
219 |
|
220 do_test_pending(); |
|
221 var listener = new ImageListener(startImageCallback(checkClone), firstLoadDone); |
|
222 var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools) |
|
223 .createScriptedObserver(listener); |
|
224 var req = gCurrentLoader.loadImageXPCOM(uri, null, null, null, null, outer, null, 0, null, null); |
|
225 requests.push(req); |
|
226 |
|
227 // Ensure that we don't cause any mayhem when we lock an image. |
|
228 req.lockImage(); |
|
229 |
|
230 listener.synchronous = false; |
|
231 } |