test_quota_observer.js (5977B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const userAgentID = "28cd09e2-7506-42d8-9e50-b02785adc7ef"; 7 8 var db; 9 10 function run_test() { 11 do_get_profile(); 12 setPrefs({ 13 userAgentID, 14 }); 15 run_next_test(); 16 } 17 18 let putRecord = async function (perm, record) { 19 let uri = Services.io.newURI(record.scope); 20 21 PermissionTestUtils.add( 22 uri, 23 "desktop-notification", 24 Ci.nsIPermissionManager[perm] 25 ); 26 registerCleanupFunction(() => { 27 PermissionTestUtils.remove(uri, "desktop-notification"); 28 }); 29 30 await db.put(record); 31 }; 32 33 add_task(async function test_expiration_history_observer() { 34 db = PushServiceWebSocket.newPushDB(); 35 registerCleanupFunction(() => db.drop().then(_ => db.close())); 36 37 // A registration that we'll expire... 38 await putRecord("ALLOW_ACTION", { 39 channelID: "379c0668-8323-44d2-a315-4ee83f1a9ee9", 40 pushEndpoint: "https://example.org/push/1", 41 scope: "https://example.com/deals", 42 pushCount: 0, 43 lastPush: 0, 44 version: null, 45 originAttributes: "", 46 quota: 16, 47 }); 48 49 // ...And a registration that we'll evict on startup. 50 await putRecord("ALLOW_ACTION", { 51 channelID: "4cb6e454-37cf-41c4-a013-4e3a7fdd0bf1", 52 pushEndpoint: "https://example.org/push/3", 53 scope: "https://example.com/stuff", 54 pushCount: 0, 55 lastPush: 0, 56 version: null, 57 originAttributes: "", 58 quota: 0, 59 }); 60 61 await PlacesTestUtils.addVisits({ 62 uri: "https://example.com/infrequent", 63 title: "Infrequently-visited page", 64 visitDate: (Date.now() - 14 * 24 * 60 * 60 * 1000) * 1000, 65 transition: Ci.nsINavHistoryService.TRANSITION_LINK, 66 }); 67 68 let unregisterDone; 69 let unregisterPromise = new Promise(resolve => (unregisterDone = resolve)); 70 let subChangePromise = promiseObserverNotification( 71 PushServiceComponent.subscriptionChangeTopic, 72 (subject, data) => data == "https://example.com/stuff" 73 ); 74 75 PushService.init({ 76 serverURI: "wss://push.example.org/", 77 db, 78 makeWebSocket(uri) { 79 return new MockWebSocket(uri, { 80 onHello() { 81 this.serverSendMsg( 82 JSON.stringify({ 83 messageType: "hello", 84 status: 200, 85 uaid: userAgentID, 86 }) 87 ); 88 this.serverSendMsg( 89 JSON.stringify({ 90 messageType: "notification", 91 updates: [ 92 { 93 channelID: "379c0668-8323-44d2-a315-4ee83f1a9ee9", 94 version: 2, 95 }, 96 ], 97 }) 98 ); 99 }, 100 onUnregister(request) { 101 equal( 102 request.channelID, 103 "379c0668-8323-44d2-a315-4ee83f1a9ee9", 104 "Dropped wrong channel ID" 105 ); 106 equal(request.code, 201, "Expected quota exceeded unregister reason"); 107 unregisterDone(); 108 }, 109 onACK() {}, 110 }); 111 }, 112 }); 113 114 await subChangePromise; 115 await unregisterPromise; 116 117 let expiredRecord = await db.getByKeyID( 118 "379c0668-8323-44d2-a315-4ee83f1a9ee9" 119 ); 120 strictEqual(expiredRecord.quota, 0, "Expired record not updated"); 121 122 let notifiedScopes = []; 123 subChangePromise = promiseObserverNotification( 124 PushServiceComponent.subscriptionChangeTopic, 125 (subject, data) => { 126 notifiedScopes.push(data); 127 return notifiedScopes.length == 2; 128 } 129 ); 130 131 // Add an expired registration that we'll revive later using the idle 132 // observer. 133 await putRecord("ALLOW_ACTION", { 134 channelID: "eb33fc90-c883-4267-b5cb-613969e8e349", 135 pushEndpoint: "https://example.org/push/2", 136 scope: "https://example.com/auctions", 137 pushCount: 0, 138 lastPush: 0, 139 version: null, 140 originAttributes: "", 141 quota: 0, 142 }); 143 // ...And an expired registration that we'll revive on fetch. 144 await putRecord("ALLOW_ACTION", { 145 channelID: "6b2d13fe-d848-4c5f-bdda-e9fc89727dca", 146 pushEndpoint: "https://example.org/push/4", 147 scope: "https://example.net/sales", 148 pushCount: 0, 149 lastPush: 0, 150 version: null, 151 originAttributes: "", 152 quota: 0, 153 }); 154 155 // Now visit the site... 156 await PlacesTestUtils.addVisits({ 157 uri: "https://example.com/another-page", 158 title: "Infrequently-visited page", 159 visitDate: Date.now() * 1000, 160 transition: Ci.nsINavHistoryService.TRANSITION_LINK, 161 }); 162 Services.obs.notifyObservers(null, "idle-daily"); 163 164 // And we should receive notifications for both scopes. 165 await subChangePromise; 166 deepEqual( 167 notifiedScopes.sort(), 168 ["https://example.com/auctions", "https://example.com/deals"], 169 "Wrong scopes for subscription changes" 170 ); 171 172 let aRecord = await db.getByKeyID("379c0668-8323-44d2-a315-4ee83f1a9ee9"); 173 ok(!aRecord, "Should drop expired record"); 174 175 let bRecord = await db.getByKeyID("eb33fc90-c883-4267-b5cb-613969e8e349"); 176 ok(!bRecord, "Should drop evicted record"); 177 178 // Simulate a visit to a site with an expired registration, then fetch the 179 // record. This should drop the expired record and fire an observer 180 // notification. 181 await PlacesTestUtils.addVisits({ 182 uri: "https://example.net/sales", 183 title: "Firefox plushies, 99% off", 184 visitDate: Date.now() * 1000, 185 transition: Ci.nsINavHistoryService.TRANSITION_LINK, 186 }); 187 subChangePromise = promiseObserverNotification( 188 PushServiceComponent.subscriptionChangeTopic, 189 (subject, data) => { 190 if (data == "https://example.net/sales") { 191 ok( 192 subject.isContentPrincipal, 193 "Should pass subscription principal as the subject" 194 ); 195 return true; 196 } 197 return false; 198 } 199 ); 200 let record = await PushService.registration({ 201 scope: "https://example.net/sales", 202 originAttributes: "", 203 }); 204 ok(!record, "Should not return evicted record"); 205 ok( 206 !(await db.getByKeyID("6b2d13fe-d848-4c5f-bdda-e9fc89727dca")), 207 "Should drop evicted record on fetch" 208 ); 209 await subChangePromise; 210 });