RocketChat/Rocket.Chat

View on GitHub
ee/packages/license/__tests__/setLicense.spec.ts

Summary

Maintainability
C
7 hrs
Test Coverage
/**
 * @jest-environment node
 */

import { LicenseImp } from '../src';
import { DuplicatedLicenseError } from '../src/errors/DuplicatedLicenseError';
import { InvalidLicenseError } from '../src/errors/InvalidLicenseError';
import { NotReadyForValidation } from '../src/errors/NotReadyForValidation';
import { MockedLicenseBuilder, getReadyLicenseManager } from './MockedLicenseBuilder';

// Same license used on ci tasks so no I didnt leak it
const VALID_LICENSE =
    process.env.ENTERPRISE_LICENSE ||
    'X/XumwIkgwQuld0alWKt37lVA90XjKOrfiMvMZ0/RtqsMtrdL9GoAk+4jXnaY1b2ePoG7XSzGhuxEDxFKIWJK3hIKGNTvrd980LgH5sM5+1T4P42ivSpd8UZi0bwjJkCFLIu9RozzYwslGG0IehMxe0S6VjcO0UYlUJtbMCBHuR2WmTAmO6YVU3ln+pZCbrPFaTPSS1RovhKaNCNkZwIx/CLWW8UTXUuFV/ML4PbKKVoa5nvvJwPeatgL7UCnlSD90lfCiiuikpzj/Y/JLkIL6velFbwNxsrxg9iRJ2k0sKheMMSmlTiGzSvZUm+na5WQq91aKGncih+DmaEZA7QGrjp4eoA0dqTk6OmItsy0fHmQhvZIOKNMeO7vNQiLbaSV6rqibrzu7WPpeIvsvL57T1h37USoCSB6+jDqkzdfoqIpz8BxTiJDj1d8xGPJFVrgxoqQqkj9qIP/gCaEz5DF39QFv5sovk4yK2O8fEQYod2d14V9yECYl4szZPMk1IBfCAC2w7czWGHHFonhL+CQGT403y5wmDmnsnjlCqMKF72odqfTPTI8XnCvJDriPMWohnQEAGtTTyciAhNokx/mjAVJ4NeZPcsbm4BjhvJvnjxx/BhYhBBTNWPaCSZzocfrGUj9Z+ZA7BEz+xAFQyGDx3xRzqIXfT0G7w8fvgYJMU=';

describe('License set license procedures', () => {
    describe('Invalid formats', () => {
        it('should have no license by default', async () => {
            const license = new LicenseImp();

            expect(license.hasValidLicense()).toBe(false);
            expect(license.getLicense()).toBeUndefined();
        });

        it('should throw an error if the license applied is empty', async () => {
            const license = new LicenseImp();
            await expect(license.setLicense('')).rejects.toThrow(InvalidLicenseError);
        });

        it('should throw an error if the license applied is invalid', async () => {
            const license = new LicenseImp();
            await expect(license.setLicense('invalid')).rejects.toThrow(InvalidLicenseError);
        });
    });

    describe('Invalid periods', () => {
        it('should throw an error if the license is expired', async () => {
            const license = await getReadyLicenseManager();

            const mocked = new MockedLicenseBuilder();
            const token = await mocked.withExpiredDate().sign();

            await license.setLicense(token);
            expect(license.hasValidLicense()).toBe(false);
        });

        describe('license that is not not started yet is applied', () => {
            it('should throw an error if the license is not started yet', async () => {
                const license = await getReadyLicenseManager();

                const mocked = new MockedLicenseBuilder();
                const token = await mocked.withNotStartedDate().sign();

                await license.setLicense(token);
                expect(license.hasValidLicense()).toBe(false);
            });

            it('should be allowed to set the same license again if the license is not started yet', async () => {
                const license = await getReadyLicenseManager();

                const mocked = new MockedLicenseBuilder();
                const as = mocked.resetValidPeriods().withNotStartedDate();
                const token = await as.sign();

                await license.setLicense(token);

                expect(license.hasValidLicense()).toBe(false);

                // 5 minutes in the future

                const mockedData = new Date();

                mockedData.setMinutes(mockedData.getMinutes() + 5);

                jest.useFakeTimers();
                jest.setSystemTime(mockedData);

                await license.setLicense(token);

                jest.useRealTimers();

                expect(license.hasValidLicense()).toBe(true);
            });
        });
    });

    it('should throw an error if the license is duplicated', async () => {
        const license = await getReadyLicenseManager();

        await expect(license.setLicense(VALID_LICENSE)).resolves.toBe(true);
        await expect(license.setLicense(VALID_LICENSE)).rejects.toThrow(DuplicatedLicenseError);
    });

    it('should keep a valid license if a new invalid formatted license is applied', async () => {
        const license = await getReadyLicenseManager();

        await expect(license.setLicense(VALID_LICENSE)).resolves.toBe(true);
        expect(license.hasValidLicense()).toBe(true);

        await expect(license.setLicense('invalid')).rejects.toThrow(InvalidLicenseError);
        expect(license.hasValidLicense()).toBe(true);
    });

    describe('Pending cases', () => {
        it('should return an error if the license is not ready for validation yet - missing workspace url', async () => {
            const license = new LicenseImp();
            await expect(license.setLicense(VALID_LICENSE)).rejects.toThrow(NotReadyForValidation);
        });

        it('should return an error if the license is not ready for validation yet - missing counters', async () => {
            const license = new LicenseImp();
            await license.setWorkspaceUrl('http://localhost:3000');

            expect(license.getWorkspaceUrl()).toBe('localhost:3000');

            await expect(license.setLicense(VALID_LICENSE)).rejects.toThrow(NotReadyForValidation);

            expect(license.hasValidLicense()).toBe(false);
        });

        it('should return a valid license if the license is ready for validation', async () => {
            const license = await getReadyLicenseManager();

            await expect(license.setLicense(VALID_LICENSE)).resolves.toBe(true);
            expect(license.hasValidLicense()).toBe(true);
        });
    });

    describe('License V3', () => {
        it('should return a valid license if the license is ready for validation', async () => {
            const license = await getReadyLicenseManager();
            const token = await new MockedLicenseBuilder().sign();

            await expect(license.setLicense(token)).resolves.toBe(true);
            expect(license.hasValidLicense()).toBe(true);
        });

        it('should accept new licenses', async () => {
            const license = await getReadyLicenseManager();
            const mocked = new MockedLicenseBuilder();
            const oldToken = await mocked.sign();

            const newToken = await mocked.withGratedModules(['livechat-enterprise']).sign();

            await expect(license.setLicense(oldToken)).resolves.toBe(true);
            expect(license.hasValidLicense()).toBe(true);

            expect(license.hasModule('livechat-enterprise')).toBe(false);

            await expect(license.setLicense(newToken)).resolves.toBe(true);
            expect(license.hasValidLicense()).toBe(true);
            expect(license.hasModule('livechat-enterprise')).toBe(true);
        });

        it('should call a validated event after set a valid license', async () => {
            const license = await getReadyLicenseManager();
            const validateCallback = jest.fn();
            license.onValidateLicense(validateCallback);
            await expect(license.setLicense(VALID_LICENSE)).resolves.toBe(true);
            expect(license.hasValidLicense()).toBe(true);
            expect(validateCallback).toBeCalledTimes(1);
        });

        describe('License limits', () => {
            describe('invalidate license', () => {
                it('should trigger an invalidation event when a license with invalid limits is set after a valid one', async () => {
                    const invalidationCallback = jest.fn();

                    const licenseManager = await getReadyLicenseManager();
                    const mocked = new MockedLicenseBuilder();
                    const oldToken = await mocked
                        .withLimits('activeUsers', [
                            {
                                max: 10,
                                behavior: 'invalidate_license',
                            },
                        ])
                        .sign();

                    const newToken = await mocked
                        .withLimits('activeUsers', [
                            {
                                max: 1,
                                behavior: 'invalidate_license',
                            },
                        ])
                        .sign();

                    licenseManager.onInvalidateLicense(invalidationCallback);

                    licenseManager.setLicenseLimitCounter('activeUsers', () => 5);

                    await expect(licenseManager.setLicense(oldToken)).resolves.toBe(true);
                    expect(licenseManager.hasValidLicense()).toBe(true);

                    await expect(licenseManager.setLicense(newToken)).resolves.toBe(true);
                    expect(licenseManager.hasValidLicense()).toBe(false);

                    expect(invalidationCallback).toBeCalledTimes(1);
                });
            });
        });
    });
});