From e7329b63669c5cf50fa93d167c3773762855558a Mon Sep 17 00:00:00 2001 From: dblock Date: Mon, 6 Jan 2025 08:53:07 -0500 Subject: [PATCH] Upload test spec logs. Signed-off-by: dblock --- .github/workflows/test-spec.yml | 10 +++++++++- CHANGELOG.md | 1 + tools/src/Logger.ts | 34 ++++++++++++++++++++++++++------- tools/src/tester/test.ts | 5 +++-- tools/tests/Logger.test.ts | 32 +++++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test-spec.yml b/.github/workflows/test-spec.yml index d166b375f..1d915bbc7 100644 --- a/.github/workflows/test-spec.yml +++ b/.github/workflows/test-spec.yml @@ -105,7 +105,8 @@ jobs: --opensearch-url=${{ matrix.entry.url || 'https://localhost:9200'}} \ --opensearch-cert=${{ matrix.entry.cert }} \ --opensearch-key=${{ matrix.entry.key }} \ - --tests=tests/${{ matrix.entry.tests || 'default' }} + --tests=tests/${{ matrix.entry.tests || 'default' }} \ + --log logs/test-spec-${{ steps.tests.outputs.hash }}.log - name: Get Container Logs if: failure() @@ -121,6 +122,13 @@ jobs: name: coverage-${{ matrix.entry.version }}-${{ steps.tests.outputs.hash }} path: coverage/test-spec-coverage-${{ steps.tests.outputs.hash }}.json + - name: Upload Logs + uses: actions/upload-artifact@v4 + if: always() + with: + name: logs-${{ matrix.entry.version }}-${{ steps.tests.outputs.hash }} + path: logs/test-spec-${{ steps.tests.outputs.hash }}.log + merge-coverage: runs-on: ubuntu-latest needs: test-opensearch-spec diff --git a/CHANGELOG.md b/CHANGELOG.md index 47a08619e..5df6f9d0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Added `PUT /_plugins/_ml/model_groups/{model_group_id}`, `GET /_plugins/_ml/model_groups/_search`, and `POST /_plugins/_ml/model_groups/_search` ([#760](https://github.com/opensearch-project/opensearch-api-specification/pull/760)) - Added `GET /_plugins/_ml/connectors/{connector_id}`, `_search`, `POST /_plugins/_ml/connectors/_search`, and `PUT /_plugins/_ml/connectors/{connector_id}` ([#764](https://github.com/opensearch-project/opensearch-api-specification/pull/764)) - Added the ability to skip an individual chapter test ([#765](https://github.com/opensearch-project/opensearch-api-specification/pull/765)) +- Added uploading of test spec logs ([#767](https://github.com/opensearch-project/opensearch-api-specification/pull/767)) ### Removed - Removed unsupported `_common.mapping:SourceField`'s `mode` field and associated `_common.mapping:SourceFieldMode` enum ([#652](https://github.com/opensearch-project/opensearch-api-specification/pull/652)) diff --git a/tools/src/Logger.ts b/tools/src/Logger.ts index 61a3f7284..1c8142f9c 100644 --- a/tools/src/Logger.ts +++ b/tools/src/Logger.ts @@ -7,6 +7,9 @@ * compatible open source license. */ +import * as fs from 'fs' +import * as path from 'path' + export enum LogLevel { error = 1, warn = 2, @@ -15,6 +18,7 @@ export enum LogLevel { export class Logger { level: LogLevel + log_file?: string static messages = { [LogLevel.error]: 'ERROR', @@ -22,29 +26,45 @@ export class Logger { [LogLevel.info]: 'INFO' } - constructor (level: LogLevel = LogLevel.warn) { + constructor(level: LogLevel = LogLevel.warn, log_file?: string) { this.level = level + this.log_file = log_file + + if (this.log_file !== undefined) { + const logs_path = path.dirname(this.log_file) + if (!fs.existsSync(logs_path)) { + fs.mkdirSync(logs_path, { recursive: true }) + } + } } - log (message: string): void { + log(message: string): void { console.log(message) + this.#write(message) } - info (message: string): void { + info(message: string): void { this.#log(LogLevel.info, message) } - warn (message: string): void { + warn(message: string): void { this.#log(LogLevel.warn, message) } - error (message: string): void { + error(message: string): void { this.#log(LogLevel.error, message) } - #log (level: LogLevel, message: string): void { - if (level > this.level) return + #log(level: LogLevel, message: string): void { const output = `[${Logger.messages[level]}] ${message}` + this.#write(output) + if (level > this.level) return console.log(output) } + + #write(message: string): void { + if (this.log_file !== undefined) { + fs.appendFileSync(this.log_file, message + '\n') + } + } } diff --git a/tools/src/tester/test.ts b/tools/src/tester/test.ts index 8a69185fb..657050f46 100644 --- a/tools/src/tester/test.ts +++ b/tools/src/tester/test.ts @@ -46,7 +46,8 @@ const command = new Command() .default(4) .argParser((v, _) => Number.parseInt(v)) ) - .addOption(new Option('--verbose', 'whether to print the full stack trace of errors').default(false)) + .addOption(new Option('--verbose', 'display verbose log output').default(false)) + .addOption(new Option('--log ', 'save verbose log output into a file').default(undefined)) .addOption(new Option('--dry-run', 'dry run only, do not make HTTP requests').default(false)) .addOption(new Option('--opensearch-version ', 'target OpenSearch schema version').default(undefined)) .addOption(new Option('--opensearch-distribution ', 'OpenSearch distribution') @@ -69,7 +70,7 @@ const command = new Command() .parse() const opts = command.opts() -const logger = new Logger(opts.verbose ? LogLevel.info : LogLevel.warn) +const logger = new Logger(opts.verbose ? LogLevel.info : LogLevel.warn, opts.log) const spec = new MergedOpenApiSpec(opts.specPath, opts.opensearchVersion, opts.opensearchDistribution, new Logger(LogLevel.error)) const http_client = new OpenSearchHttpClient(get_opensearch_opts_from_cli({ responseType: 'arraybuffer', logger, ...opts })) diff --git a/tools/tests/Logger.test.ts b/tools/tests/Logger.test.ts index 77d9ad0b6..60f47c06f 100644 --- a/tools/tests/Logger.test.ts +++ b/tools/tests/Logger.test.ts @@ -8,6 +8,8 @@ */ import { Logger, LogLevel } from '../src/Logger' +import fs from 'fs' +import tmp from 'tmp' describe('Logger', () => { let log: jest.Mock @@ -99,4 +101,34 @@ describe('Logger', () => { ]) }) }) + + describe('with a log file', () => { + var temp: tmp.DirResult + var filename: string + var logger: Logger + + beforeEach(() => { + temp = tmp.dirSync() + filename = `${temp.name}/opensearch.log` + logger = new Logger(LogLevel.warn, filename) + }) + + afterEach(() => { + fs.unlinkSync(filename) + temp.removeCallback() + }) + + test('logs all level messages', () => { + logger.log('log') + logger.error('error') + logger.warn('warn') + logger.info('info') + expect(fs.readFileSync(filename).toString()).toEqual([ + 'log', + '[ERROR] error', + '[WARNING] warn', + '[INFO] info' + ].join("\n") + "\n") + }) + }) })