mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-14 15:56:38 +03:00
fbbd63d96b
This change fixes tests on Chromecast by loading tests later in the process. Test scripts are now dynamically inserted by boot.js, rather than loaded by Karma. The bootstrapping code then awaits the completion of that before starting the Karma frameworks (Jasmine) to run the tests. This also removes the use of goog.provide/goog.require in tests and test utils. We don't need to load test utils or library sources dynamically in each test, and this gives us more explicit control over script loading and ordering. Closes #4094
345 lines
12 KiB
JavaScript
345 lines
12 KiB
JavaScript
/*! @license
|
|
* Shaka Player
|
|
* Copyright 2016 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
// All of the database dumps referenced below were originally made from the
|
|
// "Heliocentrism" content in our demo app.
|
|
// https://storage.googleapis.com/shaka-demo-assets/heliocentrism/heliocentrism.mpd
|
|
// The dumps were made with test/test/util/canned_idb.js
|
|
const compatibilityTestsMetadata = [
|
|
{
|
|
// This was our original (v1) storage format for Shaka Player v2.0,
|
|
// deprecated in v2.3. This is not the same as the storage format from
|
|
// Shaka Player v1, which is no longer supported.
|
|
name: 'v1',
|
|
dbImagePath: '/base/test/test/assets/db-dump-v1.json',
|
|
manifestKey: 0,
|
|
readOnly: true,
|
|
makeCell: (connection) => new shaka.offline.indexeddb.V1StorageCell(
|
|
connection,
|
|
/* segmentStore= */ 'segment',
|
|
/* manifestStore= */ 'manifest'),
|
|
},
|
|
{
|
|
// Two variants of v2 exist in the field. This is the initial version of
|
|
// v2, as upgraded from v1 databases. It was broken in a way that prevented
|
|
// new records from being added. This format was introduced in Shaka Player
|
|
// v2.3 and deprecated in v2.3.2.
|
|
name: 'v2-broken',
|
|
dbImagePath: '/base/test/test/assets/db-dump-v2-broken.json',
|
|
manifestKey: 0,
|
|
readOnly: true,
|
|
makeCell: (connection) => new shaka.offline.indexeddb.V2StorageCell(
|
|
connection,
|
|
/* segmentStore= */ 'segment-v2',
|
|
/* manifestStore= */ 'manifest-v2'),
|
|
},
|
|
{
|
|
// This is the "clean" version of the v2 database format, as created from
|
|
// scratch, to which new records could be added. This format was introduced
|
|
// in Shaka Player v2.3 and deprecated in v2.3.2.
|
|
name: 'v2-clean',
|
|
dbImagePath: '/base/test/test/assets/db-dump-v2-clean.json',
|
|
manifestKey: 1,
|
|
readOnly: true,
|
|
makeCell: (connection) => new shaka.offline.indexeddb.V2StorageCell(
|
|
connection,
|
|
/* segmentStore= */ 'segment-v2',
|
|
/* manifestStore= */ 'manifest-v2'),
|
|
},
|
|
{
|
|
// This is the v3 version of the database, which is actually identical to
|
|
// the "clean" version of the v2 database. The version number was
|
|
// incremented to overcome the "broken" v2 databases. This format was
|
|
// introduced in v2.3.2 and deprecated in v3.0.
|
|
name: 'v3',
|
|
dbImagePath: '/base/test/test/assets/db-dump-v3.json',
|
|
manifestKey: 1,
|
|
readOnly: true,
|
|
makeCell: (connection) => new shaka.offline.indexeddb.V2StorageCell(
|
|
connection,
|
|
/* segmentStore= */ 'segment-v3',
|
|
/* manifestStore= */ 'manifest-v3'),
|
|
},
|
|
{
|
|
// This is the v4 version of the database as written by v2.5.0 - v2.5.9. A
|
|
// bug in v2.5 caused the stream metadata from all periods to be written to
|
|
// each period. This was corrected in v2.5.10.
|
|
// See https://github.com/shaka-project/shaka-player/issues/2389
|
|
name: 'v4-broken',
|
|
dbImagePath: '/base/test/test/assets/db-dump-v4-broken.json',
|
|
manifestKey: 1,
|
|
readOnly: true,
|
|
makeCell: (connection) => new shaka.offline.indexeddb.V2StorageCell(
|
|
connection,
|
|
// V4 of the database still used the V3 store names and structures.
|
|
/* segmentStore= */ 'segment-v3',
|
|
/* manifestStore= */ 'manifest-v3'),
|
|
},
|
|
{
|
|
// This is the v5 version of the database, introduced in v3.0.
|
|
name: 'v5',
|
|
dbImagePath: '/base/test/test/assets/db-dump-v5.json',
|
|
manifestKey: 1,
|
|
readOnly: false,
|
|
makeCell: (connection) => new shaka.offline.indexeddb.V5StorageCell(
|
|
connection,
|
|
/* segmentStore= */ 'segment-v5',
|
|
/* manifestStore= */ 'manifest-v5'),
|
|
},
|
|
];
|
|
|
|
filterDescribe('Storage Compatibility', () => window.indexedDB, () => {
|
|
for (const metadata of compatibilityTestsMetadata) {
|
|
describe(metadata.name, () => {
|
|
makeTests(metadata);
|
|
});
|
|
}
|
|
|
|
function makeTests(metadata) {
|
|
const CannedIDB = shaka.test.CannedIDB;
|
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
const Util = shaka.test.Util;
|
|
|
|
/** @type {?shaka.extern.StorageCell} */
|
|
let cell = null;
|
|
|
|
/** @type {?IDBDatabase} */
|
|
let connection = null;
|
|
|
|
/** @type {string} */
|
|
let dbImageAsString;
|
|
|
|
beforeAll(async () => {
|
|
const data = await shaka.test.Util.fetch(metadata.dbImagePath);
|
|
dbImageAsString = shaka.util.StringUtils.fromUTF8(data);
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
const dbName = 'shaka-storage-cell-test';
|
|
|
|
// Load the canned database image.
|
|
await CannedIDB.restoreJSON(
|
|
dbName, dbImageAsString, /* wipeDatabase= */ true);
|
|
|
|
// Track the connection so that we can close it when the test is over.
|
|
connection = await shaka.test.IndexedDBUtils.open(dbName);
|
|
|
|
// Create a storage cell.
|
|
cell = metadata.makeCell(connection);
|
|
});
|
|
|
|
afterEach(async () => {
|
|
// Destroy the cell before killing the connection.
|
|
if (cell) {
|
|
await cell.destroy();
|
|
}
|
|
cell = null;
|
|
|
|
if (connection) {
|
|
connection.close();
|
|
}
|
|
connection = null;
|
|
});
|
|
|
|
if (metadata.readOnly) {
|
|
it('cannot add new manifests', async () => {
|
|
const expected = Util.jasmineError(new shaka.util.Error(
|
|
shaka.util.Error.Severity.CRITICAL,
|
|
shaka.util.Error.Category.STORAGE,
|
|
shaka.util.Error.Code.NEW_KEY_OPERATION_NOT_SUPPORTED,
|
|
jasmine.any(String)));
|
|
|
|
// There should be one manifest.
|
|
const manifests = await cell.getAllManifests();
|
|
const manifest = manifests.get(metadata.manifestKey);
|
|
expect(manifest).toBeTruthy();
|
|
|
|
// Make sure that the request fails.
|
|
await expectAsync(
|
|
cell.addManifests([manifest])).toBeRejectedWith(expected);
|
|
});
|
|
|
|
it('cannot add new segment', async () => {
|
|
const expected = Util.jasmineError(new shaka.util.Error(
|
|
shaka.util.Error.Severity.CRITICAL,
|
|
shaka.util.Error.Category.STORAGE,
|
|
shaka.util.Error.Code.NEW_KEY_OPERATION_NOT_SUPPORTED,
|
|
jasmine.any(String)));
|
|
|
|
// Update the key to what should be a free key.
|
|
const segment = {data: new ArrayBuffer(16)};
|
|
|
|
// Make sure that the request fails.
|
|
await expectAsync(
|
|
cell.addSegments([segment])).toBeRejectedWith(expected);
|
|
});
|
|
} // if (metadata.readOnly)
|
|
|
|
it('can get all manifests', async () => {
|
|
// There should be one manifest.
|
|
const map = await cell.getAllManifests();
|
|
expect(map).toBeTruthy();
|
|
expect(map.size).toBe(1);
|
|
expect(map.get(metadata.manifestKey)).toBeTruthy();
|
|
});
|
|
|
|
it('can get manifest and all segments', async () => {
|
|
// There should be one manifest.
|
|
const manifests = await cell.getManifests([metadata.manifestKey]);
|
|
const manifest = manifests[0];
|
|
expect(manifest).toBeTruthy();
|
|
|
|
// Collect all the keys for each segment.
|
|
const dataKeys = getAllSegmentKeys(manifest);
|
|
|
|
// Check that each segment was successfully retrieved.
|
|
const segmentData = await cell.getSegments(dataKeys);
|
|
expect(segmentData.length).not.toBe(0);
|
|
|
|
for (const segment of segmentData) {
|
|
expect(segment).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
it('can update expiration', async () => {
|
|
const oldExpiration = Infinity;
|
|
const newExpiration = 1000;
|
|
|
|
const original = await cell.getManifests([metadata.manifestKey]);
|
|
expect(original).toBeTruthy();
|
|
expect(original[0]).toBeTruthy();
|
|
expect(original[0].expiration).toBe(oldExpiration);
|
|
|
|
await cell.updateManifestExpiration(metadata.manifestKey, newExpiration);
|
|
|
|
const updated = await cell.getManifests([metadata.manifestKey]);
|
|
expect(updated).toBeTruthy();
|
|
expect(updated[0]).toBeTruthy();
|
|
expect(updated[0].expiration).toBe(newExpiration);
|
|
});
|
|
|
|
it('can remove manifests and segments', async () => {
|
|
/** @type {!Array.<number>} */
|
|
const manifestKeys = [];
|
|
/** @type {!Array.<number>} */
|
|
const segmentKeys = [];
|
|
|
|
const manifests = await cell.getAllManifests();
|
|
manifests.forEach((manifest, manifestKey) => {
|
|
manifestKeys.push(manifestKey);
|
|
|
|
for (const key of getAllSegmentKeys(manifest)) {
|
|
segmentKeys.push(key);
|
|
}
|
|
});
|
|
|
|
expect(manifestKeys.length).toBe(1);
|
|
expect(segmentKeys.length).not.toBe(0);
|
|
|
|
// Remove all the segments.
|
|
const noop = () => {};
|
|
await cell.removeManifests(manifestKeys, noop);
|
|
await cell.removeSegments(segmentKeys, noop);
|
|
|
|
const expected = Util.jasmineError(new shaka.util.Error(
|
|
shaka.util.Error.Severity.CRITICAL,
|
|
shaka.util.Error.Category.STORAGE,
|
|
shaka.util.Error.Code.KEY_NOT_FOUND,
|
|
jasmine.any(String)));
|
|
const checkMissingSegment = async (key) => {
|
|
await expectAsync(cell.getSegments([key])).toBeRejectedWith(expected);
|
|
};
|
|
|
|
const checkMissingManifest = async (key) => {
|
|
await expectAsync(cell.getManifests([key])).toBeRejectedWith(expected);
|
|
};
|
|
|
|
// Need to check each key on its own to ensure that each key is missing
|
|
// and not just one of the keys is missing.
|
|
const checkMissingSegments = (keys) => {
|
|
return Promise.all(keys.map((key) => checkMissingSegment(key)));
|
|
};
|
|
const checkMissingManifests = (keys) => {
|
|
return Promise.all(keys.map((key) => checkMissingManifest(key)));
|
|
};
|
|
|
|
await checkMissingSegments(segmentKeys);
|
|
await checkMissingManifests(manifestKeys);
|
|
});
|
|
|
|
it('correctly converts to the current manifest format', async () => {
|
|
// There should be one manifest.
|
|
const manifestDb = (await cell.getManifests([metadata.manifestKey]))[0];
|
|
const converter = new shaka.offline.ManifestConverter(
|
|
'mechanism', 'cell');
|
|
const actual = converter.fromManifestDB(manifestDb);
|
|
|
|
const expected = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
manifest.anyTimeline();
|
|
manifest.minBufferTime = 2;
|
|
|
|
manifest.addPartialVariant((variant) => {
|
|
variant.addPartialStream(ContentType.VIDEO, (stream) => {
|
|
stream.frameRate = 29.97;
|
|
stream.mime('video/webm', 'vp9');
|
|
stream.size(640, 480);
|
|
});
|
|
});
|
|
});
|
|
|
|
expect(actual).toEqual(expected);
|
|
|
|
const segmentIndex = actual.variants[0].video.segmentIndex;
|
|
goog.asserts.assert(segmentIndex != null, 'Null segmentIndex!');
|
|
const [segment0, segment1, segment2] = Array.from(segmentIndex);
|
|
|
|
expect(segment0).toEqual(jasmine.objectContaining({
|
|
startTime: 0,
|
|
endTime: Util.closeTo(2.06874),
|
|
timestampOffset: 0,
|
|
appendWindowStart: 0,
|
|
appendWindowEnd: Util.closeTo(2.06874),
|
|
}));
|
|
expect(segment1).toEqual(jasmine.objectContaining({
|
|
startTime: Util.closeTo(2.06874),
|
|
endTime: Util.closeTo(4.20413),
|
|
timestampOffset: Util.closeTo(2.06874),
|
|
appendWindowStart: Util.closeTo(2.06874),
|
|
appendWindowEnd: Util.closeTo(4.20413),
|
|
}));
|
|
expect(segment2).toEqual(jasmine.objectContaining({
|
|
startTime: Util.closeTo(4.20413),
|
|
endTime: Util.closeTo(4.904831),
|
|
timestampOffset: Util.closeTo(4.20413),
|
|
appendWindowStart: Util.closeTo(4.20413),
|
|
appendWindowEnd: Util.closeTo(4.904831),
|
|
}));
|
|
});
|
|
|
|
/**
|
|
* Get the keys for each segment. This will include the init segments.
|
|
*
|
|
* @param {shaka.extern.ManifestDB} manifest
|
|
* @return {!Array.<number>}
|
|
*/
|
|
function getAllSegmentKeys(manifest) {
|
|
const keys = new Set();
|
|
|
|
for (const stream of manifest.streams) {
|
|
for (const segment of stream.segments) {
|
|
if (segment.initSegmentKey != null) {
|
|
keys.add(segment.initSegmentKey);
|
|
}
|
|
|
|
keys.add(segment.dataKey);
|
|
}
|
|
}
|
|
|
|
return Array.from(keys);
|
|
}
|
|
} // makeTests
|
|
});
|