/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const userAgentID = "28cd09e2-7506-42d8-9e50-b02785adc7ef"; var db; function run_test() { do_get_profile(); setPrefs({ userAgentID, }); run_next_test(); } let putRecord = async function (perm, record) { let uri = Services.io.newURI(record.scope); PermissionTestUtils.add( uri, "desktop-notification", Ci.nsIPermissionManager[perm] ); registerCleanupFunction(() => { PermissionTestUtils.remove(uri, "desktop-notification"); }); await db.put(record); }; add_task(async function test_expiration_history_observer() { db = PushServiceWebSocket.newPushDB(); registerCleanupFunction(() => db.drop().then(_ => db.close())); // A registration that we'll expire... await putRecord("ALLOW_ACTION", { channelID: "379c0668-8323-44d2-a315-4ee83f1a9ee9", pushEndpoint: "https://example.org/push/1", scope: "https://example.com/deals", pushCount: 0, lastPush: 0, version: null, originAttributes: "", quota: 16, }); // ...And a registration that we'll evict on startup. await putRecord("ALLOW_ACTION", { channelID: "4cb6e454-37cf-41c4-a013-4e3a7fdd0bf1", pushEndpoint: "https://example.org/push/3", scope: "https://example.com/stuff", pushCount: 0, lastPush: 0, version: null, originAttributes: "", quota: 0, }); await PlacesTestUtils.addVisits({ uri: "https://example.com/infrequent", title: "Infrequently-visited page", visitDate: (Date.now() - 14 * 24 * 60 * 60 * 1000) * 1000, transition: Ci.nsINavHistoryService.TRANSITION_LINK, }); let unregisterDone; let unregisterPromise = new Promise(resolve => (unregisterDone = resolve)); let subChangePromise = promiseObserverNotification( PushServiceComponent.subscriptionChangeTopic, (subject, data) => data == "https://example.com/stuff" ); PushService.init({ serverURI: "wss://push.example.org/", db, makeWebSocket(uri) { return new MockWebSocket(uri, { onHello(request) { this.serverSendMsg( JSON.stringify({ messageType: "hello", status: 200, uaid: userAgentID, }) ); this.serverSendMsg( JSON.stringify({ messageType: "notification", updates: [ { channelID: "379c0668-8323-44d2-a315-4ee83f1a9ee9", version: 2, }, ], }) ); }, onUnregister(request) { equal( request.channelID, "379c0668-8323-44d2-a315-4ee83f1a9ee9", "Dropped wrong channel ID" ); equal(request.code, 201, "Expected quota exceeded unregister reason"); unregisterDone(); }, onACK(request) {}, }); }, }); await subChangePromise; await unregisterPromise; let expiredRecord = await db.getByKeyID( "379c0668-8323-44d2-a315-4ee83f1a9ee9" ); strictEqual(expiredRecord.quota, 0, "Expired record not updated"); let notifiedScopes = []; subChangePromise = promiseObserverNotification( PushServiceComponent.subscriptionChangeTopic, (subject, data) => { notifiedScopes.push(data); return notifiedScopes.length == 2; } ); // Add an expired registration that we'll revive later using the idle // observer. await putRecord("ALLOW_ACTION", { channelID: "eb33fc90-c883-4267-b5cb-613969e8e349", pushEndpoint: "https://example.org/push/2", scope: "https://example.com/auctions", pushCount: 0, lastPush: 0, version: null, originAttributes: "", quota: 0, }); // ...And an expired registration that we'll revive on fetch. await putRecord("ALLOW_ACTION", { channelID: "6b2d13fe-d848-4c5f-bdda-e9fc89727dca", pushEndpoint: "https://example.org/push/4", scope: "https://example.net/sales", pushCount: 0, lastPush: 0, version: null, originAttributes: "", quota: 0, }); // Now visit the site... await PlacesTestUtils.addVisits({ uri: "https://example.com/another-page", title: "Infrequently-visited page", visitDate: Date.now() * 1000, transition: Ci.nsINavHistoryService.TRANSITION_LINK, }); Services.obs.notifyObservers(null, "idle-daily"); // And we should receive notifications for both scopes. await subChangePromise; deepEqual( notifiedScopes.sort(), ["https://example.com/auctions", "https://example.com/deals"], "Wrong scopes for subscription changes" ); let aRecord = await db.getByKeyID("379c0668-8323-44d2-a315-4ee83f1a9ee9"); ok(!aRecord, "Should drop expired record"); let bRecord = await db.getByKeyID("eb33fc90-c883-4267-b5cb-613969e8e349"); ok(!bRecord, "Should drop evicted record"); // Simulate a visit to a site with an expired registration, then fetch the // record. This should drop the expired record and fire an observer // notification. await PlacesTestUtils.addVisits({ uri: "https://example.net/sales", title: "Firefox plushies, 99% off", visitDate: Date.now() * 1000, transition: Ci.nsINavHistoryService.TRANSITION_LINK, }); subChangePromise = promiseObserverNotification( PushServiceComponent.subscriptionChangeTopic, (subject, data) => { if (data == "https://example.net/sales") { ok( subject.isContentPrincipal, "Should pass subscription principal as the subject" ); return true; } return false; } ); let record = await PushService.registration({ scope: "https://example.net/sales", originAttributes: "", }); ok(!record, "Should not return evicted record"); ok( !(await db.getByKeyID("6b2d13fe-d848-4c5f-bdda-e9fc89727dca")), "Should drop evicted record on fetch" ); await subChangePromise; });