-
Notifications
You must be signed in to change notification settings - Fork 91
Added script to verify all tests scenario are associated with a version tag #2421
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: development/2.15
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,7 +23,6 @@ | |
|
|
||
| import 'cli-testing/hooks/KeycloakSetup'; | ||
| import 'cli-testing/hooks/Logger'; | ||
| import 'cli-testing/hooks/versionTags'; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wrote why im doing this in the top comment of the pr |
||
|
|
||
| // HTTPS should not cause any error for CTST | ||
| process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; | ||
|
|
@@ -43,7 +42,7 @@ | |
|
|
||
| setParallelCanAssign(noParallelRun); | ||
|
|
||
| BeforeAll(async function () { | ||
| const kafkaHosts = process.env['KAFKA_HOST_PORT']; | ||
| const dlqTopic = process.env['KAFKA_DEAD_LETTER_TOPIC']; | ||
| if (kafkaHosts && dlqTopic) { | ||
|
|
@@ -51,7 +50,7 @@ | |
| } | ||
| }); | ||
|
|
||
| AfterAll(async function () { | ||
| await stopDLQConsumer(); | ||
| }); | ||
|
|
||
|
|
||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We usually put them in .github/scripts ? Also we should have tests for it 🙏 |
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,75 @@ | ||||
| /** | ||||
| * Verifies that every Scenario in the ctst feature files | ||||
| * has a semver version tag (e.g. @2.6.0), either on the Feature, | ||||
| * an enclosing Rule, or directly on the scenario. | ||||
| * | ||||
| * Exits with code 1 and lists offenders if any are missing. | ||||
| */ | ||||
|
|
||||
| /* eslint-disable no-console */ | ||||
|
|
||||
| import { Parser, AstBuilder, GherkinClassicTokenMatcher } from '@cucumber/gherkin'; | ||||
|
SylvainSenechal marked this conversation as resolved.
|
||||
| import { IdGenerator } from '@cucumber/messages'; | ||||
| import * as fs from 'fs'; | ||||
| import * as path from 'path'; | ||||
|
|
||||
| const VERSION_TAG_REGEX = /^@\d+\.\d+\.\d+$/; | ||||
| const FEATURES_DIR = path.resolve(__dirname, '../features'); | ||||
|
|
||||
| function collectFeatureFiles(dir: string): string[] { | ||||
| const files: string[] = []; | ||||
| for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { | ||||
| const full = path.join(dir, entry.name); | ||||
| if (entry.isDirectory()) { | ||||
| files.push(...collectFeatureFiles(full)); | ||||
| } else if (entry.name.endsWith('.feature')) { | ||||
| files.push(full); | ||||
| } | ||||
| } | ||||
| return files; | ||||
| } | ||||
|
|
||||
| let totalScenarios = 0; | ||||
| const offenders: string[] = []; | ||||
| const parser = new Parser(new AstBuilder(IdGenerator.incrementing()), new GherkinClassicTokenMatcher()); | ||||
|
|
||||
| for (const file of collectFeatureFiles(FEATURES_DIR)) { | ||||
| const rel = path.relative(FEATURES_DIR, file); | ||||
| const ast = parser.parse(fs.readFileSync(file, 'utf8')); | ||||
| const feature = ast.feature; | ||||
| if (!feature) { continue; } | ||||
|
|
||||
| const featureHasVersion = feature.tags.some(t => VERSION_TAG_REGEX.test(t.name)); | ||||
|
|
||||
| for (const child of feature.children) { | ||||
| if (child.scenario) { | ||||
| totalScenarios++; | ||||
| const hasVersion = featureHasVersion || child.scenario.tags.some(t => VERSION_TAG_REGEX.test(t.name)); | ||||
| if (!hasVersion) { | ||||
| offenders.push(` ${rel}:${child.scenario.location.line} — "${child.scenario.name}"`); | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this |
||||
| } | ||||
| } else if (child.rule) { | ||||
| // Version tag can be inherited from Feature or Rule | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
| const ruleHasVersion = child.rule.tags.some(t => VERSION_TAG_REGEX.test(t.name)); | ||||
| for (const ruleChild of child.rule.children) { | ||||
| if (!ruleChild.scenario) { continue; } // skip Background inside Rule | ||||
| totalScenarios++; | ||||
| const hasVersion = featureHasVersion || ruleHasVersion | ||||
| || ruleChild.scenario.tags.some(t => VERSION_TAG_REGEX.test(t.name)); | ||||
| if (!hasVersion) { | ||||
| offenders.push(` ${rel}:${ruleChild.scenario.location.line} — "${ruleChild.scenario.name}"`); | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can create a new function to do that instead of duplicating the logic ( |
||||
| } | ||||
| } | ||||
| } | ||||
| // Background nodes are intentionally ignored | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You have twice the same comment https://github.com/scality/Zenko/pull/2421/changes#diff-637785e467dea30f38c5f19d551eefd93a7feffae2da263d44066c7d8c8c2adcR55. It's maybe better to add the why, than just describing the code (if relevant). |
||||
| } | ||||
| } | ||||
|
|
||||
| if (offenders.length > 0) { | ||||
| console.error(`\n${offenders.length} scenario(s) missing a version tag (@X.Y.Z):\n`); | ||||
| offenders.forEach(o => console.error(o)); | ||||
| console.error('\nAdd a version tag (e.g. @2.15.0) to each scenario or its parent Feature.\n'); | ||||
| process.exit(1); | ||||
| } | ||||
|
|
||||
| console.log(`All ${totalScenarios} scenarios have a version tag.`); | ||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,7 @@ | |
| "node": ">=24" | ||
| }, | ||
| "dependencies": { | ||
| "@cucumber/cucumber": "^12.7.0", | ||
| "@cucumber/cucumber": "^12.9.0", | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. kinda useless because of the caret but still did it as im adding the dev dependencies |
||
| "@kubernetes/client-node": "^1.4.0", | ||
| "@platformatic/kafka": "^1.30.0", | ||
| "@smithy/node-http-handler": "^4.0.0", | ||
|
|
@@ -33,6 +33,8 @@ | |
| "@aws-sdk/client-iam": "^3.901.0", | ||
| "@aws-sdk/client-s3": "^3.931.0", | ||
| "@aws-sdk/client-sts": "^3.901.0", | ||
| "@cucumber/gherkin": "^38.0.0", | ||
| "@cucumber/messages": "^32.3.1", | ||
| "@eslint/compat": "^1.1.1", | ||
| "@eslint/eslintrc": "^3.1.0", | ||
| "@eslint/js": "^9.9.1", | ||
|
|
@@ -50,6 +52,7 @@ | |
| "scripts": { | ||
| "build:cucumber": "tsc --build tsconfig.json", | ||
| "unused-steps": "! yarn cucumber-js --config ctst/cucumber.config.cjs --dry-run --format usage 2>&1 | grep UNUSED", | ||
| "ensure-version-tags": "ts-node ctst/scripts/ensureVersionTags.ts", | ||
| "test:aws_crr": "mocha --config mocha/.mocharc.js -t 10000 --reporter-options configFile=mocha/mocha-reporter.json,cmrOutput=mocha-junit-reporter+testsuitesTitle+test_aws_crr mocha/backbeat/tests/crr/awsBackend.js", | ||
| "test:azure_crr": "mocha --config mocha/.mocharc.js -t 10000 --reporter-options configFile=mocha/mocha-reporter.json,cmrOutput=mocha-junit-reporter+testsuitesTitle+test_azure_crr mocha/backbeat/tests/crr/azureBackend.js", | ||
| "test:gcp_crr": "mocha --config mocha/.mocharc.js -t 10000 --reporter-options configFile=mocha/mocha-reporter.json,cmrOutput=mocha-junit-reporter+testsuitesTitle+test_gcp_crr mocha/backbeat/tests/crr/gcpBackend.js", | ||
|
|
||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we want that?
this "tagging" was introduced when CTST was used in Artesca, and embedded the tests : so there was one version of CTST and tests targeting multiple zenko versions.
the tests are now managed in
git-so the information is really available via git blame or others-, I don't see the benefit of manually adding the tag on every test?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, yes, there is another version of this pr where I just remove all tags + the useless before hook
I kinda liked having directly visible tags attached to the scenarios as its faster to read than commits but you're right