Skip to content

Commit

Permalink
runtime consolidation: refactoring (#2398)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidjgoss committed Apr 21, 2024
1 parent 2c147a8 commit 8f96d9f
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 46 deletions.
6 changes: 0 additions & 6 deletions src/api/runtime.ts
Expand Up @@ -15,9 +15,6 @@ export function makeRuntime({
pickleIds,
newId,
supportCodeLibrary,
requireModules,
requirePaths,
importPaths,
options: { parallel, ...options },
}: {
cwd: string
Expand All @@ -42,9 +39,6 @@ export function makeRuntime({
options,
newId,
supportCodeLibrary,
requireModules,
requirePaths,
importPaths,
numberOfWorkers: parallel,
})
}
Expand Down
9 changes: 4 additions & 5 deletions src/runtime/parallel/command_types.ts
@@ -1,5 +1,7 @@
import * as messages from '@cucumber/messages'
import { Envelope } from '@cucumber/messages'
import { IRuntimeOptions } from '../index'
import { ISupportCodeCoordinates } from '../../api'

// Messages from Coordinator to Worker

Expand All @@ -10,10 +12,7 @@ export interface IWorkerCommand {
}

export interface IWorkerCommandInitialize {
filterStacktraces: boolean
requireModules: string[]
requirePaths: string[]
importPaths: string[]
supportCodeCoordinates: ISupportCodeCoordinates
supportCodeIds?: ICanonicalSupportCodeIds
options: IRuntimeOptions
}
Expand All @@ -36,6 +35,6 @@ export interface IWorkerCommandRun {
// Messages from Worker to Coordinator

export interface ICoordinatorReport {
jsonEnvelope?: string
jsonEnvelope?: Envelope
ready?: boolean
}
19 changes: 2 additions & 17 deletions src/runtime/parallel/coordinator.ts
Expand Up @@ -24,9 +24,6 @@ export interface INewCoordinatorOptions {
newId: IdGenerator.NewId
pickleIds: string[]
supportCodeLibrary: SupportCodeLibrary
requireModules: string[]
requirePaths: string[]
importPaths: string[]
numberOfWorkers: number
}

Expand Down Expand Up @@ -61,9 +58,6 @@ export default class Coordinator implements IRuntime {
private readonly inProgressPickles: Record<string, messages.Pickle>
private readonly workers: Record<string, IWorker>
private readonly supportCodeLibrary: SupportCodeLibrary
private readonly requireModules: string[]
private readonly requirePaths: string[]
private readonly importPaths: string[]
private readonly numberOfWorkers: number
private readonly logger: ILogger
private success: boolean
Expand All @@ -78,9 +72,6 @@ export default class Coordinator implements IRuntime {
options,
newId,
supportCodeLibrary,
requireModules,
requirePaths,
importPaths,
numberOfWorkers,
}: INewCoordinatorOptions) {
this.cwd = cwd
Expand All @@ -91,9 +82,6 @@ export default class Coordinator implements IRuntime {
this.options = options
this.newId = newId
this.supportCodeLibrary = supportCodeLibrary
this.requireModules = requireModules
this.requirePaths = requirePaths
this.importPaths = importPaths
this.pickleIds = Array.from(pickleIds)
this.numberOfWorkers = numberOfWorkers
this.success = true
Expand All @@ -107,7 +95,7 @@ export default class Coordinator implements IRuntime {
worker.state = WorkerState.idle
this.awakenWorkers(worker)
} else if (doesHaveValue(message.jsonEnvelope)) {
const envelope = messages.parseEnvelope(message.jsonEnvelope)
const envelope = message.jsonEnvelope
this.eventBroadcaster.emit('envelope', envelope)
if (doesHaveValue(envelope.testCaseFinished)) {
delete this.inProgressPickles[worker.id]
Expand Down Expand Up @@ -159,10 +147,7 @@ export default class Coordinator implements IRuntime {
})
const initializeCommand: IWorkerCommand = {
initialize: {
filterStacktraces: this.options.filterStacktraces,
requireModules: this.requireModules,
requirePaths: this.requirePaths,
importPaths: this.importPaths,
supportCodeCoordinates: this.supportCodeLibrary.originalCoordinates,
supportCodeIds: {
stepDefinitionIds: this.supportCodeLibrary.stepDefinitions.map(
(s) => s.id
Expand Down
30 changes: 12 additions & 18 deletions src/runtime/parallel/worker.ts
Expand Up @@ -53,36 +53,29 @@ export default class Worker {
this.sendMessage = sendMessage
this.eventBroadcaster = new EventEmitter()
this.eventBroadcaster.on('envelope', (envelope: messages.Envelope) => {
// assign `workerId` property only for the `testCaseStarted` message
if (envelope.testCaseStarted) {
envelope.testCaseStarted.workerId = this.id
}
this.sendMessage({ jsonEnvelope: JSON.stringify(envelope) })
this.sendMessage({ jsonEnvelope: envelope })
})
}

async initialize({
filterStacktraces,
requireModules,
requirePaths,
importPaths,
supportCodeCoordinates,
supportCodeIds,
options,
}: IWorkerCommandInitialize): Promise<void> {
supportCodeLibraryBuilder.reset(this.cwd, this.newId, {
requireModules,
requirePaths,
importPaths,
})
requireModules.map((module) => tryRequire(module))
requirePaths.map((module) => tryRequire(module))
for (const path of importPaths) {
supportCodeLibraryBuilder.reset(
this.cwd,
this.newId,
supportCodeCoordinates
)
supportCodeCoordinates.requireModules.map((module) => tryRequire(module))
supportCodeCoordinates.requirePaths.map((module) => tryRequire(module))
for (const path of supportCodeCoordinates.importPaths) {
await import(pathToFileURL(path).toString())
}
this.supportCodeLibrary = supportCodeLibraryBuilder.finalize(supportCodeIds)

this.worldParameters = options.worldParameters
this.filterStacktraces = filterStacktraces
this.filterStacktraces = options.filterStacktraces
this.runTestRunHooks = makeRunTestRunHooks(
options.dryRun,
this.supportCodeLibrary.defaultTimeout,
Expand Down Expand Up @@ -125,6 +118,7 @@ export default class Worker {
}: IWorkerCommandRun): Promise<void> {
const stopwatch = create(elapsed)
const testCaseRunner = new TestCaseRunner({
workerId: this.id,
eventBroadcaster: this.eventBroadcaster,
stopwatch,
gherkinDocument,
Expand Down
7 changes: 7 additions & 0 deletions src/runtime/test_case_runner.ts
Expand Up @@ -18,6 +18,7 @@ import AttachmentManager from './attachment_manager'
import { getAmbiguousStepException } from './helpers'

export interface INewTestCaseRunnerOptions {
workerId?: string
eventBroadcaster: EventEmitter
stopwatch: IStopwatch
gherkinDocument: messages.GherkinDocument
Expand All @@ -32,6 +33,7 @@ export interface INewTestCaseRunnerOptions {
}

export default class TestCaseRunner {
private readonly workerId: string | undefined
private readonly attachmentManager: AttachmentManager
private currentTestCaseStartedId: string
private currentTestStepId: string
Expand All @@ -50,6 +52,7 @@ export default class TestCaseRunner {
private readonly worldParameters: JsonObject

constructor({
workerId,
eventBroadcaster,
stopwatch,
gherkinDocument,
Expand All @@ -62,6 +65,7 @@ export default class TestCaseRunner {
supportCodeLibrary,
worldParameters,
}: INewTestCaseRunnerOptions) {
this.workerId = workerId
this.attachmentManager = new AttachmentManager(
({ data, media, fileName }) => {
if (doesNotHaveValue(this.currentTestStepId)) {
Expand Down Expand Up @@ -212,6 +216,9 @@ export default class TestCaseRunner {
timestamp: this.stopwatch.timestamp(),
},
}
if (this.workerId) {
testCaseStarted.testCaseStarted.workerId = this.workerId
}
this.eventBroadcaster.emit('envelope', testCaseStarted)
// used to determine whether a hook is a Before or After
let didWeRunStepsYet = false
Expand Down
37 changes: 37 additions & 0 deletions src/runtime/test_case_runner_spec.ts
Expand Up @@ -17,6 +17,7 @@ import { assembleTestCases } from './assemble_test_cases'
import IEnvelope = messages.Envelope

interface ITestRunnerRequest {
workerId?: string
gherkinDocument: messages.GherkinDocument
pickle: messages.Pickle
retries?: number
Expand Down Expand Up @@ -47,6 +48,7 @@ async function testRunner(
// listen for envelopers _after_ we've assembled test cases
eventBroadcaster.on('envelope', (e) => envelopes.push(e))
const runner = new TestCaseRunner({
workerId: options.workerId,
eventBroadcaster,
stopwatch: create(),
gherkinDocument: options.gherkinDocument,
Expand Down Expand Up @@ -534,5 +536,40 @@ describe('TestCaseRunner', () => {
})
})
})

it('emits workerId on testCaseStarted when provided', async () => {
// Arrange
const supportCodeLibrary = buildSupportCodeLibrary(({ Given }) => {
Given('a step', function () {
clock.tick(1)
})
})
const {
gherkinDocument,
pickles: [pickle],
} = await parse({
data: ['Feature: a', 'Scenario: b', 'Given a step'].join('\n'),
uri: 'a.feature',
})

// Act
const { envelopes } = await testRunner({
workerId: 'foo',
gherkinDocument,
pickle,
supportCodeLibrary,
})

// Assert
expect(envelopes).to.deep.include({
testCaseStarted: {
workerId: 'foo',
attempt: 0,
id: '2',
testCaseId: '0',
timestamp: predictableTimestamp(0),
},
})
})
})
})

0 comments on commit 8f96d9f

Please sign in to comment.