Skip to content

Commit 1ef509e

Browse files
test: address Copilot review comments on app worker unit tests
- worker.spec.ts: snapshot/restore process.env instead of deleting keys - worker.spec.ts: replace meaningless expect(true) with not.to.throw() - worker.spec.ts: assert fakeWatcher.close() in 'closes watchers' test - static-mirroring-worker.spec.ts: snapshot/restore process.env.SECRET - static-mirroring-worker.spec.ts: implement 'rejects events from relay itself' test - static-mirroring-worker.spec.ts: assert true (not just boolean) for valid event - static-mirroring-worker.spec.ts: add real assertions to onMessage tests with mock client - static-mirroring-worker.spec.ts: assert WebSocket.terminate() in close test - app.spec.ts: use deterministic counter instead of Math.random() for worker IDs - app.spec.ts: advance fake timers and assert cluster.fork in restart test - src/app/static-mirroring-worker.ts: validate this.config after path() lookup - src/app/app.ts: use this.process.env consistently for all env reads in run()
1 parent 4675276 commit 1ef509e

5 files changed

Lines changed: 88 additions & 45 deletions

File tree

src/app/app.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ export class App implements IRunnable {
4747
░ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░░ ░ ░ ░ ▒ ░ ░
4848
░ ░ ░ ░ ░ ░ ░ ░ ░ ░`)
4949
const width = 74
50-
const torHiddenServicePort = process.env.HIDDEN_SERVICE_PORT ? Number(process.env.HIDDEN_SERVICE_PORT) : 80
51-
const port = process.env.RELAY_PORT ? Number(process.env.RELAY_PORT) : 8008
50+
const torHiddenServicePort = this.process.env.HIDDEN_SERVICE_PORT ? Number(this.process.env.HIDDEN_SERVICE_PORT) : 80
51+
const port = this.process.env.RELAY_PORT ? Number(this.process.env.RELAY_PORT) : 8008
5252

5353
const logCentered = (input: string, width: number) => {
5454
const start = (width - input.length) >> 1

src/app/static-mirroring-worker.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ export class StaticMirroringWorker implements IRunnable {
5656
logger.info('mirroring', currentSettings.mirroring)
5757

5858
this.config = path(['mirroring', 'static', this.process.env.MIRROR_INDEX], currentSettings) as Mirror
59+
if (!this.config) {
60+
throw new Error(`Mirror configuration not found for index ${this.process.env.MIRROR_INDEX}`)
61+
}
5962

6063
let since = Math.floor(Date.now() / 1000) - 60 * 10
6164

test/unit/app/app.spec.ts

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,20 @@ describe('App', () => {
3737
} as any,
3838
})
3939

40-
const createFakeWorker = (): any => ({
41-
id: Math.floor(Math.random() * 10000),
42-
process: { pid: Math.floor(Math.random() * 100000) },
43-
send: sandbox.stub(),
44-
})
40+
let workerIdCounter = 0
41+
42+
const createFakeWorker = (): any => {
43+
const id = ++workerIdCounter
44+
return {
45+
id,
46+
process: { pid: id + 100000 },
47+
send: sandbox.stub(),
48+
}
49+
}
4550

4651
beforeEach(() => {
4752
sandbox = Sinon.createSandbox()
53+
workerIdCounter = 0
4854

4955
fakeProcess = Object.assign(new EventEmitter(), {
5056
exit: sandbox.stub(),
@@ -290,9 +296,10 @@ describe('App', () => {
290296
describe('onClusterExit', () => {
291297
let worker: any
292298
let deadWorker: any
299+
let clock: Sinon.SinonFakeTimers
293300

294301
beforeEach(() => {
295-
sandbox.useFakeTimers()
302+
clock = sandbox.useFakeTimers()
296303

297304
worker = createFakeWorker()
298305
deadWorker = createFakeWorker()
@@ -319,11 +326,18 @@ describe('App', () => {
319326
})
320327

321328
it('schedules worker restart on unexpected exit', () => {
322-
// When a worker exits unexpectedly, the app schedules a restart
323-
// We verify that exit handling doesn't throw
324-
expect(() => {
325-
fakeCluster.emit('exit', deadWorker, 1, '')
326-
}).not.to.throw()
329+
settingsState.workers = { count: 1 }
330+
settingsState.mirroring = { static: [] }
331+
332+
app.run()
333+
334+
const registeredWorker = (fakeCluster.fork as Sinon.SinonStub).firstCall.returnValue
335+
fakeCluster.fork.resetHistory()
336+
337+
fakeCluster.emit('exit', registeredWorker, 1, '')
338+
clock.tick(10001)
339+
340+
expect(fakeCluster.fork).to.have.been.called
327341
})
328342
})
329343

test/unit/app/static-mirroring-worker.spec.ts

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { StaticMirroringWorker } from '../../../src/app/static-mirroring-worker'
88
import { Event } from '../../../src/@types/event'
99
import { Settings } from '../../../src/@types/settings'
1010
import { IEventRepository, IUserRepository } from '../../../src/@types/repositories'
11+
import { getPublicKey, getRelayPrivateKey } from '../../../src/utils/event'
12+
import { WebSocketServerAdapterEvent } from '../../../src/constants/adapter'
1113

1214
chai.use(sinonChai)
1315

@@ -54,8 +56,11 @@ describe('StaticMirroringWorker', () => {
5456
...overrides,
5557
})
5658

59+
let savedSecret: string | undefined
60+
5761
beforeEach(() => {
5862
sandbox = Sinon.createSandbox()
63+
savedSecret = process.env.SECRET
5964
process.env.SECRET = 'test-secret-for-unit-tests'
6065

6166
fakeProcess = Object.assign(new EventEmitter(), {
@@ -84,7 +89,8 @@ describe('StaticMirroringWorker', () => {
8489
})
8590

8691
afterEach(() => {
87-
delete process.env.SECRET
92+
if (savedSecret === undefined) delete process.env.SECRET
93+
else process.env.SECRET = savedSecret
8894
sandbox.restore()
8995
})
9096

@@ -124,15 +130,20 @@ describe('StaticMirroringWorker', () => {
124130

125131
describe('canAcceptEvent', () => {
126132
it('rejects events from the relay itself', () => {
127-
// This tests the private canAcceptEvent method indirectly through the worker behavior
128-
// For now, we focus on testing the public interface
133+
const relayPrivkey = getRelayPrivateKey(settingsState.info!.relay_url)
134+
const relayPubkey = getPublicKey(relayPrivkey)
135+
136+
const event = createEvent({ pubkey: relayPubkey })
137+
const result = (worker as any).canAcceptEvent(event)
138+
139+
expect(result).to.equal(false)
129140
})
130141

131142
it('accepts valid events within limits', () => {
132143
const event = createEvent({ pubkey: 'd'.repeat(64) })
133144
const result = (worker as any).canAcceptEvent(event)
134145

135-
expect(result).to.be.a('boolean')
146+
expect(result).to.equal(true)
136147
})
137148

138149
it('rejects events with content exceeding limits', () => {
@@ -357,29 +368,42 @@ describe('StaticMirroringWorker', () => {
357368
})
358369

359370
describe('onMessage', () => {
371+
let mockClient: { send: Sinon.SinonStub; readyState: number }
372+
373+
beforeEach(() => {
374+
mockClient = { send: sandbox.stub(), readyState: 1 /* WebSocket.OPEN */ }
375+
;(worker as any).config = settingsState.mirroring!.static![0]
376+
;(worker as any).client = mockClient
377+
})
378+
360379
it('relays broadcast messages to connected mirror', () => {
361-
const testMessage = {
362-
eventName: 'Broadcast',
380+
fakeProcess.emit('message', {
381+
eventName: WebSocketServerAdapterEvent.Broadcast,
363382
event: createEvent(),
364383
source: 'local',
365-
}
366-
367-
// Simulate message reception
368-
fakeProcess.emit('message', testMessage)
384+
})
369385

370-
// The message handler should attempt to forward if client is open
386+
expect(mockClient.send).to.have.been.called
371387
})
372388

373-
it('ignores messages from the same source', () => {
374-
const testMessage = {
375-
eventName: 'Broadcast',
389+
it('ignores messages from the same source as the mirror', () => {
390+
fakeProcess.emit('message', {
391+
eventName: WebSocketServerAdapterEvent.Broadcast,
376392
event: createEvent(),
377393
source: 'ws://source-relay.com',
378-
}
394+
})
395+
396+
expect(mockClient.send).not.to.have.been.called
397+
})
379398

380-
fakeProcess.emit('message', testMessage)
399+
it('ignores non-broadcast messages', () => {
400+
fakeProcess.emit('message', {
401+
eventName: 'other-event',
402+
event: createEvent(),
403+
source: 'local',
404+
})
381405

382-
// Should not forward to same source
406+
expect(mockClient.send).not.to.have.been.called
383407
})
384408
})
385409

@@ -415,9 +439,12 @@ describe('StaticMirroringWorker', () => {
415439

416440
describe('close', () => {
417441
it('terminates the WebSocket client', () => {
442+
const mockClient = { terminate: sandbox.stub() }
443+
;(worker as any).client = mockClient
444+
418445
worker.close()
419446

420-
// Verify close completes without error
447+
expect(mockClient.terminate).to.have.been.called
421448
})
422449

423450
it('invokes the callback when provided', () => {

test/unit/app/worker.spec.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@ describe('AppWorker', () => {
1818
let fakeAdapter: any
1919
let watchSettingsStub: Sinon.SinonStub
2020

21+
let savedEnv: { PORT: string | undefined; RELAY_PORT: string | undefined }
22+
2123
beforeEach(() => {
2224
sandbox = Sinon.createSandbox()
2325

26+
savedEnv = { PORT: process.env.PORT, RELAY_PORT: process.env.RELAY_PORT }
27+
2428
fakeProcess = Object.assign(new EventEmitter(), {
2529
exit: sandbox.stub(),
2630
env: process.env,
@@ -46,9 +50,10 @@ describe('AppWorker', () => {
4650
})
4751

4852
afterEach(() => {
49-
// Clean up env vars
50-
delete process.env.PORT
51-
delete process.env.RELAY_PORT
53+
if (savedEnv.PORT === undefined) delete process.env.PORT
54+
else process.env.PORT = savedEnv.PORT
55+
if (savedEnv.RELAY_PORT === undefined) delete process.env.RELAY_PORT
56+
else process.env.RELAY_PORT = savedEnv.RELAY_PORT
5257
sandbox.restore()
5358
})
5459

@@ -147,21 +152,13 @@ describe('AppWorker', () => {
147152
it('handles TypeError about database connection without throwing', () => {
148153
const error = new TypeError("Cannot read properties of undefined (reading '__knexUid')")
149154

150-
// This should not throw because onError logs and returns for this specific error
151-
fakeProcess.emit('uncaughtException', error)
152-
153-
// Verify error was handled gracefully
154-
expect(true).to.be.true
155+
expect(() => fakeProcess.emit('uncaughtException', error)).not.to.throw()
155156
})
156157

157-
it('logs other errors', () => {
158+
it('logs other errors without throwing', () => {
158159
const error = new Error('test error')
159160

160-
// onError logs the error
161-
fakeProcess.emit('uncaughtException', error)
162-
163-
// Verify the handler was called
164-
expect(true).to.be.true
161+
expect(() => fakeProcess.emit('uncaughtException', error)).not.to.throw()
165162
})
166163
})
167164

@@ -233,6 +230,8 @@ describe('AppWorker', () => {
233230
worker.close()
234231

235232
expect(fakeAdapter.close).to.have.been.called
233+
expect(fakeWatcher1.close).to.have.been.called
234+
expect(fakeWatcher2.close).to.have.been.called
236235
})
237236

238237
it('handles no watchers gracefully', () => {

0 commit comments

Comments
 (0)