Fix race condition on switching calls (#2591)

This commit is contained in:
Claudio Costa
2023-03-07 18:23:21 -06:00
committed by GitHub
parent 893f13e59d
commit 49ed221659
4 changed files with 73 additions and 26 deletions

View File

@@ -75,13 +75,15 @@ describe('main/windows/callsWidgetWindow', () => {
baseWindow.setAlwaysOnTop = jest.fn(); baseWindow.setAlwaysOnTop = jest.fn();
baseWindow.setBackgroundColor = jest.fn(); baseWindow.setBackgroundColor = jest.fn();
baseWindow.setMenuBarVisibility = jest.fn(); baseWindow.setMenuBarVisibility = jest.fn();
baseWindow.setBounds = jest.fn();
baseWindow.webContents = { baseWindow.webContents = {
setWindowOpenHandler: jest.fn(), setWindowOpenHandler: jest.fn(),
on: jest.fn(), on: jest.fn(),
}; };
baseWindow.isDestroyed = jest.fn(() => false);
beforeEach(() => { beforeEach(() => {
baseWindow.setBounds = jest.fn();
mainWindow.getBounds.mockImplementation(() => { mainWindow.getBounds.mockImplementation(() => {
return { return {
x: 0, x: 0,
@@ -100,6 +102,14 @@ describe('main/windows/callsWidgetWindow', () => {
}; };
}); });
baseWindow.show = jest.fn(() => {
baseWindow.emit('show');
});
baseWindow.close = jest.fn(() => {
baseWindow.emit('closed');
});
baseWindow.loadURL.mockImplementation(() => ({ baseWindow.loadURL.mockImplementation(() => ({
catch: jest.fn(), catch: jest.fn(),
})); }));
@@ -108,6 +118,8 @@ describe('main/windows/callsWidgetWindow', () => {
afterEach(() => { afterEach(() => {
jest.resetAllMocks(); jest.resetAllMocks();
baseWindow.removeAllListeners('show');
baseWindow.removeAllListeners('ready-to-show');
}); });
it('verify initial configuration', () => { it('verify initial configuration', () => {
@@ -175,14 +187,24 @@ describe('main/windows/callsWidgetWindow', () => {
expect(widgetWindow.win.webContents.openDevTools).toHaveBeenCalled(); expect(widgetWindow.win.webContents.openDevTools).toHaveBeenCalled();
}); });
it('closing window', () => { it('closing window', async () => {
baseWindow.close = jest.fn(() => { const widgetWindow = new CallsWidgetWindow(mainWindow, mainView, widgetConfig);
baseWindow.emit('closed');
await widgetWindow.close();
expect(widgetWindow.win.close).toHaveBeenCalled();
expect(widgetWindow.win.isDestroyed).toHaveBeenCalled();
}); });
it('closing window - already closed', async () => {
baseWindow.isDestroyed = jest.fn().mockReturnValue(true);
const widgetWindow = new CallsWidgetWindow(mainWindow, mainView, widgetConfig); const widgetWindow = new CallsWidgetWindow(mainWindow, mainView, widgetConfig);
widgetWindow.close();
expect(widgetWindow.win.close).toHaveBeenCalled(); await widgetWindow.close();
expect(widgetWindow.win.isDestroyed).toHaveBeenCalled();
expect(widgetWindow.win.close).not.toHaveBeenCalled();
}); });
it('resize', () => { it('resize', () => {
@@ -191,10 +213,6 @@ describe('main/windows/callsWidgetWindow', () => {
id: 'windowID', id: 'windowID',
}; };
baseWindow.show = jest.fn(() => {
baseWindow.emit('show');
});
let winBounds = { let winBounds = {
x: 0, x: 0,
y: 0, y: 0,
@@ -209,12 +227,18 @@ describe('main/windows/callsWidgetWindow', () => {
winBounds = bounds; winBounds = bounds;
}); });
baseWindow.show = jest.fn(() => {
baseWindow.emit('show');
});
expect(baseWindow.setBounds).not.toHaveBeenCalled();
baseWindow.webContents.getZoomFactor = jest.fn(() => 1.0); baseWindow.webContents.getZoomFactor = jest.fn(() => 1.0);
const widgetWindow = new CallsWidgetWindow(mainWindow, mainView, widgetConfig); const widgetWindow = new CallsWidgetWindow(mainWindow, mainView, widgetConfig);
widgetWindow.win.emit('ready-to-show'); widgetWindow.win.emit('ready-to-show');
expect(baseWindow.setBounds).toHaveBeenCalledTimes(2); expect(baseWindow.setBounds).toHaveBeenCalledTimes(1);
expect(baseWindow.setBounds).toHaveBeenCalledWith({ expect(baseWindow.setBounds).toHaveBeenCalledWith({
x: 12, x: 12,
@@ -260,10 +284,6 @@ describe('main/windows/callsWidgetWindow', () => {
id: 'windowID', id: 'windowID',
}; };
baseWindow.show = jest.fn(() => {
baseWindow.emit('show');
});
let winBounds = { let winBounds = {
x: 0, x: 0,
y: 0, y: 0,

View File

@@ -89,9 +89,16 @@ export default class CallsWidgetWindow extends EventEmitter {
this.load(); this.load();
} }
public close() { public async close() {
log.debug('CallsWidgetWindow.close'); log.debug('CallsWidgetWindow.close');
return new Promise<void>((resolve) => {
if (this.win.isDestroyed()) {
resolve();
return;
}
this.once('closed', resolve);
this.win.close(); this.win.close();
});
} }
public getServerName() { public getServerName() {

View File

@@ -1032,6 +1032,23 @@ describe('main/windows/windowManager', () => {
}, },
}, },
}; };
beforeEach(() => {
CallsWidgetWindow.mockImplementation(() => {
return {
win: {
isDestroyed: jest.fn(() => true),
},
on: jest.fn(),
close: jest.fn(),
};
});
});
afterEach(() => {
jest.resetAllMocks();
});
const windowManager = new WindowManager(); const windowManager = new WindowManager();
windowManager.viewManager = { windowManager.viewManager = {
views: new Map([ views: new Map([
@@ -1039,25 +1056,25 @@ describe('main/windows/windowManager', () => {
]), ]),
}; };
it('should create calls widget window', () => { it('should create calls widget window', async () => {
expect(windowManager.callsWidgetWindow).toBeUndefined(); expect(windowManager.callsWidgetWindow).toBeUndefined();
windowManager.createCallsWidgetWindow('server-1_tab-messaging', {callID: 'test'}); await windowManager.createCallsWidgetWindow('server-1_tab-messaging', {callID: 'test'});
expect(windowManager.callsWidgetWindow).toBeDefined(); expect(windowManager.callsWidgetWindow).toBeDefined();
}); });
it('should not create a new window if call is the same', () => { it('should not create a new window if call is the same', async () => {
const widgetWindow = windowManager.callsWidgetWindow; const widgetWindow = windowManager.callsWidgetWindow;
expect(widgetWindow).toBeDefined(); expect(widgetWindow).toBeDefined();
widgetWindow.getCallID = jest.fn(() => 'test'); widgetWindow.getCallID = jest.fn(() => 'test');
windowManager.createCallsWidgetWindow('server-1_tab-messaging', {callID: 'test'}); await windowManager.createCallsWidgetWindow('server-1_tab-messaging', {callID: 'test'});
expect(windowManager.callsWidgetWindow).toEqual(widgetWindow); expect(windowManager.callsWidgetWindow).toEqual(widgetWindow);
}); });
it('should create a new window if switching calls', () => { it('should create a new window if switching calls', async () => {
const widgetWindow = windowManager.callsWidgetWindow; const widgetWindow = windowManager.callsWidgetWindow;
expect(widgetWindow).toBeDefined(); expect(widgetWindow).toBeDefined();
widgetWindow.getCallID = jest.fn(() => 'test'); widgetWindow.getCallID = jest.fn(() => 'test');
windowManager.createCallsWidgetWindow('server-1_tab-messaging', {callID: 'test2'}); await windowManager.createCallsWidgetWindow('server-1_tab-messaging', {callID: 'test2'});
expect(windowManager.callsWidgetWindow).not.toEqual(widgetWindow); expect(windowManager.callsWidgetWindow).not.toEqual(widgetWindow);
}); });
}); });

View File

@@ -127,14 +127,17 @@ export class WindowManager {
}; };
} }
createCallsWidgetWindow = (viewName: string, msg: CallsJoinCallMessage) => { createCallsWidgetWindow = async (viewName: string, msg: CallsJoinCallMessage) => {
log.debug('WindowManager.createCallsWidgetWindow'); log.debug('WindowManager.createCallsWidgetWindow');
if (this.callsWidgetWindow) { if (this.callsWidgetWindow) {
// trying to join again the call we are already in should not be allowed. // trying to join again the call we are already in should not be allowed.
if (this.callsWidgetWindow.getCallID() === msg.callID) { if (this.callsWidgetWindow.getCallID() === msg.callID) {
return; return;
} }
this.callsWidgetWindow.close();
// to switch from one call to another we need to wait for the existing
// window to be fully closed.
await this.callsWidgetWindow.close();
} }
const currentView = this.viewManager?.views.get(viewName); const currentView = this.viewManager?.views.get(viewName);
if (!currentView) { if (!currentView) {