Skip to content

Commit

Permalink
Merge pull request #81 from bugsnag/bengourley/plugin-refactor
Browse files Browse the repository at this point in the history
refactor: Rename electron plugins and add unit tests
  • Loading branch information
bengourley authored Apr 15, 2021
2 parents 492db6c + d9e2bb3 commit 113de84
Show file tree
Hide file tree
Showing 48 changed files with 770 additions and 459 deletions.
21 changes: 14 additions & 7 deletions packages/electron/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 7 additions & 6 deletions packages/electron/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,19 @@
"@bugsnag/plugin-console-breadcrumbs": "^7.9.0",
"@bugsnag/plugin-electron-app": "1.0.0",
"@bugsnag/plugin-electron-app-breadcrumbs": "1.0.0",
"@bugsnag/plugin-electron-client-state-manager": "1.0.0",
"@bugsnag/plugin-electron-device": "1.0.0",
"@bugsnag/plugin-electron-ipc": "1.0.0",
"@bugsnag/plugin-electron-network-status": "1.0.0",
"@bugsnag/plugin-electron-renderer-client-sync": "1.0.0",
"@bugsnag/plugin-electron-event-sync": "1.0.0",
"@bugsnag/plugin-electron-renderer-client-state-updates": "1.0.0",
"@bugsnag/plugin-electron-renderer-event-data": "1.0.0",
"@bugsnag/plugin-electron-session": "^1.0.0",
"@bugsnag/plugin-electron-state-sync": "1.0.0",
"@bugsnag/plugin-window-onerror": "^7.9.0",
"@bugsnag/plugin-window-unhandled-rejection": "^7.9.0",
"@bugsnag/plugin-internal-callback-marker": "^1.0.0",
"@bugsnag/plugin-interaction-breadcrumbs": "^7.9.0",
"@bugsnag/plugin-network-breadcrumbs": "^7.9.0",
"@bugsnag/plugin-node-uncaught-exception": "^7.7.0",
"@bugsnag/plugin-node-unhandled-rejection": "^7.7.0"
"@bugsnag/plugin-node-unhandled-rejection": "^7.7.0",
"@bugsnag/plugin-window-onerror": "^7.9.0",
"@bugsnag/plugin-window-unhandled-rejection": "^7.9.0"
}
}
7 changes: 3 additions & 4 deletions packages/electron/src/client/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@ module.exports = (opts) => {
// main internal plugins go here
const internalPlugins = [
// THIS PLUGIN MUST BE FIRST!
require('@bugsnag/plugin-electron-event-sync/internal-plugin-marker').firstPlugin,
require('@bugsnag/plugin-electron-event-sync/main-event-sync.js'),
require('@bugsnag/plugin-electron-state-sync'),
require('@bugsnag/plugin-internal-callback-marker').FirstPlugin,
require('@bugsnag/plugin-electron-client-state-manager'),
require('@bugsnag/plugin-electron-ipc'),
require('@bugsnag/plugin-node-uncaught-exception'),
require('@bugsnag/plugin-node-unhandled-rejection'),
Expand All @@ -39,7 +38,7 @@ module.exports = (opts) => {
require('@bugsnag/plugin-electron-session')(electron.app, electron.BrowserWindow),
require('@bugsnag/plugin-console-breadcrumbs'),
// THIS PLUGIN MUST BE LAST!
require('@bugsnag/plugin-electron-event-sync/internal-plugin-marker').lastPlugin
require('@bugsnag/plugin-internal-callback-marker').LastPlugin
]

const bugsnag = new Client(opts, schema, internalPlugins, require('../id'))
Expand Down
4 changes: 2 additions & 2 deletions packages/electron/src/client/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ module.exports = (rendererOpts) => {
opts.enabledBreadcrumbTypes = opts.enabledBreadcrumbTypes.filter(type => type !== 'error')

const internalPlugins = [
require('@bugsnag/plugin-electron-renderer-client-sync')(window.__bugsnag_ipc__),
require('@bugsnag/plugin-electron-renderer-client-state-updates')(window.__bugsnag_ipc__),
require('@bugsnag/plugin-electron-network-status')(),
require('@bugsnag/plugin-window-onerror')(),
require('@bugsnag/plugin-window-unhandled-rejection')(),
require('@bugsnag/plugin-network-breadcrumbs')(),
require('@bugsnag/plugin-interaction-breadcrumbs')(),
require('@bugsnag/plugin-console-breadcrumbs'),
require('@bugsnag/plugin-electron-event-sync/renderer-event-sync')(window.__bugsnag_ipc__)
require('@bugsnag/plugin-electron-renderer-event-data')(window.__bugsnag_ipc__)
]

const bugsnag = new Client(opts, schema, internalPlugins, require('../id'))
Expand Down
14 changes: 14 additions & 0 deletions packages/plugin-electron-client-state-manager/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# @bugsnag/plugin-client-state-manager

This plugin provides a wrapper around the parts of state that need to be synchronised, providing a way for listeners to be notified of changes.

The plugin runs in the main Electron process, and patches each of the client mutators whose state we need to synchronise:

- `setUser()`
- `setContext()`
- `addMetadata()`
- `clearMetadata()`

Any call to these methods (which will be from a developer or a plugin calling `Bugsnag.<method>()` in the main process) will emit an event signifying the change and updated value.

Separately, we expose a `bulkUpdate` method for a new renderer to deliver a full state update in one pass.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const EventEmitter = require('events')

module.exports = {
name: 'stateSync',
name: 'clientStateManager',
load: (client) => {
const emitter = new EventEmitter()

Expand All @@ -11,14 +11,14 @@ module.exports = {
const origSetUser = client.setUser
client.setUser = (...args) => {
const ret = origSetUser.call(client, ...args)
emitter.emit('UserUpdate', client.getUser(), null)
emitter.emit('UserUpdate', client.getUser())
return ret
}

const origSetContext = client.setContext
client.setContext = (...args) => {
const ret = origSetContext.call(client, ...args)
emitter.emit('ContextUpdate', client.getContext(), null)
emitter.emit('ContextUpdate', client.getContext())
return ret
}

Expand All @@ -28,7 +28,7 @@ module.exports = {
const [section] = args
if (typeof section === 'string') {
const values = client.getMetadata(section)
emitter.emit('MetadataUpdate', { section, values }, null)
emitter.emit('MetadataUpdate', { section, values })
}
return ret
}
Expand All @@ -39,7 +39,7 @@ module.exports = {
const [section] = args
if (typeof section === 'string') {
const values = client.getMetadata(section)
emitter.emit('MetadataUpdate', { section, values }, null)
emitter.emit('MetadataUpdate', { section, values })
}
return ret
}
Expand All @@ -56,14 +56,10 @@ module.exports = {
for (const section in metadata) {
origAddMetadata.call(client, section, metadata[section])
}
emitter.emit('MetadataReplace', { metadata: client._metadata })
emitter.emit('MetadataReplace', client._metadata)
}
}

return {
events: ['UserUpdate', 'ContextUpdate', 'MetadataUpdate', 'MetadataReplace'],
emitter,
bulkUpdate
}
return { emitter, bulkUpdate }
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@bugsnag/plugin-electron-state-sync",
"name": "@bugsnag/plugin-electron-client-state-manager",
"version": "1.0.0",
"main": "state-sync.js",
"main": "client-state-manager.js",
"description": "@bugsnag/electron plugin to sync state between various processes",
"homepage": "https://www.bugsnag.com/",
"repository": {
Expand All @@ -17,7 +17,7 @@
"license": "MIT",
"gypfile": true,
"files": [
"state-sync.js"
"client-state-manager.js"
],
"dependencies": {
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import stateManager from '../client-state-manager'
import Client from '@bugsnag/core/client'

describe('@bugsnag/plugin-electron-client-state-manager', () => {
it('should emit events when user changes', done => {
const client = new Client({}, {}, [stateManager], {})
const { emitter } = client.getPlugin('clientStateManager')
emitter.on('UserUpdate', user => {
expect(user).toEqual({ id: '123', email: '[email protected]', name: 'Jim' })
done()
})
client.setUser('123', '[email protected]', 'Jim')
})

it('should emit events when context changes', done => {
const client = new Client({}, {}, [stateManager], {})
const { emitter } = client.getPlugin('clientStateManager')
emitter.on('ContextUpdate', (context) => {
expect(context).toBe('ctx')
done()
})
client.setContext('ctx')
})

it('should emit events when metadata is added', done => {
const client = new Client({}, {}, [stateManager], {})
const { emitter } = client.getPlugin('clientStateManager')
emitter.on('MetadataUpdate', (payload) => {
expect(payload.section).toBe('section')
expect(payload.values).toEqual({ key: 'value' })
done()
})
client.addMetadata('section', 'key', 'value')
})

it('should emit events when metadata is cleared', done => {
const client = new Client({}, {}, [stateManager], {})
const { emitter } = client.getPlugin('clientStateManager')
emitter.on('MetadataUpdate', (payload) => {
expect(payload.section).toBe('section')
expect(payload.values).toBe(undefined)
done()
})
client.clearMetadata('section', 'key')
})

it('should support bulk updates', () => {
const client = new Client({}, {}, [stateManager], {})
const { emitter, bulkUpdate } = client.getPlugin('clientStateManager')

const metadataCb = jest.fn()
const contextCb = jest.fn()
const userCb = jest.fn()

emitter.on('MetadataReplace', metadataCb)
emitter.on('ContextUpdate', contextCb)
emitter.on('UserUpdate', userCb)

// update everything
bulkUpdate({
user: {
id: '123', name: 'Jim', email: '[email protected]'
},
context: 'ctx',
metadata: {
section: { key: 'value' }
}
})

expect(metadataCb).toHaveBeenCalledWith({ section: { key: 'value' } })
expect(contextCb).toHaveBeenCalledWith('ctx')
expect(userCb).toHaveBeenCalledWith({ id: '123', name: 'Jim', email: '[email protected]' })

jest.resetAllMocks()

// update just context
bulkUpdate({
context: 'ctx'
})

expect(metadataCb).not.toHaveBeenCalled()
expect(contextCb).toHaveBeenCalledWith('ctx')
expect(userCb).not.toHaveBeenCalled()

jest.resetAllMocks()

// update just user
bulkUpdate({
user: { id: '123', name: 'Jim', email: '[email protected]' }
})

expect(metadataCb).not.toHaveBeenCalled()
expect(contextCb).not.toHaveBeenCalledWith()
expect(userCb).toHaveBeenCalledWith({ id: '123', name: 'Jim', email: '[email protected]' })

jest.resetAllMocks()

// update just metadata
bulkUpdate({
metadata: {
section: { key: 'value' }
}
})

expect(metadataCb).toHaveBeenCalledWith({ section: { key: 'value' } })
expect(contextCb).not.toHaveBeenCalled()
expect(userCb).not.toHaveBeenCalled()
})
})
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"targets": [
{
"target_name": "bugsnag_plugin_electron_client_sync_bindings",
"target_name": "bugsnag_plugin_electron_client_state_persistence_bindings",
"sources": [
"src/api.c",
"src/bugsnag_electron_client_sync.c",
"src/bugsnag_electron_client_state_persistence.c",
"src/signal_handler.c",
"src/deps/parson/parson.c",
"src/deps/tinycthread/tinycthread.c"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,33 @@ module.exports = (NativeClient) => ({
}
}, true)

const stateSync = client.getPlugin('stateSync')
const clientStateManager = client.getPlugin('clientStateManager')

stateSync.emitter.on('UserUpdate', user => {
clientStateManager.emitter.on('UserUpdate', user => {
try {
NativeClient.updateUser(user.id, user.email, user.name)
} catch (e) {
client._logger.error(e)
}
})

stateSync.emitter.on('ContextUpdate', context => {
clientStateManager.emitter.on('ContextUpdate', context => {
try {
NativeClient.updateContext(context)
} catch (e) {
client._logger.error(e)
}
})

stateSync.emitter.on('MetadataUpdate', ({ section, values }) => {
clientStateManager.emitter.on('MetadataUpdate', ({ section, values }) => {
try {
NativeClient.updateMetadata(section, values)
} catch (e) {
client._logger.error(e)
}
})

stateSync.emitter.on('MetadataReplace', ({ metadata }) => {
clientStateManager.emitter.on('MetadataReplace', (metadata) => {
try {
NativeClient.updateMetadata(metadata)
} catch (e) {
Expand Down
Loading

0 comments on commit 113de84

Please sign in to comment.