mirror of
https://github.com/ringtools/ringtools-server-ts.git
synced 2024-05-16 05:44:40 +02:00
Convert tests to jest, added tls cert/macaroon file support
This commit is contained in:
parent
c4c7288d39
commit
c6dfc5f8c8
@ -1,6 +1,8 @@
|
||||
PORT=7464
|
||||
ALLOWED_HOSTS=['*']
|
||||
MACAROON=ABC
|
||||
LND_REST_API=localhost:8080
|
||||
REJECT_UNAUTHORIZED=false
|
||||
LND_REST_API_WS=wss://localhost:8080
|
||||
LND_REST_API=https://localhost:8080
|
||||
REJECT_UNAUTHORIZED=0
|
||||
TLS_CERT_BASE64=ABCD=
|
||||
#MACAROON_FILE=readonly.macaroon
|
||||
#TLS_CERT_FILE=tls.cert
|
@ -35,19 +35,22 @@
|
||||
"@types/node": "^17.0.8",
|
||||
"@typescript-eslint/eslint-plugin": "^5.8.1",
|
||||
"@typescript-eslint/parser": "^5.8.1",
|
||||
"axios-mock-adapter": "^1.20.0",
|
||||
"concurrently": "^7.0.0",
|
||||
"eslint": "^8.5.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"fastify-tsconfig": "^1.0.1",
|
||||
"jest": "^27.4.7",
|
||||
"jest-websocket-mock": "^2.2.1",
|
||||
"mock-socket": "^9.1.0",
|
||||
"prettier": "^2.5.1",
|
||||
"ts-jest": "^27.1.2",
|
||||
"ts-node": "^10.4.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "ts-node src/index.ts",
|
||||
"start": "ts-node src/server.ts",
|
||||
"build:ts": "tsc",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"test": "npm run build:ts && tsc -p test/tsconfig.json && tap --no-coverage-map --no-check-coverage --ts test/**/*.test.ts"
|
||||
"test": "jest"
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ export default class ChannelController {
|
||||
.emit('channel', chanInfo);
|
||||
})
|
||||
.catch(() => {
|
||||
console.log('Error sending channel update');
|
||||
console.log(`Error sending channel update for ${channel.chan_id}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -1,4 +1,5 @@
|
||||
import * as https from 'https';
|
||||
import {existsSync, readFileSync} from 'fs';
|
||||
|
||||
import axios from 'axios';
|
||||
import {Subject} from 'rxjs';
|
||||
@ -8,14 +9,39 @@ import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const decodedTlsCert = Buffer.from(
|
||||
let tlsCertData: string;
|
||||
let macaroonData: string;
|
||||
let rejectUnauthorized = true;
|
||||
|
||||
// Check if files exists, otherwise try to read base64 data
|
||||
if (existsSync(process.env.MACAROON_FILE)) {
|
||||
macaroonData = readFileSync(process.env.MACAROON_FILE).toString('hex');
|
||||
} else {
|
||||
macaroonData = process.env.MACAROON || '';
|
||||
}
|
||||
|
||||
if (existsSync(process.env.TLS_CERT_FILE)) {
|
||||
tlsCertData = readFileSync(process.env.TLS_CERT_FILE).toString('ascii');
|
||||
} else {
|
||||
const tlsCertData = Buffer.from(
|
||||
process.env.TLS_CERT_BASE64 || '',
|
||||
'base64',
|
||||
).toString('ascii');
|
||||
).toString('ascii');
|
||||
}
|
||||
|
||||
if (tlsCertData === '' || macaroonData === '') {
|
||||
throw new Error(
|
||||
'TLS Certificate or Macaroon could not be loaded, this is required to run ringtools-ts-server',
|
||||
);
|
||||
}
|
||||
|
||||
if (process.env.REJECT_UNAUTHORIZED) {
|
||||
rejectUnauthorized = Boolean(Number(process.env.REJECT_UNAUTHORIZED));
|
||||
}
|
||||
|
||||
const httpsAgent = new https.Agent({
|
||||
rejectUnauthorized: Boolean(process.env.REJECT_UNAUTHORIZED) || true,
|
||||
ca: decodedTlsCert,
|
||||
rejectUnauthorized,
|
||||
ca: tlsCertData,
|
||||
});
|
||||
|
||||
axios.defaults.httpsAgent = httpsAgent;
|
||||
@ -40,20 +66,24 @@ export class LndService {
|
||||
channelUpdateSubject: Subject<any> = new Subject();
|
||||
nodeUpdateSubject: Subject<any> = new Subject();
|
||||
closedChannelSubject: Subject<any> = new Subject();
|
||||
lndRestApiWsUrl!: string;
|
||||
lndRestApiUrl!: string;
|
||||
|
||||
macaroon!: string;
|
||||
|
||||
constructor() {}
|
||||
|
||||
@Initializer()
|
||||
init() {
|
||||
this.lndRestApiUrl = process.env.LND_REST_API || 'localhost:8080';
|
||||
this.macaroon = process.env.MACAROON || '';
|
||||
this.lndRestApiWsUrl = process.env.LND_REST_API_WS || 'ws://localhost:8080';
|
||||
this.lndRestApiUrl = process.env.LND_REST_API || 'http://localhost:8080';
|
||||
|
||||
this.macaroon = macaroonData;
|
||||
this.ws = new WebSocket(
|
||||
`wss://${this.lndRestApiUrl}/v1/graph/subscribe?method=GET`,
|
||||
`${this.lndRestApiWsUrl}/v1/graph/subscribe?method=GET`,
|
||||
{
|
||||
rejectUnauthorized: Boolean(process.env.REJECT_UNAUTHORIZED) || true,
|
||||
ca: decodedTlsCert,
|
||||
rejectUnauthorized,
|
||||
ca: tlsCertData,
|
||||
headers: {
|
||||
'Grpc-Metadata-Macaroon': this.macaroon,
|
||||
},
|
||||
@ -99,7 +129,7 @@ export class LndService {
|
||||
}
|
||||
|
||||
private doLndGet(endPoint: string) {
|
||||
return axios.get(`https://${this.lndRestApiUrl}/${endPoint}`, {
|
||||
return axios.get(`${this.lndRestApiUrl}/${endPoint}`, {
|
||||
responseType: 'json',
|
||||
|
||||
headers: {
|
||||
|
@ -1,13 +1,14 @@
|
||||
import tap from 'tap';
|
||||
|
||||
import {testBuild} from './helper';
|
||||
|
||||
tap.test('requests the "/" route', async (t: any) => {
|
||||
const app = await testBuild(t);
|
||||
|
||||
const response = await app.inject({
|
||||
describe('app tests', () => {
|
||||
const app = testBuild();
|
||||
|
||||
test('requests the "/" route', async () => {
|
||||
const res = await app.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
});
|
||||
t.equal(response.statusCode, 200, 'returns a status code of 200');
|
||||
expect(res.statusCode).toBe(404);
|
||||
});
|
||||
});
|
||||
|
@ -1,18 +1,14 @@
|
||||
import tap from 'tap';
|
||||
import {testBuild} from '../helper';
|
||||
|
||||
import {testBuild} from '../../test/helper';
|
||||
|
||||
tap.test('Non-numeric channels should return 404', async (t: any) => {
|
||||
t.plan(1);
|
||||
|
||||
const app = await testBuild(t);
|
||||
describe('channel controller tests', () => {
|
||||
const app = testBuild();
|
||||
|
||||
test('Non-numeric channels should return 404', async () => {
|
||||
const response = await app.inject({
|
||||
url: '/channel/abcdefg',
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
t.equal(response.statusCode, 404, 'returns a status code of 404');
|
||||
|
||||
t.teardown(() => app.close());
|
||||
expect(response.statusCode).toEqual(404);
|
||||
});
|
||||
});
|
||||
|
@ -1,18 +1,14 @@
|
||||
import tap from 'tap';
|
||||
import {testBuild} from '../helper';
|
||||
|
||||
import {testBuild} from '../../test/helper';
|
||||
|
||||
tap.test('Main controller should do nothing', async (t: any) => {
|
||||
t.plan(1);
|
||||
|
||||
const app = await testBuild(t);
|
||||
describe('main controller tests', () => {
|
||||
const app = testBuild();
|
||||
|
||||
test('Main controller should do nothing', async () => {
|
||||
const response = await app.inject({
|
||||
url: '/',
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
t.equal(response.statusCode, 404, 'returns a status code of 404');
|
||||
|
||||
t.teardown(() => app.close());
|
||||
expect(response.statusCode).toBe(404);
|
||||
});
|
||||
});
|
||||
|
@ -1,42 +1,73 @@
|
||||
import tap from 'tap';
|
||||
import {mock, testBuild} from '../helper';
|
||||
|
||||
import {testBuild} from '../helper';
|
||||
describe('node controller tests', () => {
|
||||
const app = testBuild();
|
||||
|
||||
tap.test('Too short pubkeys should return 404', async (t: any) => {
|
||||
t.plan(1);
|
||||
const app = await testBuild(t);
|
||||
const response = await app.inject({
|
||||
test('Too short pubkeys should return 404', (done) => {
|
||||
app
|
||||
.inject({
|
||||
url: '/node/abcdefg',
|
||||
method: 'GET',
|
||||
})
|
||||
.then((response) => {
|
||||
expect(response.statusCode).toBe(404);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
t.equal(response.statusCode, 404, 'returns a status code of 404');
|
||||
|
||||
t.teardown(() => app.close());
|
||||
});
|
||||
|
||||
tap.test('Too long pubkeys should return 404', async (t: any) => {
|
||||
t.plan(1);
|
||||
const app = await testBuild(t);
|
||||
const response = await app.inject({
|
||||
test('Too long pubkeys should return 404', (done) => {
|
||||
app
|
||||
.inject({
|
||||
url: '/node/0380b3dbdf090cacee19eb4dc7a82630bd3de8b12608dd7bee971fb3cd2a5ae2fcd',
|
||||
method: 'GET',
|
||||
})
|
||||
.then((response) => {
|
||||
expect(response.statusCode).toBe(404);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
t.equal(response.statusCode, 404, 'returns a status code of 404');
|
||||
|
||||
t.teardown(() => app.close());
|
||||
});
|
||||
|
||||
tap.test('Node URI should return 404', async (t: any) => {
|
||||
t.plan(1);
|
||||
const app = await testBuild(t);
|
||||
const response = await app.inject({
|
||||
test('Node URI should return 404', (done) => {
|
||||
app
|
||||
.inject({
|
||||
url: '/node/0380b3dbdf090cacee19eb4dc7a82630bd3de8b12608dd7bee971fb3cd2a5ae2fc@[2a04:52c0:103:c1e3::1]:9735',
|
||||
method: 'GET',
|
||||
})
|
||||
.then((response) => {
|
||||
expect(response.statusCode).toBe(404);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
t.equal(response.statusCode, 404, 'returns a status code of 404');
|
||||
test('Node URI should return 404', (done) => {
|
||||
app
|
||||
.inject({
|
||||
url: '/node/0380b3dbdf090cacee19eb4dc7a82630bd3de8b12608dd7bee971fb3cd2a5ae2fc@[2a04:52c0:103:c1e3::1]:9735',
|
||||
method: 'GET',
|
||||
})
|
||||
.then((response) => {
|
||||
expect(response.statusCode).toBe(404);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
t.teardown(() => app.close());
|
||||
|
||||
// FIXME: Fix WebSocket mock
|
||||
// test('Valid Node URI should give nodeInfo', (done) => {
|
||||
// mock.onGet(/^\/node\/\d+/).reply((config) => {
|
||||
// console.log("Mock!", config.url);
|
||||
// return [200, {}]
|
||||
// });
|
||||
|
||||
|
||||
// app
|
||||
// .inject({
|
||||
// url: '/node/0205a19356bbb7482057356aef070285a2ce6141d2448545210e9d575b57eddd37',
|
||||
// method: 'GET',
|
||||
// })
|
||||
// .then((response) => {
|
||||
// expect(response.statusCode).toBe(200);
|
||||
// done();
|
||||
// });
|
||||
// });
|
||||
});
|
||||
|
@ -2,37 +2,42 @@
|
||||
import Fastify from 'fastify'
|
||||
import fp from 'fastify-plugin'
|
||||
import { build } from '../src/app'
|
||||
import * as tap from 'tap';
|
||||
import MockAdapter from "axios-mock-adapter";
|
||||
import axios from "axios";
|
||||
|
||||
export type Test = typeof tap['Test']['prototype'];
|
||||
process.env['REJECT_UNAUTHORIZED'] = '0';
|
||||
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
|
||||
process.env['LND_REST_API_WS'] = 'ws://localhost:8080';
|
||||
|
||||
const edgeMockData = {"channel_id":"760383758935523329","chan_point":"0000000000000000000000000000000000000000000000000000000000000000:0","last_update":1642475331,"node1_pub":"0205a19356bbb7482057356aef070285a2ce6141d2448545210e9d575b57eddd37","node2_pub":"03d1b19ebc6cdce5685bad391f266d077f0cacd2e5c1f46824e1427ce7dba2f630","capacity":"0","node1_policy":{"time_lock_delta":42,"min_htlc":"1000","fee_base_msat":"1","fee_rate_milli_msat":"100","disabled":false,"max_htlc_msat":"990000000","last_update":1642475331},"node2_policy":{"time_lock_delta":40,"min_htlc":"1000","fee_base_msat":"0","fee_rate_milli_msat":"100","disabled":false,"max_htlc_msat":"990000000","last_update":1642460307}};
|
||||
|
||||
// Fill in this config with all the configurations
|
||||
// needed for testing the application
|
||||
async function config () {
|
||||
return {}
|
||||
}
|
||||
|
||||
// Automatically build and tear down our instance
|
||||
async function testBuild (t: Test) {
|
||||
const app = Fastify()
|
||||
let mock;
|
||||
|
||||
// fastify-plugin ensures that all decorators
|
||||
// are exposed for testing purposes, this is
|
||||
// different from the production setup
|
||||
void app.register(fp(build), await config())
|
||||
export function testBuild() {
|
||||
const app = Fastify();
|
||||
|
||||
beforeAll(async () => {
|
||||
void app.register(fp(build), await config());
|
||||
await app.ready();
|
||||
});
|
||||
|
||||
// Tear down our app after we are done
|
||||
t.teardown(async() => {
|
||||
if (app)
|
||||
await app.close()
|
||||
})
|
||||
beforeEach(() => {
|
||||
mock = new MockAdapter(axios);
|
||||
mock.onAny(/^\/v1\/graph\/edge\/\d+/, edgeMockData);
|
||||
});
|
||||
|
||||
return app
|
||||
afterEach(() => {
|
||||
if (mock)
|
||||
mock.reset();
|
||||
});
|
||||
|
||||
afterAll(() => app.close());
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
export {
|
||||
config,
|
||||
testBuild
|
||||
}
|
||||
export { mock };
|
@ -1,9 +1,9 @@
|
||||
import tap from 'tap';
|
||||
import { LndService } from '../../src/services/lnd-service';
|
||||
|
||||
tap.test('LndService should instantiate', async (t: any) => {
|
||||
t.plan(1)
|
||||
describe('LndService tests', () => {
|
||||
test('LndService should instantiate', async () => {
|
||||
const lndService = new LndService();
|
||||
|
||||
t.type(lndService, LndService);
|
||||
expect(lndService).toBeInstanceOf(LndService);
|
||||
});
|
||||
});
|
33
yarn.lock
33
yarn.lock
@ -1443,6 +1443,15 @@ axe-core@^4.3.5:
|
||||
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.5.tgz#78d6911ba317a8262bfee292aeafcc1e04b49cc5"
|
||||
integrity sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==
|
||||
|
||||
axios-mock-adapter@^1.20.0:
|
||||
version "1.20.0"
|
||||
resolved "https://registry.yarnpkg.com/axios-mock-adapter/-/axios-mock-adapter-1.20.0.tgz#21f5b4b625306f43e8c05673616719da86e20dcb"
|
||||
integrity sha512-shZRhTjLP0WWdcvHKf3rH3iW9deb3UdKbdnKUoHmmsnBhVXN3sjPJM6ZvQ2r/ywgvBVQrMnjrSyQab60G1sr2w==
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.3"
|
||||
is-blob "^2.1.0"
|
||||
is-buffer "^2.0.5"
|
||||
|
||||
axios@^0.24.0:
|
||||
version "0.24.0"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6"
|
||||
@ -3484,6 +3493,11 @@ is-binary-path@~2.1.0:
|
||||
dependencies:
|
||||
binary-extensions "^2.0.0"
|
||||
|
||||
is-blob@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-blob/-/is-blob-2.1.0.tgz#e36cd82c90653f1e1b930f11baf9c64216a05385"
|
||||
integrity sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw==
|
||||
|
||||
is-boolean-object@^1.1.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719"
|
||||
@ -3492,6 +3506,11 @@ is-boolean-object@^1.1.0:
|
||||
call-bind "^1.0.2"
|
||||
has-tostringtag "^1.0.0"
|
||||
|
||||
is-buffer@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191"
|
||||
integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==
|
||||
|
||||
is-callable@^1.1.4, is-callable@^1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945"
|
||||
@ -3802,7 +3821,7 @@ jest-config@^27.4.7:
|
||||
pretty-format "^27.4.6"
|
||||
slash "^3.0.0"
|
||||
|
||||
jest-diff@^27.0.0, jest-diff@^27.4.6:
|
||||
jest-diff@^27.0.0, jest-diff@^27.0.2, jest-diff@^27.4.6:
|
||||
version "27.4.6"
|
||||
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.4.6.tgz#93815774d2012a2cbb6cf23f84d48c7a2618f98d"
|
||||
integrity sha512-zjaB0sh0Lb13VyPsd92V7HkqF6yKRH9vm33rwBt7rPYrpQvS1nCvlIy2pICbKta+ZjWngYLNn4cCK4nyZkjS/w==
|
||||
@ -4108,6 +4127,13 @@ jest-watcher@^27.4.6:
|
||||
jest-util "^27.4.2"
|
||||
string-length "^4.0.1"
|
||||
|
||||
jest-websocket-mock@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-websocket-mock/-/jest-websocket-mock-2.2.1.tgz#db4fc63733c9fc549c1fd0f79e6db8b3f947af1d"
|
||||
integrity sha512-fhsGLXrPfs06PhHoxqOSA9yZ6Rb4qYrf4Wcm7/nfRzjlrf1gIeuhYUkzMRjjE0TMQ37SwkmeLanwrZY4ZaNp8g==
|
||||
dependencies:
|
||||
jest-diff "^27.0.2"
|
||||
|
||||
jest-worker@^27.4.6:
|
||||
version "27.4.6"
|
||||
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.6.tgz#5d2d93db419566cb680752ca0792780e71b3273e"
|
||||
@ -4515,6 +4541,11 @@ mkdirp@^1.0.4:
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
|
||||
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
|
||||
|
||||
mock-socket@^9.1.0:
|
||||
version "9.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mock-socket/-/mock-socket-9.1.0.tgz#583f5984aa5759909c1b0f43676c669060722596"
|
||||
integrity sha512-zNsH8h0D7buVMDZ2X1GyFYso9A1X1Co/TDfFs0AIKhSLkJeh381HYESNl/mL6BzmQpNOxZVnNhEDS1OWBrS+cQ==
|
||||
|
||||
mri@1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a"
|
||||
|
Loading…
Reference in New Issue
Block a user