forked from evs-broadcast/node-emberplus
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
376 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,249 @@ | ||
import { | ||
NumberedTreeNode, | ||
EmberElement, | ||
NumberedTreeNodeImpl, | ||
EmberNodeImpl, | ||
ParameterImpl, | ||
ParameterType, | ||
QualifiedElementImpl, | ||
} from '../../../model' | ||
import { Collection, Root, RootElement } from '../../../types/types' | ||
import { EmberClient } from '../' | ||
import S101ClientMock from '../../../__mocks__/S101Client' | ||
import { DecodeResult } from '../../../encodings/ber/decoder/DecodeResult' | ||
// import { EmberTreeNode, RootElement } from '../../../types/types' | ||
// import { ElementType, EmberElement } from '../../../model/EmberElement' | ||
// import { Parameter, ParameterType } from '../../../model/Parameter' | ||
|
||
jest.mock('../../Socket/S101Client', () => require('../../../__mocks__/S101Client')) | ||
|
||
describe('client', () => { | ||
const onSocketCreate = jest.fn() | ||
const onConnection = jest.fn() | ||
const onSocketClose = jest.fn() | ||
const onSocketWrite = jest.fn() | ||
const onConnectionChanged = jest.fn() | ||
|
||
function setupSocketMock() { | ||
S101ClientMock.mockOnNextSocket((socket: any) => { | ||
onSocketCreate() | ||
|
||
socket.onConnect = onConnection | ||
socket.onWrite = onSocketWrite | ||
socket.onClose = onSocketClose | ||
}) | ||
} | ||
|
||
beforeEach(() => { | ||
setupSocketMock() | ||
}) | ||
afterEach(() => { | ||
const sockets = S101ClientMock.openSockets() | ||
// Destroy any lingering sockets, to prevent a failing test from affecting other tests: | ||
sockets.forEach((s) => s.destroy()) | ||
|
||
S101ClientMock.clearMockOnNextSocket() | ||
onSocketCreate.mockClear() | ||
onConnection.mockClear() | ||
onSocketClose.mockClear() | ||
onSocketWrite.mockClear() | ||
onConnectionChanged.mockClear() | ||
|
||
// Just a check to ensure that the unit tests cleaned up the socket after themselves: | ||
// eslint-disable-next-line jest/no-standalone-expect | ||
expect(sockets).toHaveLength(0) | ||
}) | ||
|
||
async function runWithConnection(fn: (connection: EmberClient, socket: S101ClientMock) => Promise<void>) { | ||
const client = new EmberClient('test') | ||
try { | ||
expect(client).toBeTruthy() | ||
|
||
await client.connect() | ||
|
||
// Wait for connection | ||
await new Promise(setImmediate) | ||
|
||
// Should be connected | ||
expect(client.connected).toBeTruthy() | ||
|
||
const sockets = S101ClientMock.openSockets() | ||
expect(sockets).toHaveLength(1) | ||
expect(onSocketWrite).toHaveBeenCalledTimes(0) | ||
|
||
await fn(client, sockets[0]) | ||
} finally { | ||
// Ensure cleaned up | ||
await client.disconnect() | ||
client.discard() | ||
|
||
await new Promise(setImmediate) | ||
} | ||
} | ||
|
||
function createQualifiedNodeResponse( | ||
path: string, | ||
content: EmberElement, | ||
children: Collection<NumberedTreeNode<EmberElement>> | ||
): DecodeResult<Root> { | ||
const parent = new QualifiedElementImpl<EmberElement>(path, content, children) | ||
|
||
const fixLevel = (node: NumberedTreeNode<EmberElement>, parent: NumberedTreeNode<EmberElement>) => { | ||
node.parent = parent | ||
|
||
for (const child of Object.values<NumberedTreeNode<EmberElement>>(node.children ?? {})) { | ||
fixLevel(child, node) | ||
} | ||
} | ||
for (const child of Object.values<NumberedTreeNode<EmberElement>>(children)) { | ||
fixLevel(child, parent as any as NumberedTreeNode<EmberElement>) | ||
} | ||
return { | ||
value: { | ||
0: parent as Exclude<RootElement, NumberedTreeNode<EmberElement>>, | ||
}, | ||
} | ||
} | ||
|
||
it('getDirectory resolves', async () => { | ||
await runWithConnection(async (client, socket) => { | ||
// Do initial load | ||
const getRootDirReq = await client.getDirectory(client.tree) | ||
getRootDirReq.response?.catch(() => null) // Ensure uncaught response is ok | ||
expect(onSocketWrite).toHaveBeenCalledTimes(1) | ||
// TODO: should the value of the call be checked? | ||
|
||
// Mock a valid response | ||
socket.mockData({ | ||
value: { | ||
1: new NumberedTreeNodeImpl(1, new EmberNodeImpl('Ruby', undefined, undefined, true)), | ||
}, | ||
}) | ||
|
||
// Should have a response | ||
const res = (await getRootDirReq.response) as NumberedTreeNodeImpl<EmberElement> | ||
expect(res).toMatchObject(new NumberedTreeNodeImpl(1, new EmberNodeImpl('Ruby', undefined, undefined, true))) | ||
}) | ||
}) | ||
|
||
it('getElementByPath', async () => { | ||
await runWithConnection(async (client, socket) => { | ||
// Do initial load | ||
const getRootDirReq = await client.getDirectory(client.tree) | ||
getRootDirReq.response?.catch(() => null) // Ensure uncaught response is ok | ||
expect(onSocketWrite).toHaveBeenCalledTimes(1) | ||
onSocketWrite.mockClear() | ||
|
||
// Mock a valid response | ||
socket.mockData({ | ||
value: { | ||
1: new NumberedTreeNodeImpl(1, new EmberNodeImpl('Ruby', undefined, undefined, true)), | ||
}, | ||
}) | ||
await getRootDirReq.response | ||
|
||
// Run the tree | ||
const getByPathPromise = client.getElementByPath('Ruby.Sums.On') | ||
|
||
// First lookup | ||
expect(onSocketWrite).toHaveBeenCalledTimes(1) | ||
socket.mockData({ | ||
value: { | ||
1: new NumberedTreeNodeImpl(1, new EmberNodeImpl('Ruby', undefined, undefined, true), { | ||
1: new NumberedTreeNodeImpl(1, new EmberNodeImpl('Sums', undefined, undefined, true)), | ||
}), | ||
}, | ||
}) | ||
|
||
await new Promise(setImmediate) | ||
|
||
// Second lookup | ||
expect(onSocketWrite).toHaveBeenCalledTimes(2) | ||
socket.mockData({ | ||
value: { | ||
1: new QualifiedElementImpl<EmberElement>('1.1', new EmberNodeImpl('Sums', undefined, undefined, false), { | ||
1: new NumberedTreeNodeImpl(1, new ParameterImpl(ParameterType.Boolean, 'On', undefined, false)), | ||
}) as Exclude<RootElement, NumberedTreeNode<EmberElement>>, | ||
}, | ||
}) | ||
|
||
await new Promise(setImmediate) | ||
|
||
const res = await getByPathPromise | ||
expect(res).toBeTruthy() | ||
expect(res).toMatchObject( | ||
new NumberedTreeNodeImpl(1, new ParameterImpl(ParameterType.Boolean, 'On', undefined, false)) | ||
) | ||
}) | ||
}) | ||
|
||
it('getElementByPath concurrent', async () => { | ||
await runWithConnection(async (client, socket) => { | ||
// Do initial load | ||
const getRootDirReq = await client.getDirectory(client.tree) | ||
getRootDirReq.response?.catch(() => null) // Ensure uncaught response is ok | ||
expect(onSocketWrite).toHaveBeenCalledTimes(1) | ||
onSocketWrite.mockClear() | ||
|
||
// Mock a valid response | ||
socket.mockData({ | ||
value: { | ||
1: new NumberedTreeNodeImpl(1, new EmberNodeImpl('Ruby', undefined, undefined, true)), | ||
}, | ||
}) | ||
await getRootDirReq.response | ||
|
||
// Run the tree | ||
const getByPathPromise = client.getElementByPath('Ruby.Sums.MAIN.On') | ||
const getByPathPromise2 = client.getElementByPath('Ruby.Sums.MAIN.Second') | ||
|
||
// First lookup from both | ||
expect(onSocketWrite).toHaveBeenCalledTimes(2) | ||
socket.mockData( | ||
createQualifiedNodeResponse('1', new EmberNodeImpl('Ruby', undefined, undefined, true), { | ||
1: new NumberedTreeNodeImpl(1, new EmberNodeImpl('Sums', undefined, undefined, false)), | ||
}) | ||
) | ||
|
||
socket.mockData( | ||
createQualifiedNodeResponse('1', new EmberNodeImpl('Ruby', undefined, undefined, true), { | ||
1: new NumberedTreeNodeImpl(1, new EmberNodeImpl('Sums', undefined, undefined, false)), | ||
}) | ||
) | ||
|
||
await new Promise(setImmediate) | ||
|
||
// Second lookup | ||
expect(onSocketWrite).toHaveBeenCalledTimes(4) | ||
socket.mockData( | ||
createQualifiedNodeResponse('1.1', new EmberNodeImpl('Sums', undefined, undefined, false), { | ||
1: new NumberedTreeNodeImpl(1, new EmberNodeImpl('MAIN', undefined, undefined, false)), | ||
}) | ||
) | ||
await new Promise(setImmediate) | ||
socket.mockData( | ||
createQualifiedNodeResponse('1.1', new EmberNodeImpl('Sums', undefined, undefined, false), { | ||
1: new NumberedTreeNodeImpl(1, new EmberNodeImpl('MAIN', undefined, undefined, false)), | ||
}) | ||
) | ||
|
||
await new Promise(setImmediate) | ||
|
||
// Final lookup | ||
expect(onSocketWrite).toHaveBeenCalledTimes(6) | ||
socket.mockData( | ||
createQualifiedNodeResponse('1.1.1', new EmberNodeImpl('MAIN', undefined, undefined, false), { | ||
1: new NumberedTreeNodeImpl(1, new ParameterImpl(ParameterType.Boolean, 'On', undefined, false)), | ||
2: new NumberedTreeNodeImpl(1, new ParameterImpl(ParameterType.Boolean, 'Second', undefined, false)), | ||
}) | ||
) | ||
|
||
// Both completed successfully | ||
const res = await getByPathPromise | ||
expect(res).toBeTruthy() | ||
|
||
const res2 = await getByPathPromise2 | ||
expect(res2).toBeTruthy() | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.