0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2024-12-16 21:56:25 -05:00
verdaccio/packages/proxy/test/proxy.spec.ts
Juan Picado 15c694156a
fix eslint warnings (#2265)
* chore: reduce warnings

* chore: fix eslint warnings

* fix warning
2021-06-12 09:25:53 +02:00

342 lines
12 KiB
TypeScript

import path from 'path';
import nock from 'nock';
import * as httpMocks from 'node-mocks-http';
import { Config, parseConfigFile } from '@verdaccio/config';
import { ErrorCode } from '@verdaccio/utils';
import { API_ERROR, HEADER_TYPE, HTTP_STATUS, VerdaccioError } from '@verdaccio/commons-api';
import { ProxyStorage } from '../src/up-storage';
const getConf = (name) => path.join(__dirname, '/conf', name);
const mockDebug = jest.fn();
const mockInfo = jest.fn();
const mockHttp = jest.fn();
const mockError = jest.fn();
const mockWarn = jest.fn();
jest.mock('@verdaccio/logger', () => {
const originalLogger = jest.requireActual('@verdaccio/logger');
return {
...originalLogger,
logger: {
child: () => ({
debug: (arg) => mockDebug(arg),
info: (arg) => mockInfo(arg),
http: (arg) => mockHttp(arg),
error: (arg) => mockError(arg),
warn: (arg) => mockWarn(arg),
}),
},
};
});
const domain = 'https://registry.npmjs.org';
describe('proxy', () => {
beforeEach(() => {
nock.cleanAll();
});
const defaultRequestOptions = {
url: 'https://registry.npmjs.org',
};
const proxyPath = getConf('proxy1.yaml');
const conf = new Config(parseConfigFile(proxyPath));
describe('search', () => {
test('get file from v1 endpoint', (done) => {
const url = '/-/v1/search';
nock(domain).get(url).replyWithFile(200, path.join(__dirname, 'partials/search-v1.json'));
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
const req = httpMocks.createRequest({
method: 'GET',
headers: {
referer: 'some.org',
['x-forwarded-for']: '10.0.0.1',
},
connection: {
remoteAddress: 'localhost',
},
url,
});
const stream = prox1.search({ req });
stream.on('data', (data) => {
expect(data).toBeDefined();
done();
});
});
test('abort search from v1 endpoint', (done) => {
const url = '/-/v1/search';
nock(domain).get(url).delay(20000);
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
const req = httpMocks.createRequest({
method: 'GET',
headers: {
referer: 'some.org',
['x-forwarded-for']: '10.0.0.1',
},
connection: {
remoteAddress: 'localhost',
},
url,
});
const stream = prox1.search({ req });
stream.on('end', () => {
done();
});
// TODO: apply correct types here
// @ts-ignore
stream.abort();
});
// TODO: we should test the gzip deflate here, but is hard to test
// fix me if you can deal with Incorrect Header Check issue
test.todo('get file from v1 endpoint with gzip headers');
test('search v1 endpoint fails', (done) => {
const url = '/-/v1/search';
nock(domain).get(url).replyWithError('search endpoint is down');
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
const req = httpMocks.createRequest({
method: 'GET',
headers: {
referer: 'some.org',
['x-forwarded-for']: '10.0.0.1',
},
connection: {
remoteAddress: 'localhost',
},
url,
});
const stream = prox1.search({ req });
stream.on('error', (error) => {
expect(error).toEqual(Error('search endpoint is down'));
done();
});
});
test('search v1 endpoint bad status code', (done) => {
const url = '/-/v1/search';
nock(domain).get(url).reply(409);
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
const req = httpMocks.createRequest({
method: 'GET',
headers: {
referer: 'some.org',
['x-forwarded-for']: '10.0.0.1',
},
connection: {
remoteAddress: 'localhost',
},
url,
});
const stream = prox1.search({ req });
stream.on('error', (error) => {
expect(error).toEqual(ErrorCode.getInternalError(`bad status code 409 from uplink`));
done();
});
});
});
describe('fetchTarball', () => {
test('get file tarball no content-length', (done) => {
nock(domain)
.get('/jquery/-/jquery-0.0.1.tgz')
.replyWithFile(201, path.join(__dirname, 'partials/jquery-0.0.1.tgz'));
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
const stream = prox1.fetchTarball('https://registry.npmjs.org/jquery/-/jquery-0.0.1.tgz');
stream.on('data', (data) => {
expect(data).toBeDefined();
done();
});
});
test('get file tarball correct content-length', (done) => {
nock(domain)
.get('/jquery/-/jquery-0.0.1.tgz')
// types does not match here with documentation
// @ts-expect-error
.replyWithFile(201, path.join(__dirname, 'partials/jquery-0.0.1.tgz'), {
[HEADER_TYPE.CONTENT_LENGTH]: 277,
});
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
const stream = prox1.fetchTarball('https://registry.npmjs.org/jquery/-/jquery-0.0.1.tgz');
stream.on(HEADER_TYPE.CONTENT_LENGTH, (data) => {
expect(data).toEqual('277');
done();
});
});
describe('error handling', () => {
test('should be offline uplink', (done) => {
const tarball = 'https://registry.npmjs.org/jquery/-/jquery-0.0.1.tgz';
nock(domain).get('/jquery/-/jquery-0.0.1.tgz').times(100).replyWithError('some error');
const proxy = new ProxyStorage(defaultRequestOptions, conf);
const stream = proxy.fetchTarball(tarball);
// to test a uplink is offline we have to be try 3 times
// the default failed request are set to 2
process.nextTick(function () {
stream.on('error', function (err) {
expect(err).not.toBeNull();
// expect(err.statusCode).toBe(404);
expect(proxy.failed_requests).toBe(1);
const streamSecondTry = proxy.fetchTarball(tarball);
streamSecondTry.on('error', function (err) {
expect(err).not.toBeNull();
/*
code: 'ENOTFOUND',
errno: 'ENOTFOUND',
*/
// expect(err.statusCode).toBe(404);
expect(proxy.failed_requests).toBe(2);
const streamThirdTry = proxy.fetchTarball(tarball);
streamThirdTry.on('error', function (err: VerdaccioError) {
expect(err).not.toBeNull();
expect(err.statusCode).toBe(HTTP_STATUS.INTERNAL_ERROR);
expect(proxy.failed_requests).toBe(2);
expect(err.message).toMatch(API_ERROR.UPLINK_OFFLINE);
done();
});
});
});
});
});
test('not found tarball', (done) => {
nock(domain).get('/jquery/-/jquery-0.0.1.tgz').reply(404);
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
const stream = prox1.fetchTarball('https://registry.npmjs.org/jquery/-/jquery-0.0.1.tgz');
stream.on('error', (response) => {
expect(response).toEqual(ErrorCode.getNotFound(API_ERROR.NOT_FILE_UPLINK));
done();
});
});
test('fail tarball request', (done) => {
nock(domain).get('/jquery/-/jquery-0.0.1.tgz').replyWithError('boom file');
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
const stream = prox1.fetchTarball('https://registry.npmjs.org/jquery/-/jquery-0.0.1.tgz');
stream.on('error', (response) => {
expect(response).toEqual(Error('boom file'));
done();
});
});
test('bad uplink request', (done) => {
nock(domain).get('/jquery/-/jquery-0.0.1.tgz').reply(409);
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
const stream = prox1.fetchTarball('https://registry.npmjs.org/jquery/-/jquery-0.0.1.tgz');
stream.on('error', (response) => {
expect(response).toEqual(ErrorCode.getInternalError(`bad uplink status code: 409`));
done();
});
});
test('content length header mismatch', (done) => {
nock(domain)
.get('/jquery/-/jquery-0.0.1.tgz')
// types does not match here with documentation
// @ts-expect-error
.replyWithFile(201, path.join(__dirname, 'partials/jquery-0.0.1.tgz'), {
[HEADER_TYPE.CONTENT_LENGTH]: 0,
});
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
const stream = prox1.fetchTarball('https://registry.npmjs.org/jquery/-/jquery-0.0.1.tgz');
stream.on('error', (response) => {
expect(response).toEqual(ErrorCode.getInternalError(API_ERROR.CONTENT_MISMATCH));
done();
});
});
});
});
describe('getRemoteMetadata', () => {
describe('basic requests', () => {
test('proxy call with etag', (done) => {
nock(domain)
.get('/jquery')
.reply(
200,
{ body: 'test' },
{
etag: () => `_ref_4444`,
}
);
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
prox1.getRemoteMetadata('jquery', {}, (_error, body, etag) => {
expect(etag).toEqual('_ref_4444');
expect(body).toEqual({ body: 'test' });
done();
});
});
test('proxy call with etag as option', (done) => {
nock(domain)
.get('/jquery')
.reply(
200,
{ body: 'test' },
{
etag: () => `_ref_4444`,
}
);
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
prox1.getRemoteMetadata('jquery', { etag: 'rev_3333' }, (_error, body, etag) => {
expect(etag).toEqual('_ref_4444');
expect(body).toEqual({ body: 'test' });
done();
});
});
test('proxy not found', (done) => {
nock(domain).get('/jquery').reply(404);
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
prox1.getRemoteMetadata('jquery', { etag: 'rev_3333' }, (error) => {
expect(error).toEqual(ErrorCode.getNotFound(API_ERROR.NOT_PACKAGE_UPLINK));
done();
});
});
});
describe('error handling', () => {
test('reply with error', (done) => {
nock(domain).get('/jquery').replyWithError('something awful happened');
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
prox1.getRemoteMetadata('jquery', {}, (error) => {
expect(error).toEqual(new Error('something awful happened'));
done();
});
});
test('reply with bad body json format', (done) => {
nock(domain).get('/jquery').reply(200, 'some-text');
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
prox1.getRemoteMetadata('jquery', {}, (error) => {
expect(error).toEqual(new SyntaxError('Unexpected token s in JSON at position 0'));
done();
});
});
test('400 error proxy call', (done) => {
nock(domain).get('/jquery').reply(409);
const prox1 = new ProxyStorage(defaultRequestOptions, conf);
prox1.getRemoteMetadata('jquery', {}, (error) => {
expect(error.statusCode).toEqual(500);
expect(mockInfo).toHaveBeenCalled();
expect(mockHttp).toHaveBeenCalledWith({
request: { method: 'GET', url: 'https://registry.npmjs.org/jquery' },
status: 409,
});
expect(mockHttp).toHaveBeenCalledWith({
bytes: { in: 0, out: 0 },
err: undefined,
error: undefined,
request: { method: 'GET', url: 'https://registry.npmjs.org/jquery' },
status: 409,
});
done();
});
});
});
});
});