chrome-devtools-frontend
Version:
Chrome DevTools UI
369 lines (343 loc) • 13.7 kB
text/typescript
// Copyright 2024 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Lantern from '../lantern.js';
const {TCPConnection} = Lantern.Simulation;
describe('TCPConnection', () => {
describe('#constructor', () => {
it('should create the connection', () => {
const rtt = 150;
const throughput = 1600 * 1024;
const connection = new TCPConnection(rtt, throughput);
assert.isOk(connection);
assert.strictEqual(connection.rtt, rtt);
});
});
describe('#maximumSaturatedConnections', () => {
it('should compute number of supported simulated requests', () => {
const availableThroughput = 1460 * 8 * 10; // 10 TCP segments/second
assert.strictEqual(TCPConnection.maximumSaturatedConnections(100, availableThroughput), 1);
assert.strictEqual(TCPConnection.maximumSaturatedConnections(300, availableThroughput), 3);
assert.strictEqual(TCPConnection.maximumSaturatedConnections(1000, availableThroughput), 10);
});
});
describe('.setWarmed', () => {
it('adjusts the time to download appropriately', () => {
const connection = new TCPConnection(100, Infinity);
assert.strictEqual(connection.simulateDownloadUntil(0).timeElapsed, 300);
connection.setWarmed(true);
assert.strictEqual(connection.simulateDownloadUntil(0).timeElapsed, 100);
});
});
describe('.setCongestionWindow', () => {
it('adjusts the time to download appropriately', () => {
const connection = new TCPConnection(100, Infinity);
assert.deepEqual(connection.simulateDownloadUntil(50000), {
bytesDownloaded: 50000,
extraBytesDownloaded: 0,
congestionWindow: 40,
roundTrips: 5,
timeElapsed: 500,
connectionTiming: {
connectionTime: 250,
dnsResolutionTime: 0,
sslTime: 100,
timeToFirstByte: 300,
},
});
connection.setCongestionWindow(40); // will download all in one round trip
assert.deepEqual(connection.simulateDownloadUntil(50000), {
bytesDownloaded: 50000,
extraBytesDownloaded: 0,
congestionWindow: 40,
roundTrips: 3,
timeElapsed: 300,
connectionTiming: {
connectionTime: 250,
dnsResolutionTime: 0,
sslTime: 100,
timeToFirstByte: 300,
},
});
});
});
describe('.setH2OverflowBytesDownloaded', () => {
it('adjusts the time to download appropriately for H2 connections', () => {
const connection = new TCPConnection(100, Infinity, 0, true, true);
connection.setWarmed(true);
assert.strictEqual(connection.simulateDownloadUntil(30000).timeElapsed, 200);
connection.setH2OverflowBytesDownloaded(20000);
assert.strictEqual(connection.simulateDownloadUntil(30000).timeElapsed, 100);
connection.setH2OverflowBytesDownloaded(50000);
assert.strictEqual(connection.simulateDownloadUntil(30000).timeElapsed, 0);
});
it('does not adjust the time to download for non-H2 connections', () => {
const connection = new TCPConnection(100, Infinity, 0, true, false);
connection.setWarmed(true);
assert.strictEqual(connection.simulateDownloadUntil(30000).timeElapsed, 200);
connection.setH2OverflowBytesDownloaded(20000);
assert.strictEqual(connection.simulateDownloadUntil(30000).timeElapsed, 200);
connection.setH2OverflowBytesDownloaded(50000);
assert.strictEqual(connection.simulateDownloadUntil(30000).timeElapsed, 200);
});
});
describe('.simulateDownloadUntil', () => {
describe('when maximumTime is not set', () => {
it('should provide the correct values small payload non-SSL', () => {
const connection = new TCPConnection(100, Infinity, 0, false);
assert.deepEqual(connection.simulateDownloadUntil(7300), {
bytesDownloaded: 7300,
extraBytesDownloaded: 0,
congestionWindow: 10,
roundTrips: 2,
timeElapsed: 200,
connectionTiming: {
connectionTime: 150,
dnsResolutionTime: 0,
sslTime: undefined, // non-SSL
timeToFirstByte: 200,
},
});
});
it('should provide the correct values small payload SSL', () => {
const connection = new TCPConnection(100, Infinity, 0, true);
assert.deepEqual(connection.simulateDownloadUntil(7300), {
bytesDownloaded: 7300,
extraBytesDownloaded: 0,
congestionWindow: 10,
roundTrips: 3,
timeElapsed: 300,
connectionTiming: {
connectionTime: 250,
dnsResolutionTime: 0,
sslTime: 100,
timeToFirstByte: 300,
},
});
});
it('should provide the correct values small payload H2', () => {
const connection = new TCPConnection(100, Infinity, 0, true, true);
assert.deepEqual(connection.simulateDownloadUntil(7300), {
bytesDownloaded: 7300,
extraBytesDownloaded: 7300,
congestionWindow: 10,
roundTrips: 3,
timeElapsed: 300,
connectionTiming: {
connectionTime: 250,
dnsResolutionTime: 0,
sslTime: 100,
timeToFirstByte: 300,
},
});
});
it('should provide the correct values response time', () => {
const responseTime = 78;
const connection = new TCPConnection(100, Infinity, responseTime, true);
assert.deepEqual(connection.simulateDownloadUntil(7300), {
bytesDownloaded: 7300,
extraBytesDownloaded: 0,
congestionWindow: 10,
roundTrips: 3,
timeElapsed: 300 + responseTime,
connectionTiming: {
connectionTime: 250,
dnsResolutionTime: 0,
sslTime: 100,
timeToFirstByte: 378,
},
});
});
it('should provide the correct values large payload', () => {
const connection = new TCPConnection(100, 8 * 1000 * 1000);
const bytesToDownload = 10 * 1000 * 1000; // 10 mb
assert.deepEqual(connection.simulateDownloadUntil(bytesToDownload), {
bytesDownloaded: bytesToDownload,
extraBytesDownloaded: 0,
congestionWindow: 68,
roundTrips: 105,
timeElapsed: 10500,
connectionTiming: {
connectionTime: 250,
dnsResolutionTime: 0,
sslTime: 100,
timeToFirstByte: 300,
},
});
});
it('should provide the correct values resumed small payload', () => {
const connection = new TCPConnection(100, Infinity, 0, true);
assert.deepEqual(connection.simulateDownloadUntil(7300, {timeAlreadyElapsed: 250}), {
bytesDownloaded: 7300,
extraBytesDownloaded: 0,
congestionWindow: 10,
roundTrips: 3,
timeElapsed: 50,
connectionTiming: {
connectionTime: 250,
dnsResolutionTime: 0,
sslTime: 100,
timeToFirstByte: 300,
},
});
});
it('should provide the correct values resumed small payload H2', () => {
const connection = new TCPConnection(100, Infinity, 0, true, true);
connection.setWarmed(true);
connection.setH2OverflowBytesDownloaded(10000);
assert.deepEqual(connection.simulateDownloadUntil(7300), {
bytesDownloaded: 0,
extraBytesDownloaded: 2700, // 10000 - 7300
congestionWindow: 10,
roundTrips: 0,
timeElapsed: 0,
connectionTiming: {
timeToFirstByte: 0,
},
});
});
it('should provide the correct values resumed large payload', () => {
const connection = new TCPConnection(100, 8 * 1000 * 1000);
const bytesToDownload = 5 * 1000 * 1000; // 5 mb
connection.setCongestionWindow(68);
assert.deepEqual(
connection.simulateDownloadUntil(bytesToDownload, {timeAlreadyElapsed: 5234}),
{
bytesDownloaded: bytesToDownload,
extraBytesDownloaded: 0,
congestionWindow: 68,
roundTrips: 51, // 5 mb / (1460 * 68)
timeElapsed: 5100,
connectionTiming: {
connectionTime: 250,
dnsResolutionTime: 0,
sslTime: 100,
timeToFirstByte: 300,
},
},
);
});
});
describe('when maximumTime is set', () => {
it('should provide the correct values less than TTFB', () => {
const connection = new TCPConnection(100, Infinity, 0, false);
assert.deepEqual(
connection.simulateDownloadUntil(7300, {timeAlreadyElapsed: 0, maximumTimeToElapse: 68}),
{
bytesDownloaded: 7300,
extraBytesDownloaded: 0,
congestionWindow: 10,
roundTrips: 2,
timeElapsed: 200,
connectionTiming: {
connectionTime: 150,
dnsResolutionTime: 0,
sslTime: undefined, // non-SSL
timeToFirstByte: 200,
},
},
);
});
it('should provide the correct values just over TTFB', () => {
const connection = new TCPConnection(100, Infinity, 0, false);
assert.deepEqual(
connection.simulateDownloadUntil(7300, {timeAlreadyElapsed: 0, maximumTimeToElapse: 250}),
{
bytesDownloaded: 7300,
extraBytesDownloaded: 0,
congestionWindow: 10,
roundTrips: 2,
timeElapsed: 200,
connectionTiming: {
connectionTime: 150,
dnsResolutionTime: 0,
sslTime: undefined, // non-SSL
timeToFirstByte: 200,
},
},
);
});
it('should provide the correct values with already elapsed', () => {
const connection = new TCPConnection(100, Infinity, 0, false);
assert.deepEqual(
connection.simulateDownloadUntil(7300, {
timeAlreadyElapsed: 75,
maximumTimeToElapse: 250,
}),
{
bytesDownloaded: 7300,
extraBytesDownloaded: 0,
congestionWindow: 10,
roundTrips: 2,
timeElapsed: 125,
connectionTiming: {
connectionTime: 150,
dnsResolutionTime: 0,
sslTime: undefined, // non-SSL
timeToFirstByte: 200,
},
},
);
});
it('should provide the correct values large payloads', () => {
const connection = new TCPConnection(100, 8 * 1000 * 1000);
const bytesToDownload = 10 * 1000 * 1000; // 10 mb
assert.deepEqual(
connection.simulateDownloadUntil(bytesToDownload, {
timeAlreadyElapsed: 500,
maximumTimeToElapse: 740,
}),
{
bytesDownloaded: 683280, // should be less than 68 * 1460 * 8
extraBytesDownloaded: 0,
congestionWindow: 68,
roundTrips: 8,
timeElapsed: 800, // skips the handshake because time already elapsed
connectionTiming: {
connectionTime: 250,
dnsResolutionTime: 0,
sslTime: 100,
timeToFirstByte: 300,
},
},
);
});
it('should all add up', () => {
const connection = new TCPConnection(100, 8 * 1000 * 1000);
const bytesToDownload = 10 * 1000 * 1000; // 10 mb
const firstStoppingPoint = 5234;
const secondStoppingPoint = 315;
const thirdStoppingPoint = 10500 - firstStoppingPoint - secondStoppingPoint;
const firstSegment = connection.simulateDownloadUntil(bytesToDownload, {
timeAlreadyElapsed: 0,
maximumTimeToElapse: firstStoppingPoint,
});
const firstOvershoot = firstSegment.timeElapsed - firstStoppingPoint;
connection.setCongestionWindow(firstSegment.congestionWindow);
const secondSegment = connection.simulateDownloadUntil(
bytesToDownload - firstSegment.bytesDownloaded,
{
timeAlreadyElapsed: firstSegment.timeElapsed,
maximumTimeToElapse: secondStoppingPoint - firstOvershoot,
},
);
const secondOvershoot = firstOvershoot + secondSegment.timeElapsed - secondStoppingPoint;
connection.setCongestionWindow(secondSegment.congestionWindow);
const thirdSegment = connection.simulateDownloadUntil(
bytesToDownload - firstSegment.bytesDownloaded - secondSegment.bytesDownloaded,
{timeAlreadyElapsed: firstSegment.timeElapsed + secondSegment.timeElapsed},
);
const thirdOvershoot = secondOvershoot + thirdSegment.timeElapsed - thirdStoppingPoint;
assert.strictEqual(thirdOvershoot, 0);
assert.strictEqual(
firstSegment.bytesDownloaded + secondSegment.bytesDownloaded + thirdSegment.bytesDownloaded,
bytesToDownload,
);
assert.strictEqual(
firstSegment.timeElapsed + secondSegment.timeElapsed + thirdSegment.timeElapsed,
10500,
);
});
});
});
});