Files
shaka-player/test/net/networking_engine_unit.js
T
Jacob Trimble 78fc6d9b36 Disallow unknown properties (2/5).
This is part of adding a new conformance rule to add additional type
safety.  This will disallow using properties of unknown types or using
unknown properties.

The first parts will be fixing errors caused by the new rule.  These
are backwards compatible, so can be applied before the rule is enabled.
Once all the errors and bugs are fixed, the rule will be enabled.

Change-Id: I48335fc6659d3c33a6d55b00d087b59410c79cf7
2017-06-27 19:47:42 +00:00

948 lines
30 KiB
JavaScript

/**
* @license
* Copyright 2016 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
describe('NetworkingEngine', /** @suppress {accessControls} */ function() {
/** @const */
var StatusPromise = shaka.test.StatusPromise;
/** @const */
var Util = shaka.test.Util;
/** @const */
var requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT;
/** @const */
var originalGetLocationProtocol =
shaka.net.NetworkingEngine.getLocationProtocol_;
/** @type {string} */
var fakeProtocol;
/** @type {!shaka.net.NetworkingEngine} */
var networkingEngine;
/** @type {!jasmine.Spy} */
var resolveScheme;
/** @type {!jasmine.Spy} */
var rejectScheme;
/** @type {!shaka.util.Error} */
var error;
beforeAll(function() {
shaka.net.NetworkingEngine.getLocationProtocol_ = function() {
return fakeProtocol;
};
});
beforeEach(function() {
fakeProtocol = 'http:';
error = new shaka.util.Error(
shaka.util.Error.Severity.RECOVERABLE,
shaka.util.Error.Category.NETWORK,
shaka.util.Error.Code.HTTP_ERROR);
networkingEngine = new shaka.net.NetworkingEngine();
resolveScheme = jasmine.createSpy('resolve scheme').and.callFake(
function() {
return Promise.resolve({
uri: '', data: new ArrayBuffer(5), headers: {}
});
});
rejectScheme = jasmine.createSpy('reject scheme')
.and.callFake(function() { return Promise.reject(error); });
shaka.net.NetworkingEngine.registerScheme(
'resolve', Util.spyFunc(resolveScheme));
shaka.net.NetworkingEngine.registerScheme(
'reject', Util.spyFunc(rejectScheme));
});
afterEach(function() {
shaka.net.NetworkingEngine.unregisterScheme('resolve');
shaka.net.NetworkingEngine.unregisterScheme('reject');
});
afterAll(function() {
shaka.net.NetworkingEngine.getLocationProtocol_ =
originalGetLocationProtocol;
});
describe('retry', function() {
it('will retry', function(done) {
var request = createRequest('reject://foo', {
maxAttempts: 2,
baseDelay: 0,
backoffFactor: 0,
fuzzFactor: 0,
timeout: 0
});
rejectScheme.and.callFake(function() {
if (rejectScheme.calls.count() == 1)
return Promise.reject(error);
else
return Promise.resolve({
uri: '', data: new ArrayBuffer(0), headers: {}
});
});
networkingEngine.request(requestType, request)
.catch(fail)
.then(function() {
expect(rejectScheme.calls.count()).toBe(2);
done();
});
});
it('will retry twice', function(done) {
var request = createRequest('reject://foo', {
maxAttempts: 3,
baseDelay: 0,
backoffFactor: 0,
fuzzFactor: 0,
timeout: 0
});
rejectScheme.and.callFake(function() {
if (rejectScheme.calls.count() < 3)
return Promise.reject(error);
else
return Promise.resolve({
uri: '', data: new ArrayBuffer(0), headers: {}
});
});
networkingEngine.request(requestType, request)
.catch(fail)
.then(function() {
expect(rejectScheme.calls.count()).toBe(3);
done();
});
});
it('will fail overall', function(done) {
var request = createRequest('reject://foo', {
maxAttempts: 3,
baseDelay: 0,
backoffFactor: 0,
fuzzFactor: 0,
timeout: 0
});
networkingEngine.request(requestType, request)
.then(fail)
.catch(function() { expect(rejectScheme.calls.count()).toBe(3); })
.then(done);
});
describe('backoff', function() {
/** @const */
var baseDelay = 200;
/** @const */
var origSetTimeout = shaka.net.NetworkingEngine.setTimeout_;
/** @const */
var realRandom = Math.random;
/** @type {!jasmine.Spy} */
var setTimeoutSpy;
beforeAll(function() {
setTimeoutSpy = jasmine.createSpy('setTimeout');
setTimeoutSpy.and.callFake(origSetTimeout);
shaka.net.NetworkingEngine.setTimeout_ = Util.spyFunc(setTimeoutSpy);
Math.random = function() { return 0.75; };
});
afterAll(function() {
Math.random = realRandom;
shaka.net.NetworkingEngine.setTimeout_ = origSetTimeout;
});
beforeEach(function() {
setTimeoutSpy.calls.reset();
});
it('uses baseDelay', function(done) {
var request = createRequest('reject://foo', {
maxAttempts: 2,
baseDelay: baseDelay,
fuzzFactor: 0,
backoffFactor: 2,
timeout: 0
});
networkingEngine.request(requestType, request)
.then(fail)
.catch(function() {
expect(setTimeoutSpy.calls.count()).toBe(1);
expect(setTimeoutSpy)
.toHaveBeenCalledWith(jasmine.any(Function), baseDelay);
})
.then(done);
});
it('uses backoffFactor', function(done) {
var request = createRequest('reject://foo', {
maxAttempts: 3,
baseDelay: baseDelay,
fuzzFactor: 0,
backoffFactor: 2,
timeout: 0
});
networkingEngine.request(requestType, request)
.then(fail)
.catch(function() {
expect(setTimeoutSpy.calls.count()).toBe(2);
expect(setTimeoutSpy)
.toHaveBeenCalledWith(jasmine.any(Function), baseDelay);
expect(setTimeoutSpy)
.toHaveBeenCalledWith(jasmine.any(Function), baseDelay * 2);
})
.then(done);
});
it('uses fuzzFactor', function(done) {
var request = createRequest('reject://foo', {
maxAttempts: 2,
baseDelay: baseDelay,
fuzzFactor: 1,
backoffFactor: 1,
timeout: 0
});
networkingEngine.request(requestType, request)
.then(fail)
.catch(function() {
// (rand * 2.0) - 1.0 = (0.75 * 2.0) - 1.0 = 0.5
// 0.5 * fuzzFactor = 0.5 * 1 = 0.5
// delay * (1 + 0.5) = baseDelay * (1 + 0.5)
expect(setTimeoutSpy.calls.count()).toBe(1);
expect(setTimeoutSpy)
.toHaveBeenCalledWith(jasmine.any(Function), baseDelay * 1.5);
})
.then(done);
});
});
it('uses multiple URIs', function(done) {
var request = createRequest('', {
maxAttempts: 3,
baseDelay: 0,
backoffFactor: 0,
fuzzFactor: 0,
timeout: 0
});
request.uris = ['reject://foo', 'resolve://foo'];
networkingEngine.request(requestType, request)
.catch(fail)
.then(function() {
expect(rejectScheme.calls.count()).toBe(1);
expect(resolveScheme.calls.count()).toBe(1);
done();
});
});
it('won\'t retry for CRITICAL error', function(done) {
var request = createRequest('reject://foo', {
maxAttempts: 5,
baseDelay: 0,
backoffFactor: 0,
fuzzFactor: 0,
timeout: 0
});
error.severity = shaka.util.Error.Severity.CRITICAL;
networkingEngine.request(requestType, request)
.then(fail)
.catch(function() {
expect(rejectScheme.calls.count()).toBe(1);
done();
});
});
});
describe('request', function() {
it('uses registered schemes', function(done) {
networkingEngine.request(requestType, createRequest('resolve://foo'))
.catch(fail)
.then(function() {
expect(resolveScheme).toHaveBeenCalled();
done();
});
});
it('can unregister scheme', function(done) {
shaka.net.NetworkingEngine.unregisterScheme('resolve');
networkingEngine.request(requestType, createRequest('resolve://foo'))
.then(fail)
.catch(function() { expect(resolveScheme).not.toHaveBeenCalled(); })
.then(done);
});
it('rejects if scheme does not exist', function(done) {
networkingEngine.request(requestType, createRequest('foo://foo'))
.then(fail)
.catch(function() { expect(resolveScheme).not.toHaveBeenCalled(); })
.then(done);
});
it('returns the response object', function(done) {
networkingEngine.request(requestType, createRequest('resolve://foo'))
.catch(fail)
.then(function(response) {
expect(response).toBeTruthy();
expect(response.data).toBeTruthy();
expect(response.data.byteLength).toBe(5);
expect(response.headers).toBeTruthy();
done();
});
});
it('passes correct arguments to plugin', function(done) {
var request = createRequest('resolve://foo');
request.method = 'POST';
resolveScheme.and.callFake(
function(uri, requestPassed, requestTypePassed) {
expect(uri).toBe(request.uris[0]);
expect(requestPassed).toEqual(request);
expect(requestTypePassed).toEqual(requestType);
return Promise.resolve({});
});
networkingEngine.request(requestType, request).catch(fail).then(done);
});
it('infers a scheme for // URIs', function(done) {
fakeProtocol = 'resolve:';
networkingEngine.request(requestType, createRequest('//foo'))
.catch(fail)
.then(function() {
expect(resolveScheme).toHaveBeenCalled();
expect(resolveScheme.calls.argsFor(0)[0]).toBe('resolve://foo');
done();
});
});
it('fills in defaults for partial request objects', function(done) {
var originalRequest = /** @type {shakaExtern.Request} */ ({
uris: ['resolve://foo']
});
resolveScheme.and.callFake(function(uri, request, requestTypePassed) {
// NetworkingEngine should have filled in these values:
expect(request.method).toBeTruthy();
expect(request.headers).toBeTruthy();
expect(request.retryParameters).toBeTruthy();
return Promise.resolve({});
});
networkingEngine.request(requestType, originalRequest)
.catch(fail).then(done);
});
});
describe('request filter', function() {
/** @type {!jasmine.Spy} */
var filter;
beforeEach(function() {
filter = jasmine.createSpy('request filter');
networkingEngine.registerRequestFilter(Util.spyFunc(filter));
});
afterEach(function() {
networkingEngine.unregisterRequestFilter(Util.spyFunc(filter));
});
it('can be called', function(done) {
networkingEngine.request(requestType, createRequest('resolve://foo'))
.catch(fail)
.then(function() {
expect(filter).toHaveBeenCalled();
done();
});
});
it('called on failure', function(done) {
networkingEngine.request(requestType, createRequest('reject://foo'))
.then(fail)
.catch(function() { expect(filter).toHaveBeenCalled(); })
.then(done);
});
it('is given correct arguments', function(done) {
var request = createRequest('resolve://foo');
networkingEngine.request(requestType, request)
.catch(fail)
.then(function() {
expect(filter.calls.argsFor(0)[0]).toBe(requestType);
expect(filter.calls.argsFor(0)[1]).toBe(request);
expect(filter.calls.argsFor(0)[1].uris[0]).toBe(request.uris[0]);
done();
});
});
it('waits for asynchronous filters', function(done) {
var responseFilter = jasmine.createSpy('response filter');
networkingEngine.registerResponseFilter(Util.spyFunc(responseFilter));
var p = new shaka.util.PublicPromise();
var p2 = new shaka.util.PublicPromise();
filter.and.returnValue(p);
responseFilter.and.returnValue(p2);
var request = createRequest('resolve://foo');
var r = new StatusPromise(networkingEngine.request(requestType, request));
Util.delay(0.1).then(function() {
expect(filter).toHaveBeenCalled();
expect(resolveScheme).not.toHaveBeenCalled();
expect(responseFilter).not.toHaveBeenCalled();
expect(r.status).toBe('pending');
p.resolve();
return Util.delay(0.1);
}).then(function() {
expect(resolveScheme).toHaveBeenCalled();
expect(responseFilter).toHaveBeenCalled();
expect(r.status).toBe('pending');
p2.resolve();
return Util.delay(0.1);
}).then(function() {
expect(r.status).toBe('resolved');
done();
}).catch(fail);
});
it('turns errors into shaka errors', function(done) {
var fakeError = 'fake error';
filter.and.callFake(function() {
throw fakeError;
});
networkingEngine.request(requestType, createRequest('resolve://foo'))
.then(fail)
.catch(function(e) {
expect(e.severity).toBe(shaka.util.Error.Severity.CRITICAL);
expect(e.code).toBe(shaka.util.Error.Code.REQUEST_FILTER_ERROR);
expect(e.data).toEqual([fakeError]);
done();
});
});
it('can modify uris', function(done) {
filter.and.callFake(function(type, request) {
request.uris = ['resolve://foo'];
});
networkingEngine.request(requestType, createRequest('reject://foo'))
.catch(fail)
.then(function() {
expect(filter).toHaveBeenCalled();
done();
});
});
it('applies request filters sequentially', function(done) {
var secondFilter = jasmine.createSpy('second request filter');
networkingEngine.registerRequestFilter(Util.spyFunc(secondFilter));
var order = 0;
filter.and.callFake(function() {
expect(order).toBe(0);
order += 1;
});
secondFilter.and.callFake(function() {
expect(order).toBe(1);
order += 1;
});
networkingEngine.request(requestType, createRequest('resolve://foo'))
.catch(fail)
.then(done);
});
it('can modify requests asynchronously', function(done) {
var p = new shaka.util.PublicPromise();
filter.and.callFake(function(type, request) {
return p.then(function() {
request.uris = ['resolve://foo'];
request.allowCrossSiteCredentials = true;
});
});
networkingEngine.request(requestType, createRequest('reject://foo'))
.catch(fail)
.then(function() {
expect(resolveScheme).toHaveBeenCalled();
expect(resolveScheme.calls.argsFor(0)[1].allowCrossSiteCredentials)
.toBe(true);
done();
});
Util.delay(0.1).then(function() {
expect(filter).toHaveBeenCalled();
expect(resolveScheme).not.toHaveBeenCalled();
p.resolve();
});
});
it('can modify allowCrossSiteCredentials', function(done) {
filter.and.callFake(function(type, request) {
request.allowCrossSiteCredentials = true;
});
networkingEngine.request(requestType, createRequest('resolve://foo'))
.catch(fail)
.then(function() {
expect(filter).toHaveBeenCalled();
expect(resolveScheme).toHaveBeenCalled();
expect(resolveScheme.calls.argsFor(0)[1].allowCrossSiteCredentials)
.toBe(true);
done();
});
});
it('if rejects will stop requests', function(done) {
var request = createRequest('resolve://foo', {
maxAttempts: 3,
baseDelay: 0,
backoffFactor: 0,
fuzzFactor: 0,
timeout: 0
});
filter.and.returnValue(Promise.reject());
networkingEngine.request(requestType, request)
.then(fail)
.catch(function() {
expect(resolveScheme).not.toHaveBeenCalled();
expect(filter.calls.count()).toBe(1);
})
.then(done);
});
it('if throws will stop requests', function(done) {
var request = createRequest('resolve://foo', {
maxAttempts: 3,
baseDelay: 0,
backoffFactor: 0,
fuzzFactor: 0,
timeout: 0
});
filter.and.throwError(error);
networkingEngine.request(requestType, request)
.then(fail)
.catch(function() {
expect(resolveScheme).not.toHaveBeenCalled();
expect(filter.calls.count()).toBe(1);
})
.then(done);
});
it('causes no errors to remove an unused filter', function() {
var unusedFilter = jasmine.createSpy('unused filter');
networkingEngine.unregisterRequestFilter(Util.spyFunc(unusedFilter));
});
});
describe('response filter', function() {
/** @type {!jasmine.Spy} */
var filter;
beforeEach(function() {
filter = jasmine.createSpy('response filter');
networkingEngine.registerResponseFilter(Util.spyFunc(filter));
resolveScheme.and.callFake(function(request) {
var response = {
uri: '', data: new ArrayBuffer(100), headers: {}
};
return Promise.resolve(response);
});
});
afterEach(function() {
networkingEngine.unregisterResponseFilter(Util.spyFunc(filter));
});
it('can be called', function(done) {
networkingEngine.request(requestType, createRequest('resolve://foo'))
.catch(fail)
.then(function() {
expect(filter).toHaveBeenCalled();
done();
});
});
it('not called on failure', function(done) {
networkingEngine.request(requestType, createRequest('reject://foo'))
.then(fail)
.catch(function() { expect(filter).not.toHaveBeenCalled(); })
.then(done);
});
it('is given correct arguments', function(done) {
var request = createRequest('resolve://foo');
networkingEngine.request(requestType, request)
.catch(fail)
.then(function() {
expect(filter.calls.argsFor(0)[0]).toBe(requestType);
expect(filter.calls.argsFor(0)[1]).toBeTruthy();
expect(filter.calls.argsFor(0)[1].data).toBeTruthy();
expect(filter.calls.argsFor(0)[1].headers).toBeTruthy();
done();
});
});
it('can modify data', function(done) {
filter.and.callFake(function(type, response) {
response.data = new ArrayBuffer(5);
});
networkingEngine.request(requestType, createRequest('resolve://foo'))
.catch(fail)
.then(function(response) {
expect(filter).toHaveBeenCalled();
expect(response).toBeTruthy();
expect(response.data.byteLength).toBe(5);
done();
});
});
it('can modify headers', function(done) {
filter.and.callFake(function(type, response) {
expect(response.headers).toBeTruthy();
response.headers['DATE'] = 'CAT';
});
networkingEngine.request(requestType, createRequest('resolve://foo'))
.catch(fail)
.then(function(response) {
expect(filter).toHaveBeenCalled();
expect(response).toBeTruthy();
expect(response.headers['DATE']).toBe('CAT');
done();
});
});
it('applies response filters sequentially', function(done) {
var secondFilter = jasmine.createSpy('second response filter');
networkingEngine.registerResponseFilter(Util.spyFunc(secondFilter));
var order = 0;
filter.and.callFake(function() {
expect(order).toBe(0);
order += 1;
});
secondFilter.and.callFake(function() {
expect(order).toBe(1);
order += 1;
});
networkingEngine.request(requestType, createRequest('resolve://foo'))
.catch(fail)
.then(done);
});
it('turns errors into shaka errors', function(done) {
var fakeError = 'fake error';
filter.and.callFake(function() {
throw fakeError;
});
networkingEngine.request(requestType, createRequest('resolve://foo'))
.then(fail)
.catch(function(e) {
expect(e.code).toBe(shaka.util.Error.Code.RESPONSE_FILTER_ERROR);
expect(e.data).toEqual([fakeError]);
done();
});
});
it('can modify responses asynchronously', function(done) {
var p = new shaka.util.PublicPromise();
filter.and.callFake(function(type, response) {
return p.then(function() {
expect(response.headers).toBeTruthy();
response.headers['DATE'] = 'CAT';
response.data = new ArrayBuffer(5);
});
});
var request = createRequest('resolve://foo');
var r = new StatusPromise(networkingEngine.request(requestType, request)
.catch(fail)
.then(function(response) {
expect(response).toBeTruthy();
expect(response.headers['DATE']).toBe('CAT');
expect(response.data.byteLength).toBe(5);
done();
}));
Util.delay(0.1).then(function() {
expect(filter).toHaveBeenCalled();
expect(r.status).toBe('pending');
p.resolve();
});
});
it('if throws will stop requests', function(done) {
filter.and.callFake(function() { throw error; });
networkingEngine.request(requestType, createRequest('resolve://foo'))
.then(fail)
.catch(function() { expect(filter).toHaveBeenCalled(); })
.then(done);
});
it('if throws will retry', function(done) {
var request = createRequest('resolve://foo', {
maxAttempts: 2,
baseDelay: 0,
backoffFactor: 0,
fuzzFactor: 0,
timeout: 0
});
error.severity = shaka.util.Error.Severity.RECOVERABLE;
filter.and.callFake(function() {
if (filter.calls.count() == 1) throw error;
});
networkingEngine.request(requestType, request)
.catch(fail)
.then(function() {
expect(resolveScheme.calls.count()).toBe(2);
expect(filter.calls.count()).toBe(2);
done();
});
});
it('causes no errors to remove an unused filter', function() {
var unusedFilter = jasmine.createSpy('unused filter');
networkingEngine.unregisterResponseFilter(Util.spyFunc(unusedFilter));
});
});
describe('destroy', function() {
it('waits for all operations to complete', function(done) {
var request = createRequest('resolve://foo');
var p = new shaka.util.PublicPromise();
resolveScheme.and.returnValue(p);
var r1 =
new StatusPromise(networkingEngine.request(requestType, request));
var r2 =
new StatusPromise(networkingEngine.request(requestType, request));
expect(r1.status).toBe('pending');
expect(r2.status).toBe('pending');
/** @type {!shaka.test.StatusPromise} */
var d;
Util.delay(0.1).then(function() {
d = new StatusPromise(networkingEngine.destroy());
expect(d.status).toBe('pending');
expect(r1.status).toBe('pending');
expect(r2.status).toBe('pending');
return Util.delay(0.1);
}).then(function() {
expect(d.status).toBe('pending');
p.resolve({});
return d;
}).then(function() {
return Util.delay(0.1);
}).then(function() {
expect(r1.status).not.toBe('pending');
expect(r2.status).not.toBe('pending');
expect(d.status).toBe('resolved');
}).catch(fail).then(done);
});
it('causes requests to reject if called while filtering', function(done) {
var filter = jasmine.createSpy('request filter');
networkingEngine.registerRequestFilter(Util.spyFunc(filter));
var p = new shaka.util.PublicPromise();
filter.and.returnValue(p);
var request = createRequest('resolve://foo', {
maxAttempts: 1,
baseDelay: 0,
backoffFactor: 0,
fuzzFactor: 0,
timeout: 0
});
var r = new StatusPromise(networkingEngine.request(requestType, request));
/** @type {!shaka.test.StatusPromise} */
var d;
Util.delay(0.1).then(function() {
expect(filter).toHaveBeenCalled();
expect(r.status).toBe('pending');
d = new StatusPromise(networkingEngine.destroy());
p.resolve();
return Util.delay(0.1);
}).then(function() {
expect(d.status).toBe('resolved');
expect(r.status).toBe('rejected');
expect(resolveScheme).not.toHaveBeenCalled();
}).catch(fail).then(done);
});
it('resolves even when a request fails', function(done) {
var request = createRequest('reject://foo');
var p = new shaka.util.PublicPromise();
rejectScheme.and.returnValue(p);
var r1 =
new StatusPromise(networkingEngine.request(requestType, request));
var r2 =
new StatusPromise(networkingEngine.request(requestType, request));
expect(r1.status).toBe('pending');
expect(r2.status).toBe('pending');
/** @type {!shaka.test.StatusPromise} */
var d;
Util.delay(0.1).then(function() {
d = new StatusPromise(networkingEngine.destroy());
expect(d.status).toBe('pending');
return Util.delay(0.1);
}).then(function() {
expect(d.status).toBe('pending');
p.reject(error);
return d;
}).then(function() {
return Util.delay(0.1);
}).then(function() {
expect(r1.status).toBe('rejected');
expect(r2.status).toBe('rejected');
expect(d.status).toBe('resolved');
}).catch(fail).then(done);
});
it('prevents new requests', function(done) {
var request = createRequest('resolve://foo');
var p = new shaka.util.PublicPromise();
resolveScheme.and.returnValue(p);
var r1 =
new StatusPromise(networkingEngine.request(requestType, request));
/** @type {!shaka.test.StatusPromise} */
var r2;
/** @type {!shaka.test.StatusPromise} */
var d;
expect(r1.status).toBe('pending');
Util.delay(0.1).then(function() {
// The request has already been made.
expect(resolveScheme.calls.count()).toBe(1);
d = new StatusPromise(networkingEngine.destroy());
expect(d.status).toBe('pending');
r2 = new StatusPromise(networkingEngine.request(requestType, request));
expect(r2.status).toBe('pending');
// A new request has not been made.
expect(resolveScheme.calls.count()).toBe(1);
return Util.delay(0.1);
}).then(function() {
expect(r1.status).toBe('pending');
expect(r2.status).toBe('rejected');
expect(d.status).toBe('pending');
p.resolve({});
return d;
}).then(function() {
return Util.delay(0.1);
}).then(function() {
expect(r1.status).toBe('resolved');
expect(r2.status).toBe('rejected');
expect(d.status).toBe('resolved');
expect(resolveScheme.calls.count()).toBe(1);
}).catch(fail).then(done);
});
it('does not allow further retries', function(done) {
var request = createRequest('reject://foo', {
maxAttempts: 3,
baseDelay: 0,
backoffFactor: 0,
fuzzFactor: 0,
timeout: 0
});
var p1 = new shaka.util.PublicPromise();
var p2 = new shaka.util.PublicPromise();
rejectScheme.and.callFake(function() {
return (rejectScheme.calls.count() == 1) ? p1 : p2;
});
var r1 =
new StatusPromise(networkingEngine.request(requestType, request));
/** @type {shaka.test.StatusPromise} */
var d;
expect(r1.status).toBe('pending');
Util.delay(0.1).then(function() {
expect(rejectScheme.calls.count()).toBe(1);
d = new StatusPromise(networkingEngine.destroy());
expect(d.status).toBe('pending');
return Util.delay(0.1);
}).then(function() {
expect(r1.status).toBe('pending');
expect(d.status).toBe('pending');
expect(rejectScheme.calls.count()).toBe(1);
// Reject the initial request.
p1.reject(error);
// Resolve any retry, but since we have already been destroyed, this
// promise should not be used.
p2.resolve();
return d;
}).then(function() {
return Util.delay(0.1);
}).then(function() {
expect(d.status).toBe('resolved');
// The request was never retried.
expect(r1.status).toBe('rejected');
expect(rejectScheme.calls.count()).toBe(1);
}).catch(fail).then(done);
});
});
it('ignores cache hits', function(done) {
var onSegmentDownloaded = jasmine.createSpy('onSegmentDownloaded');
networkingEngine =
new shaka.net.NetworkingEngine(Util.spyFunc(onSegmentDownloaded));
networkingEngine.request(requestType, createRequest('resolve://foo'))
.then(function() {
expect(onSegmentDownloaded).toHaveBeenCalled();
onSegmentDownloaded.calls.reset();
resolveScheme.and.callFake(function() {
return Promise.resolve({
uri: '',
data: new ArrayBuffer(5),
headers: {},
fromCache: true
});
});
return networkingEngine.request(
requestType, createRequest('resolve://foo'));
})
.then(function() {
expect(onSegmentDownloaded).not.toHaveBeenCalled();
})
.catch(fail)
.then(done);
});
/**
* @param {string} uri
* @param {shakaExtern.RetryParameters=} opt_retryParameters
* @return {shakaExtern.Request}
*/
function createRequest(uri, opt_retryParameters) {
var retryParameters = opt_retryParameters ||
shaka.net.NetworkingEngine.defaultRetryParameters();
return shaka.net.NetworkingEngine.makeRequest([uri], retryParameters);
}
});