From feb622501b43a65326e5bdf1c0a1e1524a9981c0 Mon Sep 17 00:00:00 2001 From: Salah Benmoussati <51402489+sbenmoussati@users.noreply.github.com> Date: Wed, 22 Jan 2025 12:18:38 +0100 Subject: [PATCH] SDA-4770 Adaptations on openfin integration (#2268) * SDA-4770 Adaptations on openfin integration * SDA-4770 Adaptations on openfin integration --- spec/mainApiHandler.spec.ts | 24 ++++++++++ spec/openfinHandler.spec.ts | 87 +++++++++++++++++++++++++++++++----- src/app/main-api-handler.ts | 8 ++++ src/app/openfin-handler.ts | 40 +++++++++++++++-- src/common/api-interface.ts | 3 ++ src/renderer/preload-main.ts | 4 ++ src/renderer/ssf-api.ts | 30 +++++++++++++ 7 files changed, 182 insertions(+), 14 deletions(-) diff --git a/spec/mainApiHandler.spec.ts b/spec/mainApiHandler.spec.ts index a79be1d90..2423be67b 100644 --- a/spec/mainApiHandler.spec.ts +++ b/spec/mainApiHandler.spec.ts @@ -27,6 +27,8 @@ jest.mock('../src/app/openfin-handler', () => { getAllClientsInContextGroup: jest.fn(), registerIntentHandler: jest.fn(), unregisterIntentHandler: jest.fn(), + fireIntentForContext: jest.fn(), + removeClientFromContextGroup: jest.fn(), }, }; }); @@ -712,5 +714,27 @@ describe('main api handler', () => { expect(spy).toHaveBeenCalledTimes(1); }); + + it('should call `fireIntentForContext`', () => { + const spy = jest.spyOn(openfinHandler, 'fireIntentForContext'); + const value = { + cmd: apiCmds.openfinFireIntentForContext, + }; + + ipcMain.send(apiName.symphonyApi, value); + + expect(spy).toHaveBeenCalledTimes(1); + }); + + it('should call `removeClientFromContextGroup`', () => { + const spy = jest.spyOn(openfinHandler, 'removeClientFromContextGroup'); + const value = { + cmd: apiCmds.openfinRemoveClientFromContextGroup, + }; + + ipcMain.send(apiName.symphonyApi, value); + + expect(spy).toHaveBeenCalledTimes(1); + }); }); }); diff --git a/spec/openfinHandler.spec.ts b/spec/openfinHandler.spec.ts index d6a35a9fe..d7322657a 100644 --- a/spec/openfinHandler.spec.ts +++ b/spec/openfinHandler.spec.ts @@ -14,6 +14,8 @@ jest.mock('@openfin/node-adapter', () => ({ getAllClientsInContextGroup: jest.fn(), joinContextGroup: jest.fn(), getContextGroups: jest.fn(), + fireIntentForContext: jest.fn(), + removeClientFromContextGroup: jest.fn(), }), }, }); @@ -50,10 +52,8 @@ describe('Openfin', () => { }); it('should not be connected', () => { - const info = openfinHandler.getInfo(); const connectionStatus = openfinHandler.getConnectionStatus(); - expect(info.isConnected).toBeFalsy(); expect(connectionStatus.isConnected).toBeFalsy(); }); @@ -61,13 +61,48 @@ describe('Openfin', () => { const connectSyncSpy = jest.spyOn(connectMock.Interop, 'connectSync'); await openfinHandler.connect(); - const info = openfinHandler.getInfo(); - const isConnected = openfinHandler.getConnectionStatus(); + const connectionStatus = openfinHandler.getConnectionStatus(); expect(connect).toHaveBeenCalled(); expect(connectSyncSpy).toHaveBeenCalledTimes(1); - expect(info.isConnected).toBeTruthy(); - expect(isConnected).toBeTruthy(); + expect(connectionStatus.isConnected).toBeTruthy(); + }); + + it('should reject and return false if connection times out', async () => { + jest.useFakeTimers(); + const connectSyncSpy = jest + .spyOn(connectMock.Interop, 'connectSync') + .mockImplementationOnce((_channelName) => { + return new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, 12000); + }); + }); + + const connectionTimeoutSpy = jest.spyOn(global, 'setTimeout'); + + let connectionStatus; + + const connectPromise = openfinHandler.connect(); + const resultPromise = connectPromise.then((res) => { + connectionStatus = res; + }); + + jest.advanceTimersByTime(10000); + + expect(connectionStatus).toBeUndefined(); + + await resultPromise; + + expect(connectionStatus.isConnected).toBe(false); + + expect(connectionTimeoutSpy).toHaveBeenCalledTimes(2); + expect(connectionTimeoutSpy.mock.calls[0][1]).toBeGreaterThanOrEqual(10000); + + expect(connectSyncSpy).toHaveBeenCalledTimes(1); + + jest.useRealTimers(); }); it('should reject and return false if connection times out', async () => { @@ -113,10 +148,13 @@ describe('Openfin', () => { await openfinHandler.connect(); const customIntent = { - type: 'fdc3.contact', - name: 'Andy Young', - id: { - email: 'andy.young@example.com', + name: 'ViewContact', + context: { + type: 'fdc3.contact', + name: 'Andy Young', + id: { + email: 'andy.young@example.com', + }, }, }; await openfinHandler.fireIntent(customIntent); @@ -169,4 +207,33 @@ describe('Openfin', () => { expect(getAllClientsInContextGroupSpy).toHaveBeenCalledTimes(1); }); + + it('should fire an intent for a given context', async () => { + const connectSyncMock = await connectMock.Interop.connectSync(); + const fireIntentSpy = jest.spyOn(connectSyncMock, 'fireIntentForContext'); + + await openfinHandler.connect(); + const context = { + type: 'fdc3.contact', + name: 'Andy Young', + id: { + email: 'andy.young@example.com', + }, + }; + await openfinHandler.fireIntentForContext(context); + + expect(fireIntentSpy).toHaveBeenCalledTimes(1); + }); + + it('should remove client from context group', async () => { + const connectSyncMock = await connectMock.Interop.connectSync(); + const fireIntentSpy = jest.spyOn( + connectSyncMock, + 'removeClientFromContextGroup', + ); + + await openfinHandler.removeClientFromContextGroup(); + + expect(fireIntentSpy).toHaveBeenCalledTimes(1); + }); }); diff --git a/src/app/main-api-handler.ts b/src/app/main-api-handler.ts index 42d67374c..55d433722 100644 --- a/src/app/main-api-handler.ts +++ b/src/app/main-api-handler.ts @@ -569,6 +569,12 @@ ipcMain.on( case apiCmds.openfinUnregisterIntentHandler: openfinHandler.unregisterIntentHandler(arg.intentName); break; + case apiCmds.openfinFireIntentForContext: + openfinHandler.fireIntentForContext(arg.context); + break; + case apiCmds.openfinRemoveClientFromContextGroup: + openfinHandler.removeClientFromContextGroup(); + break; default: break; } @@ -649,6 +655,8 @@ ipcMain.handle( return openfinHandler.getContextGroups(); case apiCmds.openfinGetAllClientsInContextGroup: return openfinHandler.getAllClientsInContextGroup(arg.contextGroupId); + case apiCmds.openfinGetClientInfo: + return openfinHandler.getClientInfo(); default: break; } diff --git a/src/app/openfin-handler.ts b/src/app/openfin-handler.ts index 8131d8d28..60a8c0311 100644 --- a/src/app/openfin-handler.ts +++ b/src/app/openfin-handler.ts @@ -30,8 +30,7 @@ export class OpenfinHandler { const connectionTimeoutPromise = new Promise((_, reject) => setTimeout(() => { logger.error( - `openfin-handler: Connection timeout after ${ - timeoutValue / 1000 + `openfin-handler: Connection timeout after ${timeoutValue / 1000 } seconds`, ); return reject( @@ -174,12 +173,45 @@ export class OpenfinHandler { } /** - * Returns connection status and provider name + * Returns provider name */ public getInfo() { return { provider: OPENFIN_PROVIDER, - isConnected: this.getConnectionStatus().isConnected, + fdc3Version: '', + optionalFeatures: { + OriginatingAppMetadata: false, + UserChannelMembershipAPIs: false, + DesktopAgentBridging: false, + }, + appMetadata: null, + }; + } + + /** + * Fires an intent for a given context + * @param context + */ + public fireIntentForContext(context: any) { + this.interopClient.fireIntentForContext(context); + } + + /** + * Removes a client from current context group + */ + public removeClientFromContextGroup() { + this.interopClient.removeClientFromContextGroup(); + } + + /** + * Returns client name + * + */ + public getClientInfo(): unknown { + const { openfin }: IConfig = config.getConfigFields(['openfin']); + + return { + name: openfin?.uuid || '', }; } diff --git a/src/common/api-interface.ts b/src/common/api-interface.ts index 9f0be7b09..67e41f8a4 100644 --- a/src/common/api-interface.ts +++ b/src/common/api-interface.ts @@ -93,6 +93,9 @@ export enum apiCmds { openfinJoinContextGroup = 'openfin-join-context-group', openfinGetContextGroups = 'openfin-get-context-groups', openfinGetAllClientsInContextGroup = 'openfin-get-all-clients-in-context-group', + openfinFireIntentForContext = 'openfin-fire-intent-for-context', + openfinRemoveClientFromContextGroup = 'openfin-remove-client-from-context-group', + openfinGetClientInfo = 'openfin-get-client-info', } export enum apiName { diff --git a/src/renderer/preload-main.ts b/src/renderer/preload-main.ts index 7b24af3f7..e1304c6e0 100644 --- a/src/renderer/preload-main.ts +++ b/src/renderer/preload-main.ts @@ -117,6 +117,10 @@ if (ssfWindow.ssf) { joinContextGroup: ssfWindow.ssf.openfinJoinContextGroup, getAllClientsInContextGroup: ssfWindow.ssf.openfinGetAllClientsInContextGroup, + fireIntentForContext: ssfWindow.ssf.openfinFireIntentForContext, + removeClientFromContextGroup: + ssfWindow.ssf.openfinRemoveClientFromContextGroup, + getClientInfo: ssfWindow.ssf.openfinGetClientInfo, }); } diff --git a/src/renderer/ssf-api.ts b/src/renderer/ssf-api.ts index 05550dbc9..b85350be6 100644 --- a/src/renderer/ssf-api.ts +++ b/src/renderer/ssf-api.ts @@ -988,6 +988,36 @@ export class SSFApi { }); } + /** + * Fires an intent for a given context + * @param context + */ + public openfinFireIntentForContext(context: any): void { + local.ipcRenderer.send(apiName.symphonyApi, { + cmd: apiCmds.openfinFireIntentForContext, + context, + }); + } + + /** + * Removes client from current context group + */ + public openfinRemoveClientFromContextGroup() { + local.ipcRenderer.send(apiName.symphonyApi, { + cmd: apiCmds.openfinRemoveClientFromContextGroup, + }); + } + + /** + * Returns client info + */ + public async openfinGetClientInfo() { + const info = await local.ipcRenderer.invoke(apiName.symphonyApi, { + cmd: apiCmds.openfinGetClientInfo, + }); + return info; + } + /** * * Returns Openfin connection status