blob: 9f9bd7e72d767085f231d5b8611b6f38e7947505 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
import * as Protocol from '../../generated/protocol.js';
import {createTarget} from '../../testing/EnvironmentHelpers.js';
import {
clearMockConnectionResponseHandler,
describeWithMockConnection,
setMockConnectionResponseHandler,
} from '../../testing/MockConnection.js';
import * as SDK from './sdk.js';
describeWithMockConnection('ServiceWorkerCacheModel', () => {
let cacheStorageModel: SDK.ServiceWorkerCacheModel.ServiceWorkerCacheModel;
let cache: SDK.ServiceWorkerCacheModel.Cache;
let target: SDK.Target.Target;
let manager: SDK.StorageBucketsModel.StorageBucketsModel|null;
let cacheAgent: ProtocolProxyApi.CacheStorageApi;
const testKey = 'test-key';
const testStorageBucket = {
storageKey: testKey,
name: 'inbox',
};
const testStorageBucketInfo = {
id: '0',
bucket: testStorageBucket,
expiration: 0,
quota: 0,
persistent: false,
durability: Protocol.Storage.StorageBucketsDurability.Strict,
};
beforeEach(() => {
target = createTarget();
cacheStorageModel = new SDK.ServiceWorkerCacheModel.ServiceWorkerCacheModel(target);
cache = new SDK.ServiceWorkerCacheModel.Cache(
cacheStorageModel, testStorageBucket, 'test-cache', 'id' as Protocol.CacheStorage.CacheId);
manager = target.model(SDK.StorageBucketsModel.StorageBucketsModel);
cacheAgent = target.cacheStorageAgent();
});
describe('StorageKeyAdded', () => {
it('registers cache only when the model is enabled', async () => {
const cacheAdeddSpy = sinon.spy(cacheStorageModel, 'dispatchEventToListeners');
const cacheNamePromise = new Promise<string>(resolve => {
cacheStorageModel.addEventListener(SDK.ServiceWorkerCacheModel.Events.CACHE_ADDED, event => {
resolve(event.data.cache.cacheName);
});
});
setMockConnectionResponseHandler(
'CacheStorage.requestCacheNames',
() => ({
caches: [{cacheId: 'id', storageKey: testKey, storageBucket: testStorageBucket, cacheName: 'test-cache'}],
} as Protocol.CacheStorage.RequestCacheNamesResponse));
manager?.storageBucketCreatedOrUpdated({bucketInfo: testStorageBucketInfo});
assert.isFalse(cacheAdeddSpy.calledWithExactly(
SDK.ServiceWorkerCacheModel.Events.CACHE_ADDED as unknown as sinon.SinonMatcher,
{model: cacheStorageModel, cache}));
cacheStorageModel.enable();
manager?.storageBucketCreatedOrUpdated({bucketInfo: testStorageBucketInfo});
assert.strictEqual(await cacheNamePromise, 'test-cache');
});
it('starts tracking cache', () => {
const trackCacheSpy = sinon.spy(target.storageAgent(), 'invoke_trackCacheStorageForStorageKey' as never);
cacheStorageModel.enable();
manager?.storageBucketCreatedOrUpdated({bucketInfo: testStorageBucketInfo});
sinon.assert.calledOnceWithExactly(trackCacheSpy, {storageKey: testKey});
});
});
it('stops tracking cache', () => {
const untrackCacheSpy = sinon.spy(target.storageAgent(), 'invoke_untrackCacheStorageForStorageKey' as never);
cacheStorageModel.enable();
manager?.storageBucketCreatedOrUpdated({bucketInfo: testStorageBucketInfo});
manager?.storageBucketDeleted({bucketId: testStorageBucketInfo.id});
sinon.assert.calledOnceWithExactly(untrackCacheSpy, {storageKey: testKey});
});
it('detaches storage key event listeners on dispose', () => {
const trackCacheSpy = sinon.spy(target.storageAgent(), 'invoke_trackCacheStorageForStorageKey' as never);
const untrackCacheSpy = sinon.spy(target.storageAgent(), 'invoke_untrackCacheStorageForStorageKey' as never);
cacheStorageModel.enable();
cacheStorageModel.dispose();
manager?.storageBucketCreatedOrUpdated({bucketInfo: testStorageBucketInfo});
manager?.storageBucketDeleted({bucketId: testStorageBucketInfo.id});
sinon.assert.notCalled(trackCacheSpy);
sinon.assert.notCalled(untrackCacheSpy);
});
it('calls protocol method and dispatches event on refreshCacheNames', async () => {
const requestCacheNamesSpy = sinon.spy(cacheAgent, 'invoke_requestCacheNames');
const cacheAddedPromise = new Promise<void>(resolve => {
cacheStorageModel.addEventListener(SDK.ServiceWorkerCacheModel.Events.CACHE_ADDED, () => {
resolve();
});
});
setMockConnectionResponseHandler(
'CacheStorage.requestCacheNames',
() => ({
caches: [{cacheId: 'id', storageKey: testKey, storageBucket: testStorageBucket, cacheName: 'test-cache'}],
} as Protocol.CacheStorage.RequestCacheNamesResponse));
cacheStorageModel.enable();
manager?.storageBucketCreatedOrUpdated({bucketInfo: testStorageBucketInfo});
void cacheStorageModel.refreshCacheNames();
sinon.assert.calledWithExactly(requestCacheNamesSpy, {storageBucket: testStorageBucket});
await cacheAddedPromise;
});
it('dispatches event on cacheStorageContentUpdated', () => {
const dispatcherSpy = sinon.spy(cacheStorageModel, 'dispatchEventToListeners');
manager?.storageBucketCreatedOrUpdated({bucketInfo: testStorageBucketInfo});
cacheStorageModel.cacheStorageContentUpdated(
{origin: '', storageKey: testKey, bucketId: testStorageBucketInfo.id, cacheName: 'test-cache'});
sinon.assert.calledOnceWithExactly(
dispatcherSpy,
SDK.ServiceWorkerCacheModel.Events.CACHE_STORAGE_CONTENT_UPDATED as unknown as sinon.SinonMatcher,
{storageBucket: testStorageBucket, cacheName: 'test-cache'});
});
it('requests cache names on cacheStorageListUpdated', async () => {
const requestCacheNamesSpy = sinon.spy(cacheAgent, 'invoke_requestCacheNames');
cacheStorageModel.enable();
manager?.storageBucketCreatedOrUpdated({bucketInfo: testStorageBucketInfo});
cacheStorageModel.cacheStorageListUpdated({origin: '', storageKey: testKey, bucketId: testStorageBucketInfo.id});
sinon.assert.calledWithExactly(requestCacheNamesSpy, {storageBucket: testStorageBucket});
});
it('gets caches added for storage key', async () => {
const cacheNames = ['test-cache-1', 'test-cache-2'];
const cachesAddedPromise = new Promise<void>(resolve => {
cacheStorageModel.addEventListener(SDK.ServiceWorkerCacheModel.Events.CACHE_ADDED, () => {
resolve();
});
});
setMockConnectionResponseHandler(
'CacheStorage.requestCacheNames',
() => ({
caches: [
{cacheId: 'id1', storageKey: testKey, storageBucket: testStorageBucket, cacheName: 'test-cache-1'},
{cacheId: 'id2', storageKey: testKey, storageBucket: testStorageBucket, cacheName: 'test-cache-2'},
],
} as Protocol.CacheStorage.RequestCacheNamesResponse));
cacheStorageModel.enable();
manager?.storageBucketCreatedOrUpdated({bucketInfo: testStorageBucketInfo});
// make sure enough time passed for caches to populate
await cachesAddedPromise;
const caches = cacheStorageModel.caches();
assert.deepEqual(caches.map(cache => cache.cacheName), cacheNames);
});
it('removes caches for storage key on clearForStorageKey', async () => {
setMockConnectionResponseHandler(
'CacheStorage.requestCacheNames',
() => ({
caches: [
{cacheId: 'id1', storageKey: testKey, storageBucket: testStorageBucket, cacheName: 'test-cache-1'},
{cacheId: 'id2', storageKey: testKey, storageBucket: testStorageBucket, cacheName: 'test-cache-2'},
],
} as Protocol.CacheStorage.RequestCacheNamesResponse));
cacheStorageModel.enable();
manager?.storageBucketCreatedOrUpdated({bucketInfo: testStorageBucketInfo});
cacheStorageModel.refreshCacheNames();
clearMockConnectionResponseHandler('CacheStorage.requestCacheNames');
cacheStorageModel.clearForStorageKey(testKey);
assert.isEmpty(cacheStorageModel.caches());
});
it('registers storage key on enable', async () => {
const trackCacheSpy = sinon.spy(target.storageAgent(), 'invoke_trackCacheStorageForStorageKey' as never);
manager?.storageBucketCreatedOrUpdated({bucketInfo: testStorageBucketInfo});
cacheStorageModel.enable();
sinon.assert.calledOnceWithExactly(trackCacheSpy, {storageKey: testKey});
});
});