From 91e4ac1665478166e17f01fd7c97d340c913fa2f Mon Sep 17 00:00:00 2001 From: bgrozev Date: Mon, 18 Aug 2025 13:32:41 -0500 Subject: [PATCH] ref: Extract test configuration code to TestsConfig.ts (#16329) * ref: Move iFrameUsesJaas to TestsConfig. * ref: Move room name prefix/suffix to config. * ref: Move JaaS configuration to TestsConfig. * ref: Move iframe config to TestsConfig. * ref: Move webproxy config to TestsConfig. * ref: Move JWT config to TestsConfig. * doc: Document some of the IContext fields. * Add a debug config option. --- tests/env.example | 3 ++ tests/helpers/Participant.ts | 5 ++- tests/helpers/TestsConfig.ts | 44 +++++++++++++++++++ tests/helpers/participants.ts | 13 +++--- tests/helpers/token.ts | 14 +++--- tests/helpers/types.ts | 15 +++++-- tests/helpers/utils.ts | 24 +++++----- tests/specs/2way/urlNormalisation.spec.ts | 3 +- tests/specs/3way/audioVideoModeration.spec.ts | 3 +- tests/specs/3way/lobby.spec.ts | 5 ++- tests/specs/helpers/jaas.ts | 17 +++---- tests/specs/iframe/invite.spec.ts | 5 ++- .../specs/iframe/participantsPresence.spec.ts | 3 +- tests/specs/iframe/recording.spec.ts | 9 ++-- tests/specs/iframe/visitors.spec.ts | 5 ++- tests/wdio.conf.ts | 42 ++++++------------ 16 files changed, 132 insertions(+), 78 deletions(-) create mode 100644 tests/helpers/TestsConfig.ts diff --git a/tests/env.example b/tests/env.example index 8f3d62d022..c37ebfd2f6 100644 --- a/tests/env.example +++ b/tests/env.example @@ -34,6 +34,9 @@ # The JaaS tenant, e.g. vpaas-magic-cookie-abcdabcd1234567890 #JAAS_TENANT= +# Enable debug logging. Note this includes private information from .env. +#JITSI_DEBUG=true + # An access token to use to create meetings (used for the first participant) #JWT_ACCESS_TOKEN= diff --git a/tests/helpers/Participant.ts b/tests/helpers/Participant.ts index dd04e52643..a328cca216 100644 --- a/tests/helpers/Participant.ts +++ b/tests/helpers/Participant.ts @@ -27,6 +27,7 @@ import Toolbar from '../pageobjects/Toolbar'; import VideoQualityDialog from '../pageobjects/VideoQualityDialog'; import Visitors from '../pageobjects/Visitors'; +import { config as testsConfig } from './TestsConfig'; import { LOG_PREFIX, logInfo } from './browserLogger'; import { IToken } from './token'; import { IParticipantJoinOptions, IParticipantOptions } from './types'; @@ -225,8 +226,8 @@ export class Participant { // @ts-ignore url = `${this.driver.iframePageBase}${url}&domain="${baseUrl.host}"&room="${options.roomName}"`; - if (process.env.IFRAME_TENANT) { - url = `${url}&tenant="${process.env.IFRAME_TENANT}"`; + if (testsConfig.iframe.tenant) { + url = `${url}&tenant="${testsConfig.iframe.tenant}"`; } else if (baseUrl.pathname.length > 1) { // remove leading slash url = `${url}&tenant="${baseUrl.pathname.substring(1)}"`; diff --git a/tests/helpers/TestsConfig.ts b/tests/helpers/TestsConfig.ts new file mode 100644 index 0000000000..0278dc64ea --- /dev/null +++ b/tests/helpers/TestsConfig.ts @@ -0,0 +1,44 @@ +/** + * Global configuration that the tests are run with. Loaded from environment variables. + */ +export const config = { + /** Enable debug logging. Note this includes private information from .env */ + debug: Boolean(process.env.JITSI_DEBUG?.trim()), + iframe: { + customerId: process.env.IFRAME_TENANT?.trim()?.replace('vpaas-magic-cookie-', ''), + tenant: process.env.IFRAME_TENANT?.trim(), + /** Whether the configuration specifies a JaaS account for the iFrame API tests. */ + usesJaas: Boolean(process.env.JWT_PRIVATE_KEY_PATH && process.env.JWT_KID?.startsWith('vpaas-magic-cookie-')), + }, + jaas: { + /** Whether the configuration for JaaS specific tests is enabled. */ + enabled: Boolean(process.env.JAAS_TENANT && process.env.JAAS_PRIVATE_KEY_PATH && process.env.JAAS_KID), + /** The JaaS key ID, used to sign the tokens. */ + kid: process.env.JAAS_KID?.trim(), + /** The path to the JaaS private key, used to sign JaaS tokens. */ + privateKeyPath: process.env.JAAS_PRIVATE_KEY_PATH?.trim(), + /** The JaaS tenant (vpaas-magic-cookie-) . */ + tenant: process.env.JAAS_TENANT?.trim(), + }, + jwt: { + kid: process.env.JWT_KID?.trim(), + /** A pre-configured token used by some tests. */ + preconfiguredToken: process.env.JWT_ACCESS_TOKEN?.trim(), + privateKeyPath: process.env.JWT_PRIVATE_KEY_PATH?.trim() + }, + roomName: { + /** Optional prefix for room names used for tests. */ + prefix: process.env.ROOM_NAME_PREFIX?.trim(), + /** Optional suffix for room names used for tests. */ + suffix: process.env.ROOM_NAME_SUFFIX?.trim() + }, + webhooksProxy: { + enabled: Boolean(process.env.WEBHOOKS_PROXY_URL && process.env.WEBHOOKS_PROXY_SHARED_SECRET), + sharedSecret: process.env.WEBHOOKS_PROXY_SHARED_SECRET?.trim(), + url: process.env.WEBHOOKS_PROXY_URL?.trim(), + } +}; + +if (config.debug) { + console.log('TestsConfig:', JSON.stringify(config, null, 2)); +} diff --git a/tests/helpers/participants.ts b/tests/helpers/participants.ts index 3c5a4f7c12..e7273c1ba9 100644 --- a/tests/helpers/participants.ts +++ b/tests/helpers/participants.ts @@ -1,6 +1,5 @@ -import process from 'node:process'; - import { P1, P2, P3, P4, Participant } from './Participant'; +import { config } from './TestsConfig'; import { generateToken } from './token'; import { IJoinOptions, IParticipantOptions } from './types'; @@ -17,14 +16,14 @@ export async function ensureOneParticipant(options?: IJoinOptions): Promise { it('joining the meeting', async () => { // if we are running with token this becomes ugly to match the URL - if (process.env.JWT_ACCESS_TOKEN) { + if (config.jwt.preconfiguredToken) { ctx.skipSuiteTests = true; return; diff --git a/tests/specs/3way/audioVideoModeration.spec.ts b/tests/specs/3way/audioVideoModeration.spec.ts index ba272ad051..8bfffb3db3 100644 --- a/tests/specs/3way/audioVideoModeration.spec.ts +++ b/tests/specs/3way/audioVideoModeration.spec.ts @@ -1,4 +1,5 @@ import { Participant } from '../../helpers/Participant'; +import { config } from '../../helpers/TestsConfig'; import { ensureOneParticipant, ensureThreeParticipants, ensureTwoParticipants, @@ -78,7 +79,7 @@ describe('AVModeration', () => { it('hangup and change moderator', async () => { // no moderator switching if jaas is available. - if (ctx.iFrameUsesJaas) { + if (config.iframe.usesJaas) { return; } diff --git a/tests/specs/3way/lobby.spec.ts b/tests/specs/3way/lobby.spec.ts index 466ad1494a..600f293887 100644 --- a/tests/specs/3way/lobby.spec.ts +++ b/tests/specs/3way/lobby.spec.ts @@ -1,4 +1,5 @@ import { P1, P3, Participant } from '../../helpers/Participant'; +import { config } from '../../helpers/TestsConfig'; import { ensureOneParticipant, ensureThreeParticipants, @@ -196,7 +197,7 @@ describe('Lobby', () => { it('change of moderators in lobby', async () => { // no moderator switching if jaas is available. - if (ctx.iFrameUsesJaas) { + if (config.iframe.usesJaas) { return; } await hangupAllParticipants(); @@ -288,7 +289,7 @@ describe('Lobby', () => { it('moderator leaves while lobby enabled', async () => { // no moderator switching if jaas is available. - if (ctx.iFrameUsesJaas) { + if (config.iframe.usesJaas) { return; } const { p1, p2, p3 } = ctx; diff --git a/tests/specs/helpers/jaas.ts b/tests/specs/helpers/jaas.ts index 54b323fc36..e4689c21ed 100644 --- a/tests/specs/helpers/jaas.ts +++ b/tests/specs/helpers/jaas.ts @@ -1,23 +1,24 @@ import type { Participant } from '../../helpers/Participant'; +import { config } from '../../helpers/TestsConfig'; import { joinParticipant } from '../../helpers/participants'; import { IToken, ITokenOptions, generateToken } from '../../helpers/token'; export function generateJaasToken(options: ITokenOptions): IToken { - if (!process.env.JAAS_PRIVATE_KEY_PATH || !process.env.JAAS_KID) { - throw new Error('JAAS_PRIVATE_KEY_PATH and JAAS_KID environment variables must be set'); + if (!config.jaas.enabled) { + throw new Error('JaaS is not configured.'); } // Don't override the keyId and keyPath if they are already set in options, allow tests to set them. return generateToken({ ...options, - keyId: options.keyId || process.env.JAAS_KID, - keyPath: options.keyPath || process.env.JAAS_PRIVATE_KEY_PATH, + keyId: options.keyId || config.jaas.kid, + keyPath: options.keyPath || config.jaas.privateKeyPath }); } /** * Creates a new Participant and joins the MUC with the given name. The jaas-specific properties must be set as - * environment variables: IFRAME_TENANT. + * environment variables (see env.example and TestsConfig.ts). * * @param instanceId This is the "name" passed to the Participant, I think it's used to match against one of the * pre-configured browser instances in wdio? It must be one of 'p1', 'p2', 'p3', or 'p4'. TODO: figure out how this @@ -28,15 +29,15 @@ export function generateJaasToken(options: ITokenOptions): IToken { */ export async function joinMuc(instanceId: 'p1' | 'p2' | 'p3' | 'p4', token?: IToken, roomName?: string): Promise { - if (!process.env.JAAS_TENANT) { - throw new Error('JAAS_TENANT environment variables must be set'); + if (!config.jaas.enabled) { + throw new Error('JaaS is not configured.'); } return await joinParticipant({ name: instanceId, token }, { - forceTenant: process.env.JAAS_TENANT, + forceTenant: config.jaas.tenant, roomName }); } diff --git a/tests/specs/iframe/invite.spec.ts b/tests/specs/iframe/invite.spec.ts index 638e44b55d..64b6c62386 100644 --- a/tests/specs/iframe/invite.spec.ts +++ b/tests/specs/iframe/invite.spec.ts @@ -1,5 +1,6 @@ import type { Participant } from '../../helpers/Participant'; import { setTestProperties } from '../../helpers/TestProperties'; +import { config as testsConfig } from '../../helpers/TestsConfig'; import { ensureOneParticipant } from '../../helpers/participants'; import { cleanup, @@ -13,6 +14,8 @@ setTestProperties(__filename, { useWebhookProxy: true }); +const customerId = testsConfig.iframe.customerId; + describe('Invite iframeAPI', () => { let dialInDisabled: boolean; let dialOutDisabled: boolean; @@ -102,7 +105,6 @@ describe('Invite iframeAPI', () => { const { webhooksProxy } = ctx; if (webhooksProxy) { - const customerId = process.env.IFRAME_TENANT?.replace('vpaas-magic-cookie-', ''); const sipCallOutStartedEvent: { customerId: string; data: { @@ -157,7 +159,6 @@ async function checkDialEvents(participant: Participant, direction: string, star const { webhooksProxy } = ctx; if (webhooksProxy) { - const customerId = process.env.IFRAME_TENANT?.replace('vpaas-magic-cookie-', ''); const dialInStartedEvent: { customerId: string; data: { diff --git a/tests/specs/iframe/participantsPresence.spec.ts b/tests/specs/iframe/participantsPresence.spec.ts index e749b035b4..20bfa76c7f 100644 --- a/tests/specs/iframe/participantsPresence.spec.ts +++ b/tests/specs/iframe/participantsPresence.spec.ts @@ -2,6 +2,7 @@ import { isEqual } from 'lodash-es'; import { P1, P2, Participant } from '../../helpers/Participant'; import { setTestProperties } from '../../helpers/TestProperties'; +import { config as testsConfig } from '../../helpers/TestsConfig'; import { ensureTwoParticipants, parseJid } from '../../helpers/participants'; setTestProperties(__filename, { @@ -45,7 +46,7 @@ async function checkParticipantLeftHook(p: Participant, reason: string, checkId expect(event.data.id).toBe(jwtPayload?.context?.user?.id); expect(event.data.group).toBe(jwtPayload?.context?.group); - expect(event.customerId).toBe(process.env.IFRAME_TENANT?.replace('vpaas-magic-cookie-', '')); + expect(event.customerId).toBe(testsConfig.iframe.customerId); } } } diff --git a/tests/specs/iframe/recording.spec.ts b/tests/specs/iframe/recording.spec.ts index 66af9a275e..da8f9d64b4 100644 --- a/tests/specs/iframe/recording.spec.ts +++ b/tests/specs/iframe/recording.spec.ts @@ -1,4 +1,5 @@ import { setTestProperties } from '../../helpers/TestProperties'; +import { config as testsConfig } from '../../helpers/TestsConfig'; import { ensureOneParticipant } from '../../helpers/participants'; setTestProperties(__filename, { @@ -6,6 +7,8 @@ setTestProperties(__filename, { useWebhookProxy: true }); +const { tenant, customerId } = testsConfig.iframe; + describe('Recording', () => { let recordingDisabled: boolean; let liveStreamingDisabled: boolean; @@ -69,7 +72,6 @@ describe('Recording', () => { }); if (webhooksProxy) { - const customerId = process.env.IFRAME_TENANT?.replace('vpaas-magic-cookie-', ''); const liveStreamEvent: { customerId: string; eventType: string; @@ -93,7 +95,6 @@ describe('Recording', () => { await p1.getIframeAPI().executeCommand('stopRecording', 'stream'); if (webhooksProxy) { - const customerId = process.env.IFRAME_TENANT?.replace('vpaas-magic-cookie-', ''); const liveStreamEvent: { customerId: string; eventType: string; @@ -132,7 +133,6 @@ async function testRecordingStarted(command: boolean) { } if (webhooksProxy) { - const customerId = process.env.IFRAME_TENANT?.replace('vpaas-magic-cookie-', ''); const recordingEvent: { customerId: string; eventType: string; @@ -152,7 +152,7 @@ async function testRecordingStarted(command: boolean) { const linkEvent = (await p1.getIframeAPI().getEventResult('recordingLinkAvailable')); expect(linkEvent.link.startsWith('https://')).toBe(true); - expect(linkEvent.link.includes(process.env.IFRAME_TENANT)).toBe(true); + expect(linkEvent.link.includes(tenant)).toBe(true); expect(linkEvent.ttl > 0).toBe(true); } @@ -171,7 +171,6 @@ async function testRecordingStopped(command: boolean) { } if (webhooksProxy) { - const customerId = process.env.IFRAME_TENANT?.replace('vpaas-magic-cookie-', ''); const liveStreamEvent: { customerId: string; eventType: string; diff --git a/tests/specs/iframe/visitors.spec.ts b/tests/specs/iframe/visitors.spec.ts index 38d8e5d637..ca69290cdc 100644 --- a/tests/specs/iframe/visitors.spec.ts +++ b/tests/specs/iframe/visitors.spec.ts @@ -1,4 +1,5 @@ import { setTestProperties } from '../../helpers/TestProperties'; +import { config as testsConfig } from '../../helpers/TestsConfig'; import { ensureOneParticipant, ensureTwoParticipants } from '../../helpers/participants'; setTestProperties(__filename, { @@ -90,7 +91,7 @@ describe('Visitors', () => { expect(event.data.participantJid.indexOf('meet.jitsi') != -1).toBe(true); expect(event.data.name).toBe(p2.name); expect(event.data.role).toBe('visitor'); - expect(event.customerId).toBe(process.env.IFRAME_TENANT?.replace('vpaas-magic-cookie-', '')); + expect(event.customerId).toBe(testsConfig.iframe.customerId); await p2.switchToAPI(); await p2.getIframeAPI().executeCommand('hangup'); @@ -120,7 +121,7 @@ describe('Visitors', () => { expect(eventLeft.data.participantJid.indexOf('meet.jitsi') != -1).toBe(true); expect(eventLeft.data.name).toBe(p2.name); expect(eventLeft.data.role).toBe('visitor'); - expect(eventLeft.customerId).toBe(process.env.IFRAME_TENANT?.replace('vpaas-magic-cookie-', '')); + expect(eventLeft.customerId).toBe(testsConfig.iframe.customerId); } }); }); diff --git a/tests/wdio.conf.ts b/tests/wdio.conf.ts index 22d799d518..5407689503 100644 --- a/tests/wdio.conf.ts +++ b/tests/wdio.conf.ts @@ -7,10 +7,11 @@ import process from 'node:process'; import pretty from 'pretty'; import { getTestProperties, loadTestFiles } from './helpers/TestProperties'; +import { config as testsConfig } from './helpers/TestsConfig'; import WebhookProxy from './helpers/WebhookProxy'; import { getLogs, initLogger, logInfo } from './helpers/browserLogger'; import { IContext } from './helpers/types'; -import { getRandomNumberAsStr } from './helpers/utils'; +import { generateRoomName } from './helpers/utils'; // eslint-disable-next-line @typescript-eslint/no-var-requires const allure = require('allure-commandline'); @@ -231,33 +232,19 @@ export const config: WebdriverIO.MultiremoteConfig = { bInstance.iframePageBase = `file://${path.dirname(rpath)}`; })); - globalAny.ctx.roomName = `${testName}-${getRandomNumberAsStr(40, 3)}`; - if (process.env.ROOM_NAME_PREFIX) { - globalAny.ctx.roomName = `${process.env.ROOM_NAME_PREFIX.trim()}_${globalAny.ctx.roomName}`; - } - if (process.env.ROOM_NAME_SUFFIX) { - globalAny.ctx.roomName += `_${process.env.ROOM_NAME_SUFFIX.trim()}`; - } - - globalAny.ctx.roomName = globalAny.ctx.roomName.toLowerCase(); - globalAny.ctx.iFrameUsesJaas = process.env.JWT_PRIVATE_KEY_PATH - && process.env.JWT_KID?.startsWith('vpaas-magic-cookie-'); - - const isJaasConfigured = process.env.JAAS_TENANT && process.env.JAAS_PRIVATE_KEY_PATH && process.env.JAAS_KID; + globalAny.ctx.roomName = generateRoomName(testName); // If we are running the iFrameApi tests, we need to mark it as such and if needed to create the proxy // and connect to it. - if (testProperties.useWebhookProxy) { - if (!globalAny.ctx.webhooksProxy - && process.env.WEBHOOKS_PROXY_URL && process.env.WEBHOOKS_PROXY_SHARED_SECRET) { - globalAny.ctx.webhooksProxy = new WebhookProxy( - `${process.env.WEBHOOKS_PROXY_URL}?tenant=${ - isJaasConfigured ? process.env.JAAS_TENANT : process.env.IFRAME_TENANT - }&room=${globalAny.ctx.roomName}`, - process.env.WEBHOOKS_PROXY_SHARED_SECRET, - `${TEST_RESULTS_DIR}/webhooks-${cid}-${testName}.log`); - globalAny.ctx.webhooksProxy.connect(); - } + if (testProperties.useWebhookProxy && testsConfig.webhooksProxy.enabled && !globalAny.ctx.webhooksProxy) { + // Note this prevents iframe and jaas test from running together. + const tenant = testsConfig.jaas.enabled ? testsConfig.jaas.tenant : testsConfig.iframe.tenant; + + globalAny.ctx.webhooksProxy = new WebhookProxy( + `${testsConfig.webhooksProxy.url}?tenant=${tenant}&room=${globalAny.ctx.roomName}`, + testsConfig.webhooksProxy.sharedSecret!, + `${TEST_RESULTS_DIR}/webhooks-${cid}-${testName}.log`); + globalAny.ctx.webhooksProxy.connect(); } if (testProperties.useWebhookProxy && !globalAny.ctx.webhooksProxy) { @@ -265,9 +252,8 @@ export const config: WebdriverIO.MultiremoteConfig = { globalAny.ctx.skipSuiteTests = true; } - if (testProperties.useJaas && !isJaasConfigured) { - console.warn(`JaaS is not configured, skipping ${testName}. ` - + 'Set JAAS_TENANT, JAAS_KID, and JAAS_PRIVATE_KEY_PATH to enable.'); + if (testProperties.useJaas && !testsConfig.jaas.enabled) { + console.warn(`JaaS is not configured, skipping ${testName}.`); globalAny.ctx.skipSuiteTests = true; } },