Skip to content

Commit

Permalink
feat: Adds option to test and webhooks.
Browse files Browse the repository at this point in the history
  • Loading branch information
damencho committed Dec 9, 2024
1 parent d173ebc commit 8126574
Show file tree
Hide file tree
Showing 6 changed files with 302 additions and 21 deletions.
5 changes: 5 additions & 0 deletions tests/env.example
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@
#JWT_PRIVATE_KEY_PATH=
# The kid to use in the token
#JWT_KID=

# The address of the webhooks proxy used to test the webhooks feature (e.g. wss://your.service/?tenant=sometenant)
#WEBHOOKS_PROXY_URL=
# A shared secret to authenticate the webhook proxy connection
#WEBHOOKS_PROXY_SHARED_SECRET=
128 changes: 128 additions & 0 deletions tests/helpers/WebhookProxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import WebSocket from 'ws';

/**
* Uses the webhook proxy service to proxy events to the testing clients.
*/
export default class WebhookProxy {
private url;
private secret;
private ws: WebSocket | undefined;
private cache = new Map();
private listeners = new Map();
private consumers = new Map();

/**
* Initializes the webhook proxy.
* @param url
* @param secret
*/
constructor(url: string, secret: string) {
this.url = url;
this.secret = secret;
}

/**
* Connects.
*/
connect() {
this.ws = new WebSocket(this.url, {
headers: {
Authorization: this.secret
}
});

this.ws.on('error', console.error);

this.ws.on('open', function open() {
console.log('WebhookProxy connected');
});

this.ws.on('message', (data: any) => {
const msg = JSON.parse(data.toString());

if (msg.eventType) {
if (this.consumers.has(msg.eventType)) {
this.consumers.get(msg.eventType)(msg);
this.consumers.delete(msg.eventType);
} else {
this.cache.set(msg.eventType, msg);
}

if (this.listeners.has(msg.eventType)) {
this.listeners.get(msg.eventType)(msg);
}
}
});
}

/**
* Adds event consumer. Consumers receive the event single time and we remove them from the list of consumers.
* @param eventType
* @param callback
*/
addConsumer(eventType: string, callback: (deventata: any) => void) {
if (this.cache.has(eventType)) {
callback(this.cache.get(eventType));
this.cache.delete(eventType);

return;
}

this.consumers.set(eventType, callback);
}

/**
* Clear any stored event.
*/
clearCache() {
this.cache.clear();
}

/**
* Waits for the event to be received.
* @param eventType
* @param timeout
*/
async waitForEvent(eventType: string, timeout = 3000): Promise<any> {
return new Promise((resolve, reject) => {
const waiter = setTimeout(() => {
reject(new Error(`Timeout waiting for event:${eventType}`));
}, timeout);

this.addConsumer(eventType, event => {
clearTimeout(waiter);

resolve(event);
});

});
}

/**
* Adds a listener for the event type.
* @param eventType
* @param callback
*/
addListener(eventType: string, callback: (data: any) => void) {
this.listeners.set(eventType, callback);
}

/**
* Adds a listener for the event type.
* @param eventType
*/
removeListener(eventType: string) {
this.listeners.delete(eventType);
}

/**
* Disconnects the webhook proxy.
*/
disconnect() {
if (this.ws) {
this.ws.close();
console.log('WebhookProxy disconnected');
this.ws = undefined;
}
}
}
25 changes: 22 additions & 3 deletions tests/helpers/participants.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
import fs from 'fs';
import jwt from 'jsonwebtoken';
import process from 'node:process';
import { v4 as uuidv4 } from 'uuid';

import { Participant } from './Participant';
import WebhookProxy from './WebhookProxy';
import { IContext } from './types';

/**
* Generate a random room name.
* Everytime we generate a name and iframeAPI is enabled and there is a configured
* webhooks proxy we connect to it with the new room name.
*
* @returns {string} - The random room name.
*/
function generateRandomRoomName(): string {
return `jitsimeettorture-${crypto.randomUUID()}`;
const roomName = `jitsimeettorture-${crypto.randomUUID()}`;

if (context.iframeAPI && !context.webhooksProxy
&& process.env.WEBHOOKS_PROXY_URL && process.env.WEBHOOKS_PROXY_SHARED_SECRET) {
context.webhooksProxy = new WebhookProxy(`${process.env.WEBHOOKS_PROXY_URL}&room=${roomName}`,
process.env.WEBHOOKS_PROXY_SHARED_SECRET);
context.webhooksProxy.connect();
}

return roomName;
}

/**
Expand All @@ -21,7 +34,9 @@ function generateRandomRoomName(): string {
* @returns {Promise<void>}
*/
export async function ensureOneParticipant(context: IContext): Promise<void> {
context.roomName = generateRandomRoomName();
if (!context.roomName) {
context.roomName = generateRandomRoomName();
}

context.p1 = new Participant('participant1');

Expand All @@ -35,7 +50,9 @@ export async function ensureOneParticipant(context: IContext): Promise<void> {
* @returns {Promise<void>}
*/
export async function ensureThreeParticipants(context: IContext): Promise<void> {
context.roomName = generateRandomRoomName();
if (!context.roomName) {
context.roomName = generateRandomRoomName();
}

const p1 = new Participant('participant1');
const p2 = new Participant('participant2');
Expand Down Expand Up @@ -201,7 +218,9 @@ function getModeratorToken(displayName: string) {
'room': '*'
};

// @ts-ignore
payload.context.user.moderator = true;

// @ts-ignore
return jwt.sign(payload, key, headers);
}
3 changes: 3 additions & 0 deletions tests/helpers/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { Participant } from './Participant';
import WebhookProxy from './WebhookProxy';

export type IContext = {
conferenceJid: string;
iframeAPI: boolean;
jwtKid: string;
jwtPrivateKeyPath: string;
Expand All @@ -9,4 +11,5 @@ export type IContext = {
p3: Participant;
p4: Participant;
roomName: string;
webhooksProxy: WebhookProxy;
};
Loading

0 comments on commit 8126574

Please sign in to comment.