Skip to content

Commit

Permalink
Renaming parameters and adding command line tests. (#301)
Browse files Browse the repository at this point in the history
* Adding command line tests.

Signed-off-by: dblock <[email protected]>

* Renamed tab size to width.

Signed-off-by: dblock <[email protected]>

* Extracted to ansi namespace.

Signed-off-by: dblock <[email protected]>

---------

Signed-off-by: dblock <[email protected]>
  • Loading branch information
dblock authored May 30, 2024
1 parent 69247b0 commit 6da4a7c
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 40 deletions.
14 changes: 14 additions & 0 deletions tools/src/tester/Ansi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export function b (text: string): string { return `\x1b[1m${text}\x1b[0m` }
export function i (text: string): string { return `\x1b[3m${text}\x1b[0m` }

export function padding (text: string, length: number, prefix: number = 0): string {
const spaces = length - text.length > 0 ? ' '.repeat(length - text.length) : ''
return `${' '.repeat(prefix)}${text}${spaces}`
}

export function green (text: string): string { return `\x1b[32m${text}\x1b[0m` }
export function red (text: string): string { return `\x1b[31m${text}\x1b[0m` }
export function yellow (text: string): string { return `\x1b[33m${text}\x1b[0m` }
export function cyan (text: string): string { return `\x1b[36m${text}\x1b[0m` }
export function gray (text: string): string { return `\x1b[90m${text}\x1b[0m` }
export function magenta (text: string): string { return `\x1b[35m${text}\x1b[0m` }
54 changes: 20 additions & 34 deletions tools/src/tester/ResultsDisplayer.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,22 @@
import { type ChapterEvaluation, type Evaluation, Result, type StoryEvaluation } from './types/eval.types'
import { overall_result } from './helpers'

function b (text: string): string { return `\x1b[1m${text}\x1b[0m` }
function i (text: string): string { return `\x1b[3m${text}\x1b[0m` }

function padding (text: string, length: number, prefix: number = 0): string {
const spaces = length - text.length > 0 ? ' '.repeat(length - text.length) : ''
return `${' '.repeat(prefix)}${text}${spaces}`
}

function green (text: string): string { return `\x1b[32m${text}\x1b[0m` }
function red (text: string): string { return `\x1b[31m${text}\x1b[0m` }
function yellow (text: string): string { return `\x1b[33m${text}\x1b[0m` }
function cyan (text: string): string { return `\x1b[36m${text}\x1b[0m` }
function gray (text: string): string { return `\x1b[90m${text}\x1b[0m` }
function magenta (text: string): string { return `\x1b[35m${text}\x1b[0m` }
import * as ansi from './Ansi'

export interface DisplayOptions {
tab_size?: number
tab_width?: number
verbose?: boolean
}

export default class ResultsDisplayer {
evaluation: StoryEvaluation
skip_components: boolean
tab_size: number
tab_width: number
verbose: boolean

constructor (evaluation: StoryEvaluation, opts: DisplayOptions) {
this.evaluation = evaluation
this.skip_components = [Result.PASSED, Result.SKIPPED].includes(evaluation.result)
this.tab_size = opts.tab_size ?? 4
this.tab_width = opts.tab_width ?? 4
this.verbose = opts.verbose ?? false
}

Expand All @@ -45,20 +31,20 @@ export default class ResultsDisplayer {
#display_story (): void {
const result = this.evaluation.result
const message = this.evaluation.full_path
const title = cyan(b(this.evaluation.display_path))
const title = ansi.cyan(ansi.b(this.evaluation.display_path))
this.#display_evaluation({ result, message }, title)
}

#display_chapters (evaluations: ChapterEvaluation[], title: string): void {
if (this.skip_components || evaluations.length === 0) return
const result = overall_result(evaluations.map(e => e.overall))
this.#display_evaluation({ result }, title, this.tab_size)
this.#display_evaluation({ result }, title, this.tab_width)
if (result === Result.PASSED) return
for (const evaluation of evaluations) this.#display_chapter(evaluation)
}

#display_chapter (chapter: ChapterEvaluation): void {
this.#display_evaluation(chapter.overall, i(chapter.title), this.tab_size * 2)
this.#display_evaluation(chapter.overall, ansi.i(chapter.title), this.tab_width * 2)
if (chapter.overall.result === Result.PASSED || chapter.overall.result === Result.SKIPPED) return

this.#display_parameters(chapter.request?.parameters ?? {})
Expand All @@ -70,31 +56,31 @@ export default class ResultsDisplayer {
#display_parameters (parameters: Record<string, Evaluation>): void {
if (Object.keys(parameters).length === 0) return
const result = overall_result(Object.values(parameters))
this.#display_evaluation({ result }, 'PARAMETERS', this.tab_size * 3)
this.#display_evaluation({ result }, 'PARAMETERS', this.tab_width * 3)
if (result === Result.PASSED) return
for (const [name, evaluation] of Object.entries(parameters)) {
this.#display_evaluation(evaluation, name, this.tab_size * 4)
this.#display_evaluation(evaluation, name, this.tab_width * 4)
}
}

#display_request_body (evaluation: Evaluation | undefined): void {
if (evaluation == null) return
this.#display_evaluation(evaluation, 'REQUEST BODY', this.tab_size * 3)
this.#display_evaluation(evaluation, 'REQUEST BODY', this.tab_width * 3)
}

#display_status (evaluation: Evaluation | undefined): void {
if (evaluation == null) return
this.#display_evaluation(evaluation, 'RESPONSE STATUS', this.tab_size * 3)
this.#display_evaluation(evaluation, 'RESPONSE STATUS', this.tab_width * 3)
}

#display_payload (evaluation: Evaluation | undefined): void {
if (evaluation == null) return
this.#display_evaluation(evaluation, 'RESPONSE PAYLOAD', this.tab_size * 3)
this.#display_evaluation(evaluation, 'RESPONSE PAYLOAD', this.tab_width * 3)
}

#display_evaluation (evaluation: Evaluation, title: string, prefix: number = 0): void {
const result = padding(this.#result(evaluation.result), 0, prefix)
const message = evaluation.message != null ? `${gray('(' + evaluation.message + ')')}` : ''
const result = ansi.padding(this.#result(evaluation.result), 0, prefix)
const message = evaluation.message != null ? `${ansi.gray('(' + evaluation.message + ')')}` : ''
console.log(`${result} ${title} ${message}`)
if (evaluation.error && this.verbose) {
console.log('-'.repeat(100))
Expand All @@ -104,13 +90,13 @@ export default class ResultsDisplayer {
}

#result (r: Result): string {
const text = padding(r, 7)
const text = ansi.padding(r, 7)
switch (r) {
case Result.PASSED: return green(text)
case Result.SKIPPED: return yellow(text)
case Result.FAILED: return magenta(text)
case Result.ERROR: return red(text)
default: return gray(text)
case Result.PASSED: return ansi.green(text)
case Result.SKIPPED: return ansi.yellow(text)
case Result.FAILED: return ansi.magenta(text)
case Result.ERROR: return ansi.red(text)
default: return ansi.gray(text)
}
}
}
12 changes: 6 additions & 6 deletions tools/src/tester/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ import _ from 'lodash'

const command = new Command()
.description('Run test stories against the OpenSearch spec.')
.addOption(new Option('--spec, --spec_path <path>', 'path to the root folder of the multi-file spec').default('./spec'))
.addOption(new Option('--tests, --tests_path <path>', 'path to the root folder of the tests').default('./tests'))
.addOption(new Option('--tab_size <size>', 'tab size for displayed results').default('4'))
.addOption(new Option('--spec, --spec-path <path>', 'path to the root folder of the multi-file spec').default('./spec'))
.addOption(new Option('--tests, --tests-path <path>', 'path to the root folder of the tests').default('./tests'))
.addOption(new Option('--tab-width <size>', 'tab width for displayed results').default('4'))
.addOption(new Option('--verbose', 'whether to print the full stack trace of errors'))
.allowExcessArguments(false)
.parse()

const opts = command.opts()
const display_options = {
verbose: opts.verbose ?? false,
tab_size: Number.parseInt(opts.tab_size)
tab_width: Number.parseInt(opts.tabWidth)
}
const spec = (new OpenApiMerger(opts.spec_path, LogLevel.error)).merge()
const runner = new TestsRunner(spec, opts.tests_path, display_options)
const spec = (new OpenApiMerger(opts.specPath, LogLevel.error)).merge()
const runner = new TestsRunner(spec, opts.testsPath, display_options)
void runner.run().then(() => { _.noop() })
17 changes: 17 additions & 0 deletions tools/tests/tester/ansi.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as ansi from '../../src/tester/Ansi'

test('b', async () => {
expect(ansi.b('xyz')).toEqual('\x1b[1mxyz\x1b[0m')
})

test('i', async () => {
expect(ansi.i('xyz')).toEqual('\x1b[3mxyz\x1b[0m')
})

test.todo('padding')
test.todo('green')
test.todo('red')
test.todo('yellow')
test.todo('cyan')
test.todo('gray')
test.todo('magenta')
3 changes: 3 additions & 0 deletions tools/tests/tester/fixtures/empty.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
$schema: ../json_schemas/test_story.schema.yaml

chapters: []
30 changes: 30 additions & 0 deletions tools/tests/tester/start.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { spawnSync } from 'child_process'
import * as ansi from '../../src/tester/Ansi'

const spec = (args: string[]): any => {
const start = spawnSync('ts-node', ['tools/src/tester/start.ts'].concat(args), {
env: { ...process.env, OPENSEARCH_PASSWORD: 'password' }
})
return {
stdout: start.stdout?.toString(),
stderr: start.stderr?.toString()
}
}

test('--help', async () => {
expect(spec(['--help']).stdout).toContain('Usage: start [options]')
})

test('--invalid', async () => {
expect(spec(['--invalid']).stderr).toContain("error: unknown option '--invalid'")
})

test('--tests', async () => {
expect(spec(['--tests', 'tools/tests/tester/fixtures']).stdout).toContain(
`${ansi.green('PASSED ')} ${ansi.cyan(ansi.b('empty.yaml'))}`
)
})

test.todo('--tab-width')
test.todo('--verbose')
test.todo('--spec')

0 comments on commit 6da4a7c

Please sign in to comment.