|
1 const Cu = Components.utils; |
|
2 Cu.import("resource://gre/modules/Services.jsm"); |
|
3 let tempScope = {}; |
|
4 Cu.import("resource://gre/modules/devtools/dbg-client.jsm", tempScope); |
|
5 Cu.import("resource://gre/modules/devtools/dbg-server.jsm", tempScope); |
|
6 Cu.import("resource://gre/modules/Promise.jsm", tempScope); |
|
7 let {DebuggerServer, DebuggerClient, Promise} = tempScope; |
|
8 tempScope = null; |
|
9 |
|
10 const {StorageFront} = require("devtools/server/actors/storage"); |
|
11 let gTests; |
|
12 let gExpected; |
|
13 let index = 0; |
|
14 |
|
15 const beforeReload = { |
|
16 cookies: ["test1.example.org", "sectest1.example.org"], |
|
17 localStorage: ["http://test1.example.org", "http://sectest1.example.org"], |
|
18 sessionStorage: ["http://test1.example.org", "http://sectest1.example.org"], |
|
19 }; |
|
20 |
|
21 function finishTests(client) { |
|
22 // Forcing GC/CC to get rid of docshells and windows created by this test. |
|
23 forceCollections(); |
|
24 client.close(() => { |
|
25 forceCollections(); |
|
26 DebuggerServer.destroy(); |
|
27 forceCollections(); |
|
28 DebuggerClient = DebuggerServer = gTests = null; |
|
29 finish(); |
|
30 }); |
|
31 } |
|
32 |
|
33 function markOutMatched(toBeEmptied, data, deleted) { |
|
34 if (!Object.keys(toBeEmptied).length) { |
|
35 info("Object empty") |
|
36 return; |
|
37 } |
|
38 ok(Object.keys(data).length, |
|
39 "Atleast some storage types should be present in deleted"); |
|
40 for (let storageType in toBeEmptied) { |
|
41 if (!data[storageType]) { |
|
42 continue; |
|
43 } |
|
44 info("Testing for " + storageType); |
|
45 for (let host in data[storageType]) { |
|
46 ok(toBeEmptied[storageType][host], "Host " + host + " found"); |
|
47 |
|
48 for (let item of data[storageType][host]) { |
|
49 let index = toBeEmptied[storageType][host].indexOf(item); |
|
50 ok(index > -1, "Item found - " + item); |
|
51 if (index > -1) { |
|
52 toBeEmptied[storageType][host].splice(index, 1); |
|
53 } |
|
54 } |
|
55 if (!toBeEmptied[storageType][host].length) { |
|
56 delete toBeEmptied[storageType][host]; |
|
57 } |
|
58 } |
|
59 if (!Object.keys(toBeEmptied[storageType]).length) { |
|
60 delete toBeEmptied[storageType]; |
|
61 } |
|
62 } |
|
63 } |
|
64 |
|
65 function onStoresCleared(data) { |
|
66 if (data.sessionStorage || data.localStorage) { |
|
67 let hosts = data.sessionStorage || data.localStorage; |
|
68 info("Stores cleared required for session storage"); |
|
69 is(hosts.length, 1, "number of hosts is 1"); |
|
70 is(hosts[0], "http://test1.example.org", |
|
71 "host matches for " + Object.keys(data)[0]); |
|
72 gTests.next(); |
|
73 } |
|
74 else { |
|
75 ok(false, "Stores cleared should only be for local and sesion storage"); |
|
76 } |
|
77 |
|
78 } |
|
79 |
|
80 function onStoresUpdate({added, changed, deleted}) { |
|
81 info("inside stores update for index " + index); |
|
82 |
|
83 // Here, added, changed and deleted might be null even if they are required as |
|
84 // per gExpected. This is fine as they might come in the next stores-update |
|
85 // call or have already come in the previous one. |
|
86 if (added) { |
|
87 info("matching added object for index " + index); |
|
88 markOutMatched(gExpected.added, added); |
|
89 } |
|
90 if (changed) { |
|
91 info("matching changed object for index " + index); |
|
92 markOutMatched(gExpected.changed, changed); |
|
93 } |
|
94 if (deleted) { |
|
95 info("matching deleted object for index " + index); |
|
96 markOutMatched(gExpected.deleted, deleted); |
|
97 } |
|
98 |
|
99 if ((!gExpected.added || !Object.keys(gExpected.added).length) && |
|
100 (!gExpected.changed || !Object.keys(gExpected.changed).length) && |
|
101 (!gExpected.deleted || !Object.keys(gExpected.deleted).length)) { |
|
102 info("Everything expected has been received for index " + index); |
|
103 index++; |
|
104 gTests.next(); |
|
105 } |
|
106 else { |
|
107 info("Still some updates pending for index " + index); |
|
108 } |
|
109 } |
|
110 |
|
111 function* UpdateTests(front, win, client) { |
|
112 front.on("stores-update", onStoresUpdate); |
|
113 |
|
114 // index 0 |
|
115 gExpected = { |
|
116 added: { |
|
117 cookies: { |
|
118 "test1.example.org": ["c1", "c2"] |
|
119 }, |
|
120 localStorage: { |
|
121 "http://test1.example.org": ["l1"] |
|
122 } |
|
123 } |
|
124 }; |
|
125 win.addCookie("c1", "foobar1"); |
|
126 win.addCookie("c2", "foobar2"); |
|
127 win.localStorage.setItem("l1", "foobar1"); |
|
128 yield undefined; |
|
129 |
|
130 // index 1 |
|
131 gExpected = { |
|
132 changed: { |
|
133 cookies: { |
|
134 "test1.example.org": ["c1"] |
|
135 } |
|
136 }, |
|
137 added: { |
|
138 localStorage: { |
|
139 "http://test1.example.org": ["l2"] |
|
140 } |
|
141 } |
|
142 }; |
|
143 win.addCookie("c1", "new_foobar1"); |
|
144 win.localStorage.setItem("l2", "foobar2"); |
|
145 yield undefined; |
|
146 |
|
147 // index 2 |
|
148 gExpected = { |
|
149 deleted: { |
|
150 cookies: { |
|
151 "test1.example.org": ["c2"] |
|
152 }, |
|
153 localStorage: { |
|
154 "http://test1.example.org": ["l1"] |
|
155 } |
|
156 }, |
|
157 added: { |
|
158 localStorage: { |
|
159 "http://test1.example.org": ["l3"] |
|
160 } |
|
161 } |
|
162 }; |
|
163 win.removeCookie("c2"); |
|
164 win.localStorage.removeItem("l1"); |
|
165 win.localStorage.setItem("l3", "foobar3"); |
|
166 yield undefined; |
|
167 |
|
168 // index 3 |
|
169 gExpected = { |
|
170 added: { |
|
171 cookies: { |
|
172 "test1.example.org": ["c3"] |
|
173 }, |
|
174 sessionStorage: { |
|
175 "http://test1.example.org": ["s1", "s2"] |
|
176 } |
|
177 }, |
|
178 changed: { |
|
179 localStorage: { |
|
180 "http://test1.example.org": ["l3"] |
|
181 } |
|
182 }, |
|
183 deleted: { |
|
184 cookies: { |
|
185 "test1.example.org": ["c1"] |
|
186 }, |
|
187 localStorage: { |
|
188 "http://test1.example.org": ["l2"] |
|
189 } |
|
190 } |
|
191 }; |
|
192 win.removeCookie("c1"); |
|
193 win.addCookie("c3", "foobar3"); |
|
194 win.localStorage.removeItem("l2"); |
|
195 win.sessionStorage.setItem("s1", "foobar1"); |
|
196 win.sessionStorage.setItem("s2", "foobar2"); |
|
197 win.localStorage.setItem("l3", "new_foobar3"); |
|
198 yield undefined; |
|
199 |
|
200 // index 4 |
|
201 gExpected = { |
|
202 deleted: { |
|
203 sessionStorage: { |
|
204 "http://test1.example.org": ["s1"] |
|
205 } |
|
206 } |
|
207 }; |
|
208 win.sessionStorage.removeItem("s1"); |
|
209 yield undefined; |
|
210 |
|
211 // index 5 |
|
212 gExpected = { |
|
213 deleted: { |
|
214 cookies: { |
|
215 "test1.example.org": ["c3"] |
|
216 } |
|
217 } |
|
218 }; |
|
219 front.on("stores-cleared", onStoresCleared); |
|
220 win.clear(); |
|
221 yield undefined; |
|
222 // Another 2 more yield undefined s so as to wait for the "stores-cleared" to |
|
223 // fire. One for Local Storage and other for Session Storage |
|
224 yield undefined; |
|
225 yield undefined; |
|
226 |
|
227 front.off("stores-cleared", onStoresCleared); |
|
228 front.off("stores-update", onStoresUpdate); |
|
229 finishTests(client); |
|
230 } |
|
231 |
|
232 |
|
233 function test() { |
|
234 waitForExplicitFinish(); |
|
235 addTab(MAIN_DOMAIN + "storage-updates.html", function(doc) { |
|
236 try { |
|
237 // Sometimes debugger server does not get destroyed correctly by previous |
|
238 // tests. |
|
239 DebuggerServer.destroy(); |
|
240 } catch (ex) { } |
|
241 DebuggerServer.init(function () { return true; }); |
|
242 DebuggerServer.addBrowserActors(); |
|
243 |
|
244 let client = new DebuggerClient(DebuggerServer.connectPipe()); |
|
245 client.connect(function onConnect() { |
|
246 client.listTabs(function onListTabs(aResponse) { |
|
247 let form = aResponse.tabs[aResponse.selected]; |
|
248 let front = StorageFront(client, form); |
|
249 gTests = UpdateTests(front, doc.defaultView.wrappedJSObject, |
|
250 client); |
|
251 // Make an initial call to initialize the actor |
|
252 front.listStores().then(() => gTests.next()); |
|
253 }); |
|
254 }); |
|
255 }) |
|
256 } |