debian-mirror-gitlab/spec/frontend/streaming/chunk_writer_spec.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

215 lines
5.3 KiB
JavaScript
Raw Normal View History

2023-05-27 22:25:52 +05:30
import { ChunkWriter } from '~/streaming/chunk_writer';
import { RenderBalancer } from '~/streaming/render_balancer';
jest.mock('~/streaming/render_balancer');
describe('ChunkWriter', () => {
let accumulator = '';
let write;
let close;
let abort;
let config;
let render;
const createChunk = (text) => {
const encoder = new TextEncoder();
return encoder.encode(text);
};
const createHtmlStream = () => {
write = jest.fn((part) => {
accumulator += part;
});
close = jest.fn();
abort = jest.fn();
return {
write,
close,
abort,
};
};
const createWriter = () => {
return new ChunkWriter(createHtmlStream(), config);
};
const pushChunks = (...chunks) => {
const writer = createWriter();
chunks.forEach((chunk) => {
writer.write(createChunk(chunk));
});
writer.close();
};
afterAll(() => {
global.JEST_DEBOUNCE_THROTTLE_TIMEOUT = undefined;
});
beforeEach(() => {
global.JEST_DEBOUNCE_THROTTLE_TIMEOUT = 100;
accumulator = '';
config = undefined;
render = jest.fn((cb) => {
while (cb()) {
// render until 'false'
}
});
RenderBalancer.mockImplementation(() => ({ render }));
});
describe('when chunk length must be "1"', () => {
beforeEach(() => {
config = { minChunkSize: 1, maxChunkSize: 1 };
});
it('splits big chunks into smaller ones', () => {
const text = 'foobar';
pushChunks(text);
expect(accumulator).toBe(text);
expect(write).toHaveBeenCalledTimes(text.length);
});
it('handles small emoji chunks', () => {
const text = 'foo👀bar👨👩👧baz👧👧🏻👧🏼👧🏽👧🏾👧🏿';
pushChunks(text);
expect(accumulator).toBe(text);
expect(write).toHaveBeenCalledTimes(createChunk(text).length);
});
});
describe('when chunk length must not be lower than "5" and exceed "10"', () => {
beforeEach(() => {
config = { minChunkSize: 5, maxChunkSize: 10 };
});
it('joins small chunks', () => {
const text = '12345';
pushChunks(...text.split(''));
expect(accumulator).toBe(text);
expect(write).toHaveBeenCalledTimes(1);
expect(close).toHaveBeenCalledTimes(1);
});
it('handles overflow with small chunks', () => {
const text = '123456789';
pushChunks(...text.split(''));
expect(accumulator).toBe(text);
expect(write).toHaveBeenCalledTimes(2);
expect(close).toHaveBeenCalledTimes(1);
});
it('calls flush on small chunks', () => {
global.JEST_DEBOUNCE_THROTTLE_TIMEOUT = undefined;
const flushAccumulator = jest.spyOn(ChunkWriter.prototype, 'flushAccumulator');
const text = '1';
pushChunks(text);
expect(accumulator).toBe(text);
expect(flushAccumulator).toHaveBeenCalledTimes(1);
});
it('calls flush on large chunks', () => {
const flushAccumulator = jest.spyOn(ChunkWriter.prototype, 'flushAccumulator');
const text = '1234567890123';
const writer = createWriter();
writer.write(createChunk(text));
jest.runAllTimers();
expect(accumulator).toBe(text);
expect(flushAccumulator).toHaveBeenCalledTimes(1);
});
});
describe('chunk balancing', () => {
let increase;
let decrease;
let renderOnce;
beforeEach(() => {
render = jest.fn((cb) => {
let next = true;
renderOnce = () => {
if (!next) return;
next = cb();
};
});
RenderBalancer.mockImplementation(({ increase: inc, decrease: dec }) => {
increase = jest.fn(inc);
decrease = jest.fn(dec);
return {
render,
};
});
});
describe('when frame time exceeds low limit', () => {
beforeEach(() => {
config = {
minChunkSize: 1,
maxChunkSize: 5,
balanceRate: 10,
};
});
it('increases chunk size', () => {
const text = '111222223';
const writer = createWriter();
const chunk = createChunk(text);
writer.write(chunk);
renderOnce();
increase();
renderOnce();
renderOnce();
writer.close();
expect(accumulator).toBe(text);
expect(write.mock.calls).toMatchObject([['111'], ['22222'], ['3']]);
expect(close).toHaveBeenCalledTimes(1);
});
});
describe('when frame time exceeds high limit', () => {
beforeEach(() => {
config = {
minChunkSize: 1,
maxChunkSize: 10,
balanceRate: 2,
};
});
it('decreases chunk size', () => {
const text = '1111112223345';
const writer = createWriter();
const chunk = createChunk(text);
writer.write(chunk);
renderOnce();
decrease();
renderOnce();
decrease();
renderOnce();
decrease();
renderOnce();
renderOnce();
writer.close();
expect(accumulator).toBe(text);
expect(write.mock.calls).toMatchObject([['111111'], ['222'], ['33'], ['4'], ['5']]);
expect(close).toHaveBeenCalledTimes(1);
});
});
});
it('calls abort on htmlStream', () => {
const writer = createWriter();
writer.abort();
expect(abort).toHaveBeenCalledTimes(1);
});
});