mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: add support for cdnPrefix for static assets (#1191)
This commit is contained in:
		
							parent
							
								
									2b59a4219a
								
							
						
					
					
						commit
						26b7da8b5c
					
				@ -63,6 +63,7 @@ Object {
 | 
			
		||||
  "secureHeaders": false,
 | 
			
		||||
  "server": Object {
 | 
			
		||||
    "baseUriPath": "",
 | 
			
		||||
    "cdnPrefix": undefined,
 | 
			
		||||
    "enableRequestLogger": false,
 | 
			
		||||
    "gracefulShutdownEnable": true,
 | 
			
		||||
    "gracefulShutdownTimeout": 1000,
 | 
			
		||||
 | 
			
		||||
@ -11,32 +11,32 @@ jest.mock(
 | 
			
		||||
        },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const getApp = require('./app');
 | 
			
		||||
const getApp = require('./app').default;
 | 
			
		||||
 | 
			
		||||
test('should not throw when valid config', () => {
 | 
			
		||||
test('should not throw when valid config', async () => {
 | 
			
		||||
    const config = createTestConfig();
 | 
			
		||||
    const app = getApp(config, {}, {});
 | 
			
		||||
    const app = await getApp(config, {}, {});
 | 
			
		||||
    expect(typeof app.listen).toBe('function');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('should call preHook', () => {
 | 
			
		||||
test('should call preHook', async () => {
 | 
			
		||||
    let called = 0;
 | 
			
		||||
    const config = createTestConfig({
 | 
			
		||||
        preHook: () => {
 | 
			
		||||
            called++;
 | 
			
		||||
        },
 | 
			
		||||
    });
 | 
			
		||||
    getApp(config, {}, {});
 | 
			
		||||
    await getApp(config, {}, {});
 | 
			
		||||
    expect(called).toBe(1);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('should call preRouterHook', () => {
 | 
			
		||||
test('should call preRouterHook', async () => {
 | 
			
		||||
    let called = 0;
 | 
			
		||||
    const config = createTestConfig({
 | 
			
		||||
        preRouterHook: () => {
 | 
			
		||||
            called++;
 | 
			
		||||
        },
 | 
			
		||||
    });
 | 
			
		||||
    getApp(config, {}, {});
 | 
			
		||||
    await getApp(config, {}, {});
 | 
			
		||||
    expect(called).toBe(1);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
import { publicFolder } from 'unleash-frontend';
 | 
			
		||||
import fs from 'fs';
 | 
			
		||||
import express, { Application, RequestHandler } from 'express';
 | 
			
		||||
import cors from 'cors';
 | 
			
		||||
import compression from 'compression';
 | 
			
		||||
@ -22,23 +21,19 @@ import ossAuthentication from './middleware/oss-authentication';
 | 
			
		||||
import noAuthentication from './middleware/no-authentication';
 | 
			
		||||
import secureHeaders from './middleware/secure-headers';
 | 
			
		||||
 | 
			
		||||
import { rewriteHTML } from './util/rewriteHTML';
 | 
			
		||||
import { loadIndexHTML } from './util/load-index-html';
 | 
			
		||||
 | 
			
		||||
export default function getApp(
 | 
			
		||||
export default async function getApp(
 | 
			
		||||
    config: IUnleashConfig,
 | 
			
		||||
    stores: IUnleashStores,
 | 
			
		||||
    services: IUnleashServices,
 | 
			
		||||
    unleashSession?: RequestHandler,
 | 
			
		||||
): Application {
 | 
			
		||||
): Promise<Application> {
 | 
			
		||||
    const app = express();
 | 
			
		||||
 | 
			
		||||
    const baseUriPath = config.server.baseUriPath || '';
 | 
			
		||||
 | 
			
		||||
    let indexHTML = fs
 | 
			
		||||
        .readFileSync(path.join(publicFolder, 'index.html'))
 | 
			
		||||
        .toString();
 | 
			
		||||
 | 
			
		||||
    indexHTML = rewriteHTML(indexHTML, baseUriPath);
 | 
			
		||||
    let indexHTML = await loadIndexHTML(config, publicFolder);
 | 
			
		||||
 | 
			
		||||
    app.set('trust proxy', true);
 | 
			
		||||
    app.disable('x-powered-by');
 | 
			
		||||
@ -68,7 +63,7 @@ export default function getApp(
 | 
			
		||||
    app.use(secureHeaders(config));
 | 
			
		||||
    app.use(express.urlencoded({ extended: true }));
 | 
			
		||||
    app.use(favicon(path.join(publicFolder, 'favicon.ico')));
 | 
			
		||||
 | 
			
		||||
    app.use(baseUriPath, favicon(path.join(publicFolder, 'favicon.ico')));
 | 
			
		||||
    app.use(baseUriPath, express.static(publicFolder, { index: false }));
 | 
			
		||||
 | 
			
		||||
    if (config.enableOAS) {
 | 
			
		||||
@ -151,4 +146,3 @@ export default function getApp(
 | 
			
		||||
    });
 | 
			
		||||
    return app;
 | 
			
		||||
}
 | 
			
		||||
module.exports = getApp;
 | 
			
		||||
 | 
			
		||||
@ -107,6 +107,7 @@ const defaultServerOption: IServerOption = {
 | 
			
		||||
    host: process.env.HTTP_HOST,
 | 
			
		||||
    port: safeNumber(process.env.HTTP_PORT || process.env.PORT, 4242),
 | 
			
		||||
    baseUriPath: formatBaseUri(process.env.BASE_URI_PATH),
 | 
			
		||||
    cdnPrefix: process.env.CDN_PREFIX,
 | 
			
		||||
    unleashUrl: process.env.UNLEASH_URL || 'http://localhost:4242',
 | 
			
		||||
    serverMetrics: true,
 | 
			
		||||
    keepAliveTimeout: minutesToMilliseconds(1),
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@ import getApp from '../app';
 | 
			
		||||
import User from '../types/user';
 | 
			
		||||
import sessionDb from './session-db';
 | 
			
		||||
 | 
			
		||||
function getSetup(preRouterHook) {
 | 
			
		||||
async function getSetup(preRouterHook) {
 | 
			
		||||
    const base = `/random${Math.round(Math.random() * 1000)}`;
 | 
			
		||||
    const config = createTestConfig({
 | 
			
		||||
        server: { baseUriPath: base },
 | 
			
		||||
@ -23,7 +23,7 @@ function getSetup(preRouterHook) {
 | 
			
		||||
    const stores = createStores();
 | 
			
		||||
    const services = createServices(stores, config);
 | 
			
		||||
    const unleashSession = sessionDb(config, undefined);
 | 
			
		||||
    const app = getApp(config, stores, services, unleashSession);
 | 
			
		||||
    const app = await getApp(config, stores, services, unleashSession);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        base,
 | 
			
		||||
@ -31,17 +31,17 @@ function getSetup(preRouterHook) {
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
test('should return 401 when missing user', () => {
 | 
			
		||||
test('should return 401 when missing user', async () => {
 | 
			
		||||
    expect.assertions(0);
 | 
			
		||||
    const { base, request } = getSetup(() => {});
 | 
			
		||||
    const { base, request } = await getSetup(() => {});
 | 
			
		||||
 | 
			
		||||
    return request.get(`${base}/api/protectedResource`).expect(401);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('should return 200 when user exists', () => {
 | 
			
		||||
test('should return 200 when user exists', async () => {
 | 
			
		||||
    expect.assertions(0);
 | 
			
		||||
    const user = new User({ id: 1, email: 'some@mail.com' });
 | 
			
		||||
    const { base, request } = getSetup((app) =>
 | 
			
		||||
    const { base, request } = await getSetup((app) =>
 | 
			
		||||
        app.use((req, res, next) => {
 | 
			
		||||
            req.user = user;
 | 
			
		||||
            next();
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,7 @@ const uiConfig = {
 | 
			
		||||
    slogan: 'hello',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function getSetup() {
 | 
			
		||||
async function getSetup() {
 | 
			
		||||
    const base = `/random${Math.round(Math.random() * 1000)}`;
 | 
			
		||||
    const config = createTestConfig({
 | 
			
		||||
        server: { baseUriPath: base },
 | 
			
		||||
@ -19,7 +19,7 @@ function getSetup() {
 | 
			
		||||
    const stores = createStores();
 | 
			
		||||
    const services = createServices(stores, config);
 | 
			
		||||
 | 
			
		||||
    const app = getApp(config, stores, services);
 | 
			
		||||
    const app = await getApp(config, stores, services);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        base,
 | 
			
		||||
@ -36,8 +36,8 @@ let request;
 | 
			
		||||
let base;
 | 
			
		||||
let destroy;
 | 
			
		||||
 | 
			
		||||
beforeEach(() => {
 | 
			
		||||
    const setup = getSetup();
 | 
			
		||||
beforeEach(async () => {
 | 
			
		||||
    const setup = await getSetup();
 | 
			
		||||
    request = setup.request;
 | 
			
		||||
    base = setup.base;
 | 
			
		||||
    destroy = setup.destroy;
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ import { createServices } from '../../services';
 | 
			
		||||
import permissions from '../../../test/fixtures/permissions';
 | 
			
		||||
import getApp from '../../app';
 | 
			
		||||
 | 
			
		||||
function getSetup() {
 | 
			
		||||
async function getSetup() {
 | 
			
		||||
    const base = `/random${Math.round(Math.random() * 1000)}`;
 | 
			
		||||
    const perms = permissions();
 | 
			
		||||
    const config = createTestConfig({
 | 
			
		||||
@ -15,7 +15,7 @@ function getSetup() {
 | 
			
		||||
    const stores = createStores();
 | 
			
		||||
 | 
			
		||||
    const services = createServices(stores, config);
 | 
			
		||||
    const app = getApp(config, stores, services);
 | 
			
		||||
    const app = await getApp(config, stores, services);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        base,
 | 
			
		||||
@ -32,8 +32,8 @@ let base;
 | 
			
		||||
let request;
 | 
			
		||||
let destroy;
 | 
			
		||||
 | 
			
		||||
beforeEach(() => {
 | 
			
		||||
    const setup = getSetup();
 | 
			
		||||
beforeEach(async () => {
 | 
			
		||||
    const setup = await getSetup();
 | 
			
		||||
    base = setup.base;
 | 
			
		||||
    request = setup.request;
 | 
			
		||||
    destroy = setup.destroy;
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ import { createServices } from '../../services';
 | 
			
		||||
import permissions from '../../../test/fixtures/permissions';
 | 
			
		||||
import getApp from '../../app';
 | 
			
		||||
 | 
			
		||||
function getSetup() {
 | 
			
		||||
async function getSetup() {
 | 
			
		||||
    const base = `/random${Math.round(Math.random() * 1000)}`;
 | 
			
		||||
    const stores = createStores();
 | 
			
		||||
    const perms = permissions();
 | 
			
		||||
@ -15,7 +15,7 @@ function getSetup() {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const services = createServices(stores, config);
 | 
			
		||||
    const app = getApp(config, stores, services);
 | 
			
		||||
    const app = await getApp(config, stores, services);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        base,
 | 
			
		||||
@ -23,9 +23,9 @@ function getSetup() {
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
test('should render html preview of template', () => {
 | 
			
		||||
test('should render html preview of template', async () => {
 | 
			
		||||
    expect.assertions(0);
 | 
			
		||||
    const { request, base } = getSetup();
 | 
			
		||||
    const { request, base } = await getSetup();
 | 
			
		||||
    return request
 | 
			
		||||
        .get(
 | 
			
		||||
            `${base}/api/admin/email/preview/html/reset-password?name=Test%20Test`,
 | 
			
		||||
@ -35,9 +35,9 @@ test('should render html preview of template', () => {
 | 
			
		||||
        .expect((res) => 'Test Test' in res.body);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('should render text preview of template', () => {
 | 
			
		||||
test('should render text preview of template', async () => {
 | 
			
		||||
    expect.assertions(0);
 | 
			
		||||
    const { request, base } = getSetup();
 | 
			
		||||
    const { request, base } = await getSetup();
 | 
			
		||||
    return request
 | 
			
		||||
        .get(
 | 
			
		||||
            `${base}/api/admin/email/preview/text/reset-password?name=Test%20Test`,
 | 
			
		||||
@ -47,9 +47,9 @@ test('should render text preview of template', () => {
 | 
			
		||||
        .expect((res) => 'Test Test' in res.body);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('Requesting a non-existing template should yield 404', () => {
 | 
			
		||||
test('Requesting a non-existing template should yield 404', async () => {
 | 
			
		||||
    expect.assertions(0);
 | 
			
		||||
    const { request, base } = getSetup();
 | 
			
		||||
    const { request, base } = await getSetup();
 | 
			
		||||
    return request
 | 
			
		||||
        .get(`${base}/api/admin/email/preview/text/some-non-existing-template`)
 | 
			
		||||
        .expect(404);
 | 
			
		||||
 | 
			
		||||
@ -6,21 +6,21 @@ import createStores from '../../../test/fixtures/store';
 | 
			
		||||
 | 
			
		||||
import getApp from '../../app';
 | 
			
		||||
 | 
			
		||||
function getSetup() {
 | 
			
		||||
async function getSetup() {
 | 
			
		||||
    const base = `/random${Math.round(Math.random() * 1000)}`;
 | 
			
		||||
    const stores = createStores();
 | 
			
		||||
    const config = createTestConfig({
 | 
			
		||||
        server: { baseUriPath: base },
 | 
			
		||||
    });
 | 
			
		||||
    const services = createServices(stores, config);
 | 
			
		||||
    const app = getApp(config, stores, services);
 | 
			
		||||
    const app = await getApp(config, stores, services);
 | 
			
		||||
 | 
			
		||||
    return { base, eventStore: stores.eventStore, request: supertest(app) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
test('should get empty events list via admin', () => {
 | 
			
		||||
test('should get empty events list via admin', async () => {
 | 
			
		||||
    expect.assertions(1);
 | 
			
		||||
    const { request, base } = getSetup();
 | 
			
		||||
    const { request, base } = await getSetup();
 | 
			
		||||
    return request
 | 
			
		||||
        .get(`${base}/api/admin/events`)
 | 
			
		||||
        .expect('Content-Type', /json/)
 | 
			
		||||
 | 
			
		||||
@ -5,14 +5,14 @@ import getApp from '../../app';
 | 
			
		||||
import { createTestConfig } from '../../../test/config/test-config';
 | 
			
		||||
import { createServices } from '../../services';
 | 
			
		||||
 | 
			
		||||
function getSetup() {
 | 
			
		||||
async function getSetup() {
 | 
			
		||||
    const stores = createStores();
 | 
			
		||||
    const perms = permissions();
 | 
			
		||||
    const config = createTestConfig({
 | 
			
		||||
        preRouterHook: perms.hook,
 | 
			
		||||
    });
 | 
			
		||||
    const services = createServices(stores, config);
 | 
			
		||||
    const app = getApp(config, stores, services);
 | 
			
		||||
    const app = await getApp(config, stores, services);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        request: supertest(app),
 | 
			
		||||
@ -30,8 +30,8 @@ let stores;
 | 
			
		||||
let request;
 | 
			
		||||
let destroy;
 | 
			
		||||
 | 
			
		||||
beforeEach(() => {
 | 
			
		||||
    const setup = getSetup();
 | 
			
		||||
beforeEach(async () => {
 | 
			
		||||
    const setup = await getSetup();
 | 
			
		||||
    stores = setup.stores;
 | 
			
		||||
    request = setup.request;
 | 
			
		||||
    destroy = setup.destroy;
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@ import { createServices } from '../../services';
 | 
			
		||||
 | 
			
		||||
let destroy;
 | 
			
		||||
 | 
			
		||||
function getSetup() {
 | 
			
		||||
async function getSetup() {
 | 
			
		||||
    const randomBase = `/random${Math.round(Math.random() * 1000)}`;
 | 
			
		||||
    const perms = permissions();
 | 
			
		||||
    const stores = createStores();
 | 
			
		||||
@ -16,7 +16,7 @@ function getSetup() {
 | 
			
		||||
        preRouterHook: perms.hook,
 | 
			
		||||
    });
 | 
			
		||||
    const services = createServices(stores, config);
 | 
			
		||||
    const app = getApp(config, stores, services);
 | 
			
		||||
    const app = await getApp(config, stores, services);
 | 
			
		||||
 | 
			
		||||
    destroy = () => {
 | 
			
		||||
        services.versionService.destroy();
 | 
			
		||||
@ -36,8 +36,8 @@ afterEach(() => {
 | 
			
		||||
    destroy();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('add version numbers for /strategies', () => {
 | 
			
		||||
    const { request, base } = getSetup();
 | 
			
		||||
test('add version numbers for /strategies', async () => {
 | 
			
		||||
    const { request, base } = await getSetup();
 | 
			
		||||
    return request
 | 
			
		||||
        .get(`${base}/api/admin/strategies`)
 | 
			
		||||
        .expect('Content-Type', /json/)
 | 
			
		||||
@ -47,8 +47,8 @@ test('add version numbers for /strategies', () => {
 | 
			
		||||
        });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('require a name when creating a new strategy', () => {
 | 
			
		||||
    const { request, base } = getSetup();
 | 
			
		||||
test('require a name when creating a new strategy', async () => {
 | 
			
		||||
    const { request, base } = await getSetup();
 | 
			
		||||
    return request
 | 
			
		||||
        .post(`${base}/api/admin/strategies`)
 | 
			
		||||
        .send({})
 | 
			
		||||
@ -60,8 +60,8 @@ test('require a name when creating a new strategy', () => {
 | 
			
		||||
        });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('require parameters array when creating a new stratey', () => {
 | 
			
		||||
    const { request, base } = getSetup();
 | 
			
		||||
test('require parameters array when creating a new strategy', async () => {
 | 
			
		||||
    const { request, base } = await getSetup();
 | 
			
		||||
    return request
 | 
			
		||||
        .post(`${base}/api/admin/strategies`)
 | 
			
		||||
        .send({ name: 'TestStrat' })
 | 
			
		||||
@ -74,15 +74,15 @@ test('require parameters array when creating a new stratey', () => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('create a new strategy with empty parameters', async () => {
 | 
			
		||||
    const { request, base } = getSetup();
 | 
			
		||||
    const { request, base } = await getSetup();
 | 
			
		||||
    return request
 | 
			
		||||
        .post(`${base}/api/admin/strategies`)
 | 
			
		||||
        .send({ name: 'TestStrat', parameters: [] })
 | 
			
		||||
        .expect(201);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('not be possible to override name', () => {
 | 
			
		||||
    const { request, base, strategyStore } = getSetup();
 | 
			
		||||
test('not be possible to override name', async () => {
 | 
			
		||||
    const { request, base, strategyStore } = await getSetup();
 | 
			
		||||
    strategyStore.createStrategy({ name: 'Testing', parameters: [] });
 | 
			
		||||
 | 
			
		||||
    return request
 | 
			
		||||
@ -91,8 +91,8 @@ test('not be possible to override name', () => {
 | 
			
		||||
        .expect(409);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('update strategy', () => {
 | 
			
		||||
    const { request, base, strategyStore } = getSetup();
 | 
			
		||||
test('update strategy', async () => {
 | 
			
		||||
    const { request, base, strategyStore } = await getSetup();
 | 
			
		||||
    const name = 'AnotherStrat';
 | 
			
		||||
    strategyStore.createStrategy({ name, parameters: [] });
 | 
			
		||||
 | 
			
		||||
@ -102,8 +102,8 @@ test('update strategy', () => {
 | 
			
		||||
        .expect(200);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('not update unknown strategy', () => {
 | 
			
		||||
    const { request, base } = getSetup();
 | 
			
		||||
test('not update unknown strategy', async () => {
 | 
			
		||||
    const { request, base } = await getSetup();
 | 
			
		||||
    const name = 'UnknownStrat';
 | 
			
		||||
    return request
 | 
			
		||||
        .put(`${base}/api/admin/strategies/${name}`)
 | 
			
		||||
@ -111,8 +111,8 @@ test('not update unknown strategy', () => {
 | 
			
		||||
        .expect(404);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('validate format when updating strategy', () => {
 | 
			
		||||
    const { request, base, strategyStore } = getSetup();
 | 
			
		||||
test('validate format when updating strategy', async () => {
 | 
			
		||||
    const { request, base, strategyStore } = await getSetup();
 | 
			
		||||
    const name = 'AnotherStrat';
 | 
			
		||||
    strategyStore.createStrategy({ name, parameters: [] });
 | 
			
		||||
 | 
			
		||||
@ -122,16 +122,16 @@ test('validate format when updating strategy', () => {
 | 
			
		||||
        .expect(400);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('editable=false will stop delete request', () => {
 | 
			
		||||
test('editable=false will stop delete request', async () => {
 | 
			
		||||
    jest.spyOn(global.console, 'error').mockImplementation(() => jest.fn());
 | 
			
		||||
    const { request, base } = getSetup();
 | 
			
		||||
    const { request, base } = await getSetup();
 | 
			
		||||
    const name = 'default';
 | 
			
		||||
    return request.delete(`${base}/api/admin/strategies/${name}`).expect(500);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('editable=false will stop edit request', () => {
 | 
			
		||||
test('editable=false will stop edit request', async () => {
 | 
			
		||||
    jest.spyOn(global.console, 'error').mockImplementation(() => jest.fn());
 | 
			
		||||
    const { request, base } = getSetup();
 | 
			
		||||
    const { request, base } = await getSetup();
 | 
			
		||||
    const name = 'default';
 | 
			
		||||
    return request
 | 
			
		||||
        .put(`${base}/api/admin/strategies/${name}`)
 | 
			
		||||
@ -139,8 +139,8 @@ test('editable=false will stop edit request', () => {
 | 
			
		||||
        .expect(500);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('editable=true will allow delete request', () => {
 | 
			
		||||
    const { request, base, strategyStore } = getSetup();
 | 
			
		||||
test('editable=true will allow delete request', async () => {
 | 
			
		||||
    const { request, base, strategyStore } = await getSetup();
 | 
			
		||||
    const name = 'deleteStrat';
 | 
			
		||||
    strategyStore.createStrategy({ name, parameters: [] });
 | 
			
		||||
 | 
			
		||||
@ -150,8 +150,8 @@ test('editable=true will allow delete request', () => {
 | 
			
		||||
        .expect(200);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('editable=true will allow edit request', () => {
 | 
			
		||||
    const { request, base, strategyStore } = getSetup();
 | 
			
		||||
test('editable=true will allow edit request', async () => {
 | 
			
		||||
    const { request, base, strategyStore } = await getSetup();
 | 
			
		||||
    const name = 'editStrat';
 | 
			
		||||
    strategyStore.createStrategy({ name, parameters: [] });
 | 
			
		||||
 | 
			
		||||
@ -162,7 +162,7 @@ test('editable=true will allow edit request', () => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('deprecating a strategy works', async () => {
 | 
			
		||||
    const { request, base, strategyStore } = getSetup();
 | 
			
		||||
    const { request, base, strategyStore } = await getSetup();
 | 
			
		||||
    const name = 'editStrat';
 | 
			
		||||
    strategyStore.createStrategy({ name, parameters: [] });
 | 
			
		||||
 | 
			
		||||
@ -177,8 +177,8 @@ test('deprecating a strategy works', async () => {
 | 
			
		||||
        .expect((res) => expect(res.body.deprecated).toBe(true));
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('deprecating a non-existent strategy yields 404', () => {
 | 
			
		||||
    const { request, base } = getSetup();
 | 
			
		||||
test('deprecating a non-existent strategy yields 404', async () => {
 | 
			
		||||
    const { request, base } = await getSetup();
 | 
			
		||||
    return request
 | 
			
		||||
        .post(`${base}/api/admin/strategies/non-existent-strategy/deprecate`)
 | 
			
		||||
        .set('Content-Type', 'application/json')
 | 
			
		||||
@ -186,7 +186,7 @@ test('deprecating a non-existent strategy yields 404', () => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('reactivating a strategy works', async () => {
 | 
			
		||||
    const { request, base, strategyStore } = getSetup();
 | 
			
		||||
    const { request, base, strategyStore } = await getSetup();
 | 
			
		||||
    const name = 'editStrat';
 | 
			
		||||
    strategyStore.createStrategy({ name, parameters: [] });
 | 
			
		||||
 | 
			
		||||
@ -201,16 +201,16 @@ test('reactivating a strategy works', async () => {
 | 
			
		||||
        .expect((res) => expect(res.body.deprecated).toBe(false));
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('reactivating a non-existent strategy yields 404', () => {
 | 
			
		||||
    const { request, base } = getSetup();
 | 
			
		||||
test('reactivating a non-existent strategy yields 404', async () => {
 | 
			
		||||
    const { request, base } = await getSetup();
 | 
			
		||||
    return request
 | 
			
		||||
        .post(`${base}/api/admin/strategies/non-existent-strategy/reactivate`)
 | 
			
		||||
        .set('Content-Type', 'application/json')
 | 
			
		||||
        .expect(404);
 | 
			
		||||
});
 | 
			
		||||
test("deprecating 'default' strategy will yield 403", () => {
 | 
			
		||||
test("deprecating 'default' strategy will yield 403", async () => {
 | 
			
		||||
    jest.spyOn(global.console, 'error').mockImplementation(() => jest.fn());
 | 
			
		||||
    const { request, base } = getSetup();
 | 
			
		||||
    const { request, base } = await getSetup();
 | 
			
		||||
    return request
 | 
			
		||||
        .post(`${base}/api/admin/strategies/default/deprecate`)
 | 
			
		||||
        .set('Content-Type', 'application/json')
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ import getApp from '../../app';
 | 
			
		||||
import { createTestConfig } from '../../../test/config/test-config';
 | 
			
		||||
import { createServices } from '../../services';
 | 
			
		||||
 | 
			
		||||
function getSetup() {
 | 
			
		||||
async function getSetup() {
 | 
			
		||||
    const base = `/random${Math.round(Math.random() * 1000)}`;
 | 
			
		||||
    const stores = createStores();
 | 
			
		||||
    const perms = permissions();
 | 
			
		||||
@ -14,7 +14,7 @@ function getSetup() {
 | 
			
		||||
        preRouterHook: perms.hook,
 | 
			
		||||
    });
 | 
			
		||||
    const services = createServices(stores, config);
 | 
			
		||||
    const app = getApp(config, stores, services);
 | 
			
		||||
    const app = await getApp(config, stores, services);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        base,
 | 
			
		||||
@ -34,8 +34,8 @@ let tagStore;
 | 
			
		||||
let request;
 | 
			
		||||
let destroy;
 | 
			
		||||
 | 
			
		||||
beforeEach(() => {
 | 
			
		||||
    const setup = getSetup();
 | 
			
		||||
beforeEach(async () => {
 | 
			
		||||
    const setup = await getSetup();
 | 
			
		||||
    base = setup.base;
 | 
			
		||||
    tagStore = setup.tagStore;
 | 
			
		||||
    request = setup.request;
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,7 @@ async function getSetup() {
 | 
			
		||||
        server: { baseUriPath: base },
 | 
			
		||||
    });
 | 
			
		||||
    const services = createServices(stores, config);
 | 
			
		||||
    const app = getApp(config, stores, services);
 | 
			
		||||
    const app = await getApp(config, stores, services);
 | 
			
		||||
    return {
 | 
			
		||||
        base,
 | 
			
		||||
        userStore: stores.userStore,
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ test('should enable prometheus', async () => {
 | 
			
		||||
    const config = createTestConfig();
 | 
			
		||||
    const services = createServices(stores, config);
 | 
			
		||||
 | 
			
		||||
    const app = getApp(config, stores, services);
 | 
			
		||||
    const app = await getApp(config, stores, services);
 | 
			
		||||
 | 
			
		||||
    const request = supertest(app);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@ import FeatureController from './feature';
 | 
			
		||||
import { createTestConfig } from '../../../test/config/test-config';
 | 
			
		||||
import { secondsToMilliseconds } from 'date-fns';
 | 
			
		||||
 | 
			
		||||
function getSetup() {
 | 
			
		||||
async function getSetup() {
 | 
			
		||||
    const base = `/random${Math.round(Math.random() * 1000)}`;
 | 
			
		||||
    const stores = createStores();
 | 
			
		||||
    const config = createTestConfig({
 | 
			
		||||
@ -15,7 +15,7 @@ function getSetup() {
 | 
			
		||||
    });
 | 
			
		||||
    const services = createServices(stores, config);
 | 
			
		||||
 | 
			
		||||
    const app = getApp(config, stores, services);
 | 
			
		||||
    const app = await getApp(config, stores, services);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        base,
 | 
			
		||||
@ -35,8 +35,8 @@ let request;
 | 
			
		||||
let destroy;
 | 
			
		||||
let featureToggleClientStore;
 | 
			
		||||
 | 
			
		||||
beforeEach(() => {
 | 
			
		||||
    const setup = getSetup();
 | 
			
		||||
beforeEach(async () => {
 | 
			
		||||
    const setup = await getSetup();
 | 
			
		||||
    base = setup.base;
 | 
			
		||||
    request = setup.request;
 | 
			
		||||
    featureToggleClientStore = setup.featureToggleClientStore;
 | 
			
		||||
 | 
			
		||||
@ -7,12 +7,12 @@ import { createServices } from '../../services';
 | 
			
		||||
import { IUnleashStores } from '../../types';
 | 
			
		||||
import { IUnleashOptions } from '../../server-impl';
 | 
			
		||||
 | 
			
		||||
function getSetup(opts?: IUnleashOptions) {
 | 
			
		||||
async function getSetup(opts?: IUnleashOptions) {
 | 
			
		||||
    const stores = createStores();
 | 
			
		||||
 | 
			
		||||
    const config = createTestConfig(opts);
 | 
			
		||||
    const services = createServices(stores, config);
 | 
			
		||||
    const app = getApp(config, stores, services);
 | 
			
		||||
    const app = await getApp(config, stores, services);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        request: supertest(app),
 | 
			
		||||
@ -29,8 +29,8 @@ let request;
 | 
			
		||||
let stores: IUnleashStores;
 | 
			
		||||
let destroy;
 | 
			
		||||
 | 
			
		||||
beforeEach(() => {
 | 
			
		||||
    const setup = getSetup();
 | 
			
		||||
beforeEach(async () => {
 | 
			
		||||
    const setup = await getSetup();
 | 
			
		||||
    request = setup.request;
 | 
			
		||||
    stores = setup.stores;
 | 
			
		||||
    destroy = setup.destroy;
 | 
			
		||||
@ -83,7 +83,7 @@ test('should accept client metrics with yes/no', () => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('should accept client metrics with yes/no with metricsV2', async () => {
 | 
			
		||||
    const testRunner = getSetup({
 | 
			
		||||
    const testRunner = await getSetup({
 | 
			
		||||
        experimental: { metricsV2: { enabled: true } },
 | 
			
		||||
    });
 | 
			
		||||
    await testRunner.request
 | 
			
		||||
 | 
			
		||||
@ -5,11 +5,11 @@ import getLogger from '../../../test/fixtures/no-logger';
 | 
			
		||||
import getApp from '../../app';
 | 
			
		||||
import { createServices } from '../../services';
 | 
			
		||||
 | 
			
		||||
function getSetup() {
 | 
			
		||||
async function getSetup() {
 | 
			
		||||
    const stores = createStores();
 | 
			
		||||
    const config = createTestConfig();
 | 
			
		||||
    const services = createServices(stores, config);
 | 
			
		||||
    const app = getApp(config, stores, services);
 | 
			
		||||
    const app = await getApp(config, stores, services);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        request: supertest(app),
 | 
			
		||||
@ -23,8 +23,8 @@ function getSetup() {
 | 
			
		||||
}
 | 
			
		||||
let request;
 | 
			
		||||
let destroy;
 | 
			
		||||
beforeEach(() => {
 | 
			
		||||
    const setup = getSetup();
 | 
			
		||||
beforeEach(async () => {
 | 
			
		||||
    const setup = await getSetup();
 | 
			
		||||
    request = setup.request;
 | 
			
		||||
    destroy = setup.destroy;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -7,11 +7,11 @@ import getLogger from '../../test/fixtures/no-logger';
 | 
			
		||||
import getApp from '../app';
 | 
			
		||||
import { IUnleashStores } from '../types';
 | 
			
		||||
 | 
			
		||||
function getSetup() {
 | 
			
		||||
async function getSetup() {
 | 
			
		||||
    const stores = createStores();
 | 
			
		||||
    const config = createTestConfig();
 | 
			
		||||
    const services = createServices(stores, config);
 | 
			
		||||
    const app = getApp(config, stores, services);
 | 
			
		||||
    const app = await getApp(config, stores, services);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        request: supertest(app),
 | 
			
		||||
@ -26,8 +26,8 @@ function getSetup() {
 | 
			
		||||
let request;
 | 
			
		||||
let destroy;
 | 
			
		||||
let stores;
 | 
			
		||||
beforeEach(() => {
 | 
			
		||||
    const setup = getSetup();
 | 
			
		||||
beforeEach(async () => {
 | 
			
		||||
    const setup = await getSetup();
 | 
			
		||||
    request = setup.request;
 | 
			
		||||
    destroy = setup.destroy;
 | 
			
		||||
    stores = setup.stores;
 | 
			
		||||
@ -38,7 +38,7 @@ afterEach(() => {
 | 
			
		||||
    getLogger.setMuteError(false);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
test('should give 500 when db is failing', () => {
 | 
			
		||||
test('should give 500 when db is failing', async () => {
 | 
			
		||||
    jest.spyOn(global.console, 'error').mockImplementation(() => jest.fn());
 | 
			
		||||
    const config = createTestConfig();
 | 
			
		||||
    const failingStores: Partial<IUnleashStores> = {
 | 
			
		||||
@ -54,7 +54,7 @@ test('should give 500 when db is failing', () => {
 | 
			
		||||
    // @ts-ignore
 | 
			
		||||
    const services = createServices(failingStores, config);
 | 
			
		||||
    // @ts-ignore
 | 
			
		||||
    const app = getApp(createTestConfig(), failingStores, services);
 | 
			
		||||
    const app = await getApp(createTestConfig(), failingStores, services);
 | 
			
		||||
    request = supertest(app);
 | 
			
		||||
    getLogger.setMuteError(true);
 | 
			
		||||
    expect.assertions(2);
 | 
			
		||||
 | 
			
		||||
@ -4,14 +4,14 @@ import createStores from '../../test/fixtures/store';
 | 
			
		||||
import getApp from '../app';
 | 
			
		||||
import { createServices } from '../services';
 | 
			
		||||
 | 
			
		||||
function getSetup() {
 | 
			
		||||
async function getSetup() {
 | 
			
		||||
    const base = `/random${Math.round(Math.random() * 1000)}`;
 | 
			
		||||
    const stores = createStores();
 | 
			
		||||
    const config = createTestConfig({
 | 
			
		||||
        server: { baseUriPath: base },
 | 
			
		||||
    });
 | 
			
		||||
    const services = createServices(stores, config);
 | 
			
		||||
    const app = getApp(config, stores, services);
 | 
			
		||||
    const app = await getApp(config, stores, services);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        base,
 | 
			
		||||
@ -27,8 +27,8 @@ function getSetup() {
 | 
			
		||||
let base;
 | 
			
		||||
let request;
 | 
			
		||||
let destroy;
 | 
			
		||||
beforeEach(() => {
 | 
			
		||||
    const setup = getSetup();
 | 
			
		||||
beforeEach(async () => {
 | 
			
		||||
    const setup = await getSetup();
 | 
			
		||||
    base = setup.base;
 | 
			
		||||
    request = setup.request;
 | 
			
		||||
    destroy = setup.destroy;
 | 
			
		||||
 | 
			
		||||
@ -57,7 +57,7 @@ async function createApp(
 | 
			
		||||
        // eslint-disable-next-line no-param-reassign
 | 
			
		||||
        config.server.secret = secret;
 | 
			
		||||
    }
 | 
			
		||||
    const app = getApp(config, stores, services, unleashSession);
 | 
			
		||||
    const app = await getApp(config, stores, services, unleashSession);
 | 
			
		||||
 | 
			
		||||
    if (typeof config.eventHook === 'function') {
 | 
			
		||||
        addEventHook(config.eventHook, stores.eventStore);
 | 
			
		||||
 | 
			
		||||
@ -70,6 +70,7 @@ export interface IServerOption {
 | 
			
		||||
    keepAliveTimeout: number;
 | 
			
		||||
    headersTimeout: number;
 | 
			
		||||
    baseUriPath: string;
 | 
			
		||||
    cdnPrefix?: string;
 | 
			
		||||
    unleashUrl: string;
 | 
			
		||||
    serverMetrics: boolean;
 | 
			
		||||
    enableRequestLogger: boolean;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										24
									
								
								src/lib/util/load-index-html.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/lib/util/load-index-html.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
import fs from 'fs';
 | 
			
		||||
import { IUnleashConfig } from '../server-impl';
 | 
			
		||||
import { rewriteHTML } from './rewriteHTML';
 | 
			
		||||
import path from 'path';
 | 
			
		||||
import fetch from 'node-fetch';
 | 
			
		||||
 | 
			
		||||
export async function loadIndexHTML(
 | 
			
		||||
    config: IUnleashConfig,
 | 
			
		||||
    publicFolder: string,
 | 
			
		||||
): Promise<string> {
 | 
			
		||||
    const { cdnPrefix, baseUriPath = '' } = config.server;
 | 
			
		||||
 | 
			
		||||
    let indexHTML: string;
 | 
			
		||||
    if (cdnPrefix) {
 | 
			
		||||
        const res = await fetch(`${cdnPrefix}/index.html`);
 | 
			
		||||
        indexHTML = await res.text();
 | 
			
		||||
    } else {
 | 
			
		||||
        indexHTML = fs
 | 
			
		||||
            .readFileSync(path.join(publicFolder, 'index.html'))
 | 
			
		||||
            .toString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return rewriteHTML(indexHTML, baseUriPath, cdnPrefix);
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +1,15 @@
 | 
			
		||||
export const rewriteHTML = (input: string, rewriteValue: string): string => {
 | 
			
		||||
export const rewriteHTML = (
 | 
			
		||||
    input: string,
 | 
			
		||||
    rewriteValue: string,
 | 
			
		||||
    cdnPrefix?: string,
 | 
			
		||||
): string => {
 | 
			
		||||
    let result = input;
 | 
			
		||||
    result = result.replace(/::baseUriPath::/gi, rewriteValue);
 | 
			
		||||
    result = result.replace(/\/static/gi, `${rewriteValue}/static`);
 | 
			
		||||
    result = result.replace(/::cdnPrefix::/gi, cdnPrefix || '');
 | 
			
		||||
    result = result.replace(
 | 
			
		||||
        /\/static/gi,
 | 
			
		||||
        `${cdnPrefix || rewriteValue}/static`,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,7 @@ process.nextTick(async () => {
 | 
			
		||||
                    baseUriPath: '',
 | 
			
		||||
                    // keepAliveTimeout: 1,
 | 
			
		||||
                    gracefulShutdownEnable: true,
 | 
			
		||||
                    // cdnPrefix: 'https://cdn.getunleash.io/unleash/v4.4.1',
 | 
			
		||||
                },
 | 
			
		||||
                logLevel: LogLevel.debug,
 | 
			
		||||
                enableOAS: true,
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,3 @@ export function createTestConfig(config?: IUnleashOptions): IUnleashConfig {
 | 
			
		||||
    const options = mergeAll<IUnleashOptions>([testConfig, config]);
 | 
			
		||||
    return createConfig(options);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    createTestConfig,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -18,12 +18,12 @@ export interface IUnleashTest {
 | 
			
		||||
    services: IUnleashServices;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createApp(
 | 
			
		||||
async function createApp(
 | 
			
		||||
    stores,
 | 
			
		||||
    adminAuthentication = IAuthType.NONE,
 | 
			
		||||
    preHook?: Function,
 | 
			
		||||
    customOptions?: any,
 | 
			
		||||
): IUnleashTest {
 | 
			
		||||
): Promise<IUnleashTest> {
 | 
			
		||||
    const config = createTestConfig({
 | 
			
		||||
        authentication: {
 | 
			
		||||
            type: adminAuthentication,
 | 
			
		||||
@ -38,7 +38,7 @@ function createApp(
 | 
			
		||||
    const unleashSession = sessionDb(config, undefined);
 | 
			
		||||
    const emitter = new EventEmitter();
 | 
			
		||||
    emitter.setMaxListeners(0);
 | 
			
		||||
    const app = getApp(config, stores, services, unleashSession);
 | 
			
		||||
    const app = await getApp(config, stores, services, unleashSession);
 | 
			
		||||
    const request = supertest.agent(app);
 | 
			
		||||
 | 
			
		||||
    const destroy = async () => {
 | 
			
		||||
 | 
			
		||||
@ -7246,7 +7246,7 @@ universalify@^0.1.0, universalify@^0.1.2:
 | 
			
		||||
  resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz"
 | 
			
		||||
  integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
 | 
			
		||||
 | 
			
		||||
unleash-frontend@4.4.1:
 | 
			
		||||
unleash-frontend@v4.4.1:
 | 
			
		||||
  version "4.4.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/unleash-frontend/-/unleash-frontend-4.4.1.tgz#753008e8a1a25b204edf23595261635f030b8590"
 | 
			
		||||
  integrity sha512-hyVd56nbWkFdyEeCeHMVZjKlQyWu82QqzGT6IDKzYJruYpIk00/9dm7zycziZIwzu7GXfKkI4J6fnm6Ge7mB5g==
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user