Skip to content

Commit

Permalink
chore: add network-request tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Dzianis Dashkevich committed Oct 2, 2024
1 parent faddf5c commit 531b9b0
Show file tree
Hide file tree
Showing 6 changed files with 454 additions and 32 deletions.
1 change: 1 addition & 0 deletions packages/playback/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { Player } from './lib/player';
export { ServiceLocator } from './lib/service-locator';

// consts
export { LoggerLevel } from './lib/consts/logger-level';
Expand Down
20 changes: 14 additions & 6 deletions packages/playback/src/lib/network/network-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
INetworkRequest,
IRequestPayloadWithChunkHandler,
INetworkInterceptorsProvider,
IRequestPayload,
} from '../types/network.declarations';
import { NetworkRequestWithChunkHandler, NetworkRequestWithMapper } from './network-request';
import type { PlayerNetworkConfiguration } from '../types/configuration.declarations';
Expand Down Expand Up @@ -39,27 +40,27 @@ export class NetworkManager implements INetworkManager {
}

public get<T>(payload: IRequestPayloadWithMapper<T>): INetworkRequest<T> {
(payload.requestInit as RequestInit).method = 'GET';
this.updateRequestInit_(payload, 'GET');
return this.createNetworkRequestWithMapper_(payload);
}

public getProgressive(payload: IRequestPayloadWithChunkHandler): INetworkRequest<void> {
(payload.requestInit as RequestInit).method = 'GET';
this.updateRequestInit_(payload, 'GET');
return this.createNetworkRequestWithChunkHandler_(payload);
}

public post<T>(payload: IRequestPayloadWithMapper<T>): INetworkRequest<T> {
(payload.requestInit as RequestInit).method = 'POST';
this.updateRequestInit_(payload, 'POST');
return this.createNetworkRequestWithMapper_(payload);
}

public postProgressive(payload: IRequestPayloadWithChunkHandler): INetworkRequest<void> {
(payload.requestInit as RequestInit).method = 'POST';
this.updateRequestInit_(payload, 'POST');
return this.createNetworkRequestWithChunkHandler_(payload);
}

private createNetworkRequestWithMapper_<T>(payload: IRequestPayloadWithMapper<T>): INetworkRequest<T> {
return new NetworkRequestWithMapper<T>(payload, {
return NetworkRequestWithMapper.create(payload, {
logger: this.logger_,
networkInterceptorsProvider: this.networkInterceptorsProvider_,
eventEmitter: this.eventEmitter_,
Expand All @@ -69,7 +70,7 @@ export class NetworkManager implements INetworkManager {
}

private createNetworkRequestWithChunkHandler_(payload: IRequestPayloadWithChunkHandler): INetworkRequest<void> {
return new NetworkRequestWithChunkHandler(payload, {
return NetworkRequestWithChunkHandler.create(payload, {
logger: this.logger_,
networkInterceptorsProvider: this.networkInterceptorsProvider_,
eventEmitter: this.eventEmitter_,
Expand All @@ -78,6 +79,13 @@ export class NetworkManager implements INetworkManager {
});
}

private updateRequestInit_(payload: IRequestPayload, method: string): IRequestPayload {
payload.requestInit = payload.requestInit || {};
(payload.requestInit as RequestInit).method = method;

return payload;
}

protected sendRequest_(request: Request): Promise<Response> {
return this.executor_(request);
}
Expand Down
65 changes: 47 additions & 18 deletions packages/playback/src/lib/network/network-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
} from '../events/network-events';
import type { NetworkConfiguration } from '../types/configuration.declarations';

interface NetworkRequestDependencies {
export interface NetworkRequestDependencies {
logger: ILogger;
networkInterceptorsProvider: INetworkInterceptorsProvider;
eventEmitter: IEventEmitter<NetworkEventMap>;
Expand All @@ -34,11 +34,11 @@ interface NetworkRequestDependencies {
}

abstract class NetworkRequest<T> implements INetworkRequest<T> {
private static counter_ = 0;
protected static counter_ = 0;

private isAborted_ = false;
private abortController_: AbortController;

protected readonly abortController_: AbortController;
protected readonly logger_: ILogger;
protected readonly networkInterceptorsProvider_: INetworkInterceptorsProvider;
protected readonly eventEmitter_: IEventEmitter<NetworkEventMap>;
Expand All @@ -55,26 +55,22 @@ abstract class NetworkRequest<T> implements INetworkRequest<T> {
return this.isAborted_;
}

protected constructor(payload: IRequestPayload, dependencies: NetworkRequestDependencies) {
NetworkRequest.counter_++;

protected constructor(id: string, payload: IRequestPayload, dependencies: NetworkRequestDependencies) {
const { logger, networkInterceptorsProvider, configuration, eventEmitter } = dependencies;
const { requestType, requestInit, url } = payload;

this.id = `${NetworkRequest.counter_}--${requestType}`;
this.logger_ = logger.createSubLogger(`NetworkRequest (${this.id})`);
this.id = id;
this.logger_ = logger;
this.networkInterceptorsProvider_ = networkInterceptorsProvider;
this.eventEmitter_ = eventEmitter;
this.abortController_ = new AbortController();
this.executor_ = dependencies.executor;
this.requestType = requestType;
this.configuration = configuration;

const request = new Request(url, { ...requestInit, signal: this.abortController_.signal });

this.retryWrapper_ = new RetryWrapper({
...configuration,
target: (): Promise<Response> => this.sendRequest_(request),
target: (): Promise<Response> => this.sendRequest_(url, requestInit as RequestInit),
shouldRetry: (e): boolean => !(e instanceof RequestAbortedNetworkError),
});
}
Expand All @@ -84,10 +80,12 @@ abstract class NetworkRequest<T> implements INetworkRequest<T> {
* so network manager will apply request interceptors on each network attempt.
* This make sense, since retry wrapper will gradually increase delay for each attempt,
* so user's credentials may expire between attempts.
* @param initialRequest - init request
* @param url - request url
* @param requestInit - request init
*/
private async sendRequest_(initialRequest: Request): Promise<Response> {
const finalRequest = await this.applyRequestInterceptors_(initialRequest);
private async sendRequest_(url: URL, requestInit: RequestInit): Promise<Response> {
const request = new Request(url, { ...requestInit, signal: this.abortController_.signal });
const finalRequest = await this.applyRequestInterceptors_(request);

return await this.wrapNetworkRequestExecutor_(finalRequest);
}
Expand Down Expand Up @@ -135,6 +133,9 @@ abstract class NetworkRequest<T> implements INetworkRequest<T> {
} else if (hitTimeout) {
// aborted from timeout
error = new TimeoutNetworkError();
// we have to re-create abort controller,
// to update abort signal for the next request attempt
this.abortController_ = new AbortController();
} else {
// aborted externally
error = new RequestAbortedNetworkError();
Expand Down Expand Up @@ -184,8 +185,22 @@ abstract class NetworkRequest<T> implements INetworkRequest<T> {
export class NetworkRequestWithMapper<T> extends NetworkRequest<T> {
public readonly done: Promise<T>;

public constructor(payload: IRequestPayloadWithMapper<T>, dependencies: NetworkRequestDependencies) {
super(payload, dependencies);
/* v8 ignore start */
public static create<T>(
payload: IRequestPayloadWithMapper<T>,
dependencies: NetworkRequestDependencies
): NetworkRequestWithMapper<T> {
NetworkRequest.counter_++;

const id = `mapper-${payload.requestType}-${NetworkRequest.counter_}`;
dependencies.logger = dependencies.logger.createSubLogger(`NetworkRequestWithMapper (${id})`);

return new NetworkRequestWithMapper(id, payload, dependencies);
}
/* v8 ignore stop */

public constructor(id: string, payload: IRequestPayloadWithMapper<T>, dependencies: NetworkRequestDependencies) {
super(id, payload, dependencies);

this.done = this.retryWrapper_
.execute()
Expand All @@ -197,8 +212,22 @@ export class NetworkRequestWithMapper<T> extends NetworkRequest<T> {
export class NetworkRequestWithChunkHandler extends NetworkRequest<void> {
public readonly done: Promise<void>;

public constructor(payload: IRequestPayloadWithChunkHandler, dependencies: NetworkRequestDependencies) {
super(payload, dependencies);
/* v8 ignore start */
public static create(
payload: IRequestPayloadWithChunkHandler,
dependencies: NetworkRequestDependencies
): NetworkRequestWithChunkHandler {
NetworkRequest.counter_++;

const id = `chunk-${payload.requestType}-${NetworkRequest.counter_}`;
dependencies.logger = dependencies.logger.createSubLogger(`NetworkRequestWithChunkHandler (${id})`);

return new NetworkRequestWithChunkHandler(id, payload, dependencies);
}
/* v8 ignore stop */

public constructor(id: string, payload: IRequestPayloadWithChunkHandler, dependencies: NetworkRequestDependencies) {
super(id, payload, dependencies);

this.done = this.retryWrapper_.execute().then((response) => {
const reader = response.body?.getReader();
Expand Down
14 changes: 9 additions & 5 deletions packages/playback/src/lib/utils/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@ export class Logger implements ILogger {

private level_: LoggerLevel = LoggerLevel.Debug;

private get cLabel_(): string {
return `%c${this.label_}`;
}

public constructor(dependencies: LoggerDependencies) {
this.console_ = dependencies.console;
this.label_ = `%c${dependencies.label}`;
this.label_ = dependencies.label;
this.delimiter_ = dependencies.delimiter;
}

Expand All @@ -43,30 +47,30 @@ export class Logger implements ILogger {
return;
}

this.console_.debug(this.label_, style, ...args);
this.console_.debug(this.cLabel_, style, ...args);
}

public info(...args: Array<unknown>): void {
if (this.level_ > LoggerLevel.Info) {
return;
}

this.console_.info(this.label_, style, ...args);
this.console_.info(this.cLabel_, style, ...args);
}

public warn(...args: Array<unknown>): void {
if (this.level_ > LoggerLevel.Warn) {
return;
}

this.console_.warn(this.label_, style, ...args);
this.console_.warn(this.cLabel_, style, ...args);
}

public error(...args: Array<unknown>): void {
if (this.level_ > LoggerLevel.Error) {
return;
}

this.console_.error(this.label_, style, ...args);
this.console_.error(this.cLabel_, style, ...args);
}
}
Loading

0 comments on commit 531b9b0

Please sign in to comment.