"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const supertest_1 = __importDefault(require("supertest"));
const app_1 = require("../app");
const metrics_json_1 = __importDefault(require("../examples/metrics.json"));
const client_mock_1 = __importDefault(require("./client.mock"));
const unleashUrl = 'http://localhost:4242/test';
const unleashApiToken = 's1';
test('Should return empty list of toggles', () => {
    const client = new client_mock_1.default();
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ proxySecrets, unleashUrl, unleashApiToken }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .get('/proxy')
        .set('Authorization', 'sdf')
        .expect(200)
        .expect('Content-Type', /json/)
        .then((response) => {
        expect(response.body.toggles).toEqual([]);
    });
});
test('Should return list of toggles', () => {
    const toggles = [
        {
            name: 'test',
            enabled: true,
            impressionData: true,
        },
        {
            name: 'test2',
            enabled: true,
            impressionData: true,
        },
    ];
    const client = new client_mock_1.default(toggles);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ proxySecrets, unleashUrl, unleashApiToken }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .get('/proxy')
        .set('Authorization', 'sdf')
        .expect(200)
        .expect('Content-Type', /json/)
        .then((response) => {
        expect(response.body.toggles.length).toEqual(2);
    });
});
test('Should handle POST with empty/nonsensical body', async () => {
    const toggles = [
        {
            name: 'test',
            enabled: true,
            impressionData: true,
        },
        {
            name: 'test2',
            enabled: true,
            impressionData: true,
        },
    ];
    const client = new client_mock_1.default(toggles);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ proxySecrets, unleashUrl, unleashApiToken }, client);
    client.emit('ready');
    await Promise.all([{ blah: 'hello' }, undefined, {}].map((body) => (0, supertest_1.default)(app)
        .post('/proxy')
        .type('json')
        .send(body)
        .set('Accept', 'application/json')
        .set('Authorization', 'sdf')
        .expect(200)
        .expect('Content-Type', /json/)
        .then((response) => {
        expect(response.body.toggles).toHaveLength(2);
    })));
});
test('Should handle POST with extra context properties', () => {
    const client = new client_mock_1.default();
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ proxySecrets, unleashUrl, unleashApiToken }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .post('/proxy')
        .send({
        context: {
            customProperty: 'string',
            properties: { otherCustomProperty: 24 },
        },
    })
        .set('Accept', 'application/json')
        .set('Authorization', 'sdf')
        .expect(200)
        .expect('Content-Type', /json/);
});
test('Should handle POST with toggle names', () => {
    const toggles = [
        {
            name: 'test',
            enabled: true,
            impressionData: true,
        },
        {
            name: 'test2',
            enabled: true,
            impressionData: true,
        },
    ];
    const client = new client_mock_1.default(toggles);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ proxySecrets, unleashUrl, unleashApiToken }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .post('/proxy')
        .send({ toggles: ['test'] })
        .set('Accept', 'application/json')
        .set('Authorization', 'sdf')
        .expect(200)
        .expect('Content-Type', /json/)
        .then((response) => {
        expect(response.body.toggles).toHaveLength(1);
        expect(response.body.toggles[0].name).toBe('test');
    });
});
test('Should return list of toggles with custom proxy client key header', () => {
    const toggles = [
        {
            name: 'test',
            enabled: true,
            impressionData: true,
        },
        {
            name: 'test2',
            enabled: true,
            impressionData: true,
        },
    ];
    const client = new client_mock_1.default(toggles);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({
        proxySecrets,
        unleashUrl,
        unleashApiToken,
        clientKeysHeaderName: 'NotAuthorized',
    }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .get('/proxy')
        .set('NotAuthorized', 'sdf')
        .expect(200)
        .expect('Content-Type', /json/)
        .then((response) => {
        expect(response.body.toggles.length).toEqual(2);
    });
});
test('Should return list of toggles using env with multiple secrets', () => {
    process.env.UNLEASH_PROXY_SECRETS = 'secret1,secret2';
    const toggles = [
        {
            name: 'test',
            enabled: true,
            impressionData: true,
        },
        {
            name: 'test2',
            enabled: true,
            impressionData: true,
        },
    ];
    const client = new client_mock_1.default(toggles);
    const app = (0, app_1.createApp)({ unleashUrl, unleashApiToken }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .get('/proxy')
        .set('Authorization', 'secret2')
        .expect(200)
        .expect('Content-Type', /json/)
        .then((response) => {
        expect(response.body.toggles.length).toEqual(2);
    });
});
test('Should return list of toggles using env with multiple secrets with space', () => {
    process.env.UNLEASH_PROXY_SECRETS = 'secret11, secret22';
    const toggles = [
        {
            name: 'test',
            enabled: true,
            impressionData: true,
        },
        {
            name: 'test2',
            enabled: true,
            impressionData: true,
        },
    ];
    const client = new client_mock_1.default(toggles);
    const app = (0, app_1.createApp)({ unleashUrl, unleashApiToken }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .get('/proxy')
        .set('Authorization', 'secret22')
        .expect(200)
        .expect('Content-Type', /json/)
        .then((response) => {
        expect(response.body.toggles.length).toEqual(2);
    });
});
test('Should send in context to mock', async () => {
    const toggles = [
        {
            name: 'test',
            enabled: true,
            impressionData: true,
        },
    ];
    const client = new client_mock_1.default(toggles);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ proxySecrets, unleashUrl, unleashApiToken }, client);
    client.emit('ready');
    await (0, supertest_1.default)(app)
        .get('/proxy?userId=123&tenantId=me')
        .set('Authorization', 'sdf')
        .expect(200)
        .expect('Content-Type', /json/);
    expect(client.queriedContexts[0].userId).toEqual('123');
    expect(client.queriedContexts[0].properties?.tenantId).toEqual('me');
});
test('Should send in context with ip as remoteAddress', async () => {
    const userIp = '123.13.13.42';
    const toggles = [
        {
            name: 'test',
            enabled: true,
            impressionData: true,
        },
    ];
    const client = new client_mock_1.default(toggles);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ proxySecrets, unleashUrl, unleashApiToken, trustProxy: true }, client);
    client.emit('ready');
    await (0, supertest_1.default)(app)
        .get('/proxy?userId=123&tenantId=me')
        .set('Authorization', 'sdf')
        .set('X-Forwarded-For', userIp)
        .expect(200)
        .expect('Content-Type', /json/);
    expect(client.queriedContexts[0].remoteAddress).toEqual(userIp);
});
test('Should remove "undefined" environment field from context', async () => {
    const toggles = [
        {
            name: 'test',
            enabled: true,
            impressionData: true,
        },
    ];
    const client = new client_mock_1.default(toggles);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({
        unleashUrl,
        unleashApiToken,
        proxySecrets,
        environment: 'test',
    }, client);
    client.emit('ready');
    await (0, supertest_1.default)(app)
        .get('/proxy?userId=123&tenantId=me')
        .set('Authorization', 'sdf')
        .expect(200)
        .expect('Content-Type', /json/);
    expect(client.queriedContexts[0]).not.toHaveProperty('environment');
});
test('Providing a string for `properties` yields a 400', async () => {
    const toggles = [
        {
            name: 'test',
            enabled: true,
            impressionData: true,
        },
    ];
    const client = new client_mock_1.default(toggles);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({
        unleashUrl,
        unleashApiToken,
        proxySecrets,
        environment: 'test',
    }, client);
    client.emit('ready');
    await (0, supertest_1.default)(app)
        .get('/proxy?userId=123&properties=string')
        .set('Authorization', 'sdf')
        .expect(400);
});
test('Should register metrics', () => {
    const toggles = [
        {
            name: 'test',
            enabled: true,
            impressionData: true,
        },
    ];
    const client = new client_mock_1.default(toggles);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ unleashUrl, unleashApiToken, proxySecrets }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .post('/proxy/client/metrics')
        .send(metrics_json_1.default)
        .set('Authorization', 'sdf')
        .expect(200);
});
test('Should register metrics an /all path as well', () => {
    const toggles = [
        {
            name: 'test',
            enabled: true,
            impressionData: true,
        },
    ];
    const client = new client_mock_1.default(toggles);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ unleashUrl, unleashApiToken, proxySecrets }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .post('/proxy/all/client/metrics')
        .send(metrics_json_1.default)
        .set('Authorization', 'sdf')
        .expect(200);
});
test('Should require metrics to have correct format', () => {
    const client = new client_mock_1.default();
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ unleashUrl, unleashApiToken, proxySecrets }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .post('/proxy/client/metrics')
        .send({ some: 'blob' })
        .set('Authorization', 'sdf')
        .expect(400);
});
test('Should return errors as JSON', () => {
    const client = new client_mock_1.default();
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ unleashUrl, unleashApiToken, proxySecrets }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .post('/proxy/client/metrics')
        .send({ some: 'blob' })
        .set('Authorization', 'sdf')
        .expect(400)
        .expect('Content-Type', /json/);
});
describe.each([
    '',
    '/all',
    '/health',
    '/client/features',
    '/internal-backstage/prometheus',
])('GET should return not ready', (url) => {
    test(`for ${url}`, () => {
        const client = new client_mock_1.default();
        const proxySecrets = ['sdf'];
        const app = (0, app_1.createApp)({ unleashUrl, unleashApiToken, proxySecrets }, client);
        return (0, supertest_1.default)(app).get(`/proxy${url}`).expect(503);
    });
});
describe.each([
    '',
    '/all',
    '/client/features',
])('Requires valid token', (url) => {
    test(`Should return 401 if invalid api token for ${url}`, () => {
        const client = new client_mock_1.default();
        const proxySecrets = ['secret'];
        const app = (0, app_1.createApp)({ proxySecrets, unleashUrl, unleashApiToken }, client);
        client.emit('ready');
        return (0, supertest_1.default)(app)
            .get(`/proxy${url}`)
            .set('Authorization', 'I do not know your secret')
            .expect(401);
    });
    test(`Should return 401 if no api token for ${url}`, () => {
        const client = new client_mock_1.default();
        const proxySecrets = ['secret'];
        const app = (0, app_1.createApp)({ proxySecrets, unleashUrl, unleashApiToken }, client);
        client.emit('ready');
        return (0, supertest_1.default)(app).get(`/proxy${url}`).expect(401);
    });
});
describe.each([
    { url: '/health', responseBody: 'ok' },
    {
        url: '/internal-backstage/prometheus',
        responseBody: 'unleash_proxy_up 1',
    },
])('Do not require valid token', ({ url, responseBody }) => {
    test(`Should not require a token for ${url}`, () => {
        const client = new client_mock_1.default();
        const proxySecrets = ['sdf'];
        const app = (0, app_1.createApp)({ unleashUrl, unleashApiToken, proxySecrets }, client);
        client.emit('ready');
        return (0, supertest_1.default)(app)
            .get(`/proxy${url}`)
            .expect(200)
            .then((response) => {
            expect(response.text).toMatch(responseBody);
        });
    });
});
test('Should return 504 for proxy', () => {
    const client = new client_mock_1.default();
    const app = (0, app_1.createApp)({ unleashUrl, unleashApiToken }, client);
    return (0, supertest_1.default)(app)
        .get('/proxy')
        .set('Authorization', 'secret2')
        .expect(503);
});
test('Should allow every origin (*)', async () => {
    const client = new client_mock_1.default();
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ proxySecrets, unleashUrl, unleashApiToken }, client);
    client.emit('ready');
    const response = await (0, supertest_1.default)(app)
        .get('/proxy?userId=999&tenantId=me')
        .set('Origin', 'https://test.com')
        .set('Authorization', 'sdf')
        .expect(200)
        .expect('Content-Type', /json/);
    expect(response.headers).toHaveProperty('access-control-allow-origin', '*');
});
test('Should return the same origin based on cors options', async () => {
    const client = new client_mock_1.default();
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({
        proxySecrets,
        unleashUrl,
        unleashApiToken,
        cors: {
            origin: [
                'https://example.com',
                'https://demo.unleash-hosted.com',
            ],
        },
    }, client);
    client.emit('ready');
    const response = await (0, supertest_1.default)(app)
        .get('/proxy?userId=999&tenantId=me')
        .set('Origin', 'https://demo.unleash-hosted.com')
        .set('Authorization', 'sdf')
        .expect(200)
        .expect('Content-Type', /json/);
    expect(response.headers).toHaveProperty('access-control-allow-origin', 'https://demo.unleash-hosted.com');
});
test('Should return 400 bad request for malformed JSON', async () => {
    const body = '{ toggles": [] }';
    const client = new client_mock_1.default();
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ proxySecrets, unleashUrl, unleashApiToken }, client);
    client.emit('ready');
    await (0, supertest_1.default)(app)
        .post('/proxy')
        .type('json')
        .send(body)
        .set('Accept', 'application/json')
        .set('Authorization', 'sdf')
        .expect(400)
        .expect('Content-Type', /json/);
});
test('Should register server SDK', async () => {
    const toggles = [
        {
            name: 'test',
            enabled: true,
            impressionData: true,
        },
    ];
    const client = new client_mock_1.default(toggles);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({
        unleashUrl,
        unleashApiToken,
        proxySecrets,
        expServerSideSdkConfig: { tokens: ['s1'] },
    }, client);
    client.emit('ready');
    const res = await (0, supertest_1.default)(app)
        .post('/proxy/client/register')
        .send({
        appName: 'test',
        instanceId: 'i1',
        sdkVersion: 'custom1',
        environment: 'prod',
        interval: 10000,
        started: new Date(),
        strategies: ['default'],
    })
        .set('Authorization', 'sdf');
    expect(res.statusCode).toBe(200);
});
test('Should return all feature toggles', () => {
    const client = new client_mock_1.default([
        { name: 'a', enabled: true, impressionData: false },
        { name: 'b', enabled: false, impressionData: false },
        { name: 'c', enabled: true, impressionData: true },
    ]);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ unleashUrl, unleashApiToken, proxySecrets, enableAllEndpoint: true }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .get('/proxy/all')
        .set('Authorization', 'sdf')
        .expect(200)
        .expect((res) => {
        expect(res.body.toggles.length).toBe(3);
    });
});
test('/client/features should return toggle definitions', () => {
    const client = new client_mock_1.default([
        { name: 'a', enabled: true, impressionData: false },
        { name: 'b', enabled: false, impressionData: false },
        { name: 'c', enabled: true, impressionData: true },
    ]);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({
        unleashUrl,
        unleashApiToken,
        proxySecrets,
        enableAllEndpoint: true,
        expServerSideSdkConfig: { tokens: ['server-side'] },
    }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .get('/proxy/client/features')
        .set('Authorization', 'server-side')
        .expect(200)
        .expect((res) => {
        expect(res.body.features.length).toBe(3);
        expect(res.body.features[0].strategies.length).toBe(1);
    });
});
test('/client/features should not accept proxy secret', () => {
    const client = new client_mock_1.default([
        { name: 'a', enabled: true, impressionData: false },
        { name: 'b', enabled: false, impressionData: false },
        { name: 'c', enabled: true, impressionData: true },
    ]);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({
        unleashUrl,
        unleashApiToken,
        proxySecrets,
        enableAllEndpoint: true,
        expServerSideSdkConfig: { tokens: ['server-side'] },
    }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .get('/proxy/client/features')
        .set('Authorization', 'sdf')
        .expect(401);
});
test('Should return all feature toggles via POST', () => {
    const client = new client_mock_1.default([
        { name: 'a', enabled: true, impressionData: false },
        { name: 'b', enabled: false, impressionData: false },
        { name: 'c', enabled: true, impressionData: true },
    ]);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ unleashUrl, unleashApiToken, proxySecrets, enableAllEndpoint: true }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .post('/proxy/all')
        .send({
        context: {
            customProperty: 'string',
            properties: { otherCustomProperty: 24 },
        },
    })
        .set('Authorization', 'sdf')
        .expect(200)
        .expect((res) => {
        expect(res.body.toggles.length).toBe(3);
    });
});
test('Should return all named feature toggles via POST', () => {
    const client = new client_mock_1.default([
        { name: 'a', enabled: true, impressionData: false },
        { name: 'b', enabled: false, impressionData: false },
        { name: 'c', enabled: true, impressionData: true },
    ]);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ unleashUrl, unleashApiToken, proxySecrets, enableAllEndpoint: true }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .post('/proxy/all')
        .send({
        toggles: ['a'],
        context: {
            customProperty: 'string',
            properties: { otherCustomProperty: 24 },
        },
    })
        .set('Authorization', 'sdf')
        .expect(200)
        .expect((res) => {
        expect(res.body.toggles.length).toBe(1);
        expect(res.body.toggles[0].name).toBe('a');
    });
});
test('Should return all enabled feature toggles when POST-ing', () => {
    const client = new client_mock_1.default([
        { name: 'a', enabled: true, impressionData: false },
        { name: 'c', enabled: true, impressionData: true },
    ]);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ unleashUrl, unleashApiToken, proxySecrets, enableAllEndpoint: true }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .post('/proxy')
        .set('Authorization', 'sdf')
        .expect(200)
        .expect((res) => {
        expect(res.body.toggles.length).toBe(2);
    });
});
test('Should return 501 when all feature toggles is not enabled', () => {
    const client = new client_mock_1.default([
        { name: 'a', enabled: true, impressionData: false },
    ]);
    const proxySecrets = ['sdf'];
    const app = (0, app_1.createApp)({ unleashUrl, unleashApiToken, proxySecrets }, client);
    client.emit('ready');
    return (0, supertest_1.default)(app)
        .get('/proxy/all')
        .set('Authorization', 'sdf')
        .expect(501);
});
describe('Request content-types', () => {
    test.each([
        '/proxy',
        '/proxy/all',
    ])('Should assign default content-type if the request has a body but no content-type (%s)', async (endpoint) => {
        const client = new client_mock_1.default();
        const payload = {
            context: { appName: 'my-app' },
        };
        const proxySecrets = ['sdf'];
        const app = (0, app_1.createApp)({
            unleashUrl,
            unleashApiToken,
            proxySecrets,
            enableAllEndpoint: true,
        }, client);
        client.emit('ready');
        await (0, supertest_1.default)(app)
            .post(endpoint)
            .set('Authorization', 'sdf')
            .set('Content-Type', '')
            .send(payload)
            .expect(200)
            .then(() => {
            expect(client.queriedContexts[0].appName).toEqual(payload.context.appName);
        });
    });
    test.each([
        '/proxy',
        '/proxy/all',
    ])('Should reject non-"content-type: application/json" for POST requests to %s', (endpoint) => {
        const client = new client_mock_1.default();
        const proxySecrets = ['sdf'];
        const app = (0, app_1.createApp)({
            unleashUrl,
            unleashApiToken,
            proxySecrets,
            enableAllEndpoint: true,
        }, client);
        client.emit('ready');
        return (0, supertest_1.default)(app)
            .post(endpoint)
            .set('Authorization', 'sdf')
            .set('Content-Type', 'application/html')
            .send('<em>reject me!</em>')
            .expect(415);
    });
});
//# sourceMappingURL=unleash-proxy.test.js.map