This repository has been archived on 2026-11-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
qqq-orb/tests/test_ci_maintenance.py

110 lines
6.7 KiB
Python

"""CI maintenance retains Maven verification and never becomes a release request."""
import importlib.util
from pathlib import Path
import unittest
from unittest import mock
import yaml
ROOT = Path(__file__).resolve().parents[1]
spec = importlib.util.spec_from_file_location('pipeline', ROOT/'src/scripts/generate_pipeline.py')
pipeline = importlib.util.module_from_spec(spec)
spec.loader.exec_module(pipeline)
class MaintenanceTests(unittest.TestCase):
def git_result(self, *args):
return {'log': self.subject, 'rev-list': self.parents, 'diff': self.paths}.get(args[0])
def setUp(self):
self.subject = b'ci: use central pipeline\n'
self.parents = b'a'*40 + b' ' + b'b'*40 + b'\n'
self.paths = b'.qqq-ci.yml\0.circleci/config.yml\0.github/workflows/codeql.yml\0.github/workflows/release-rc.yml\0'
def test_publishing_branches_keep_unfiltered_maven_tests(self):
manifest = {'profile': 'qbit', 'orb_version': '0.7.14', 'default_branch': 'develop',
'release_on_main': True, 'test_branch_policy': 'feature-no-hotfix',
'publish': {'hotfix': True}}
with mock.patch.object(Path, 'read_text', return_value=yaml.safe_dump(manifest)):
config = pipeline.load_manifest('unused', '0.7.14')
with mock.patch.object(pipeline, 'git', side_effect=self.git_result):
for branch in ('main', 'develop', 'release/0.1', 'hotfix/1.2.3'):
with self.subTest(branch=branch):
result = pipeline.qbit_template(config, branch, '')
job = result['workflows']['test_only']['jobs'][0]['qqq-orb/mvn_test_only']
self.assertEqual(job['filters']['branches'], {'ignore': 'automation/qbit-rc-pending'})
self.assertNotIn('branch_type', job)
def test_nonpublishing_branches_verify_maintenance_but_keep_application_policy(self):
manifest = {'profile': 'qbit', 'orb_version': '0.8', 'default_branch': 'main',
'release_on_main': False, 'test_branch_policy': 'feature-no-hotfix',
'publish': {'snapshot': False, 'release_candidate': False, 'hotfix': False}}
with mock.patch.object(Path, 'read_text', return_value=yaml.safe_dump(manifest)):
config = pipeline.load_manifest('unused', '0.8')
maintenance_paths = self.paths
with mock.patch.object(pipeline, 'git', side_effect=self.git_result):
for branch in ('main', 'develop', 'release/0.1', 'hotfix/1.2.3'):
for maintenance in (True, False):
with self.subTest(branch=branch, maintenance=maintenance):
self.paths = maintenance_paths if maintenance else b'src/Main.java\0'
result = pipeline.qbit_template(config, branch, '')
job = result['workflows']['test_only']['jobs'][0]['qqq-orb/mvn_test_only']
ignored = job['filters']['branches']['ignore']
if maintenance:
self.assertEqual(ignored, 'automation/qbit-rc-pending')
else:
self.assertEqual(ignored, ['automation/qbit-rc-pending',
'/(develop|main|release/.*|hotfix/.*|integration.*)/'])
self.assertNotIn('branch_type', job)
def test_frontend_maintenance_verifies_without_publishing(self):
for profile, prefix in (('frontend-core', 'node_'), ('frontend-material', 'mvn_frontend_')):
manifest = {'profile': profile, 'orb_version': '0.8', 'default_branch': 'develop'}
with mock.patch.object(Path, 'read_text', return_value=yaml.safe_dump(manifest)):
config = pipeline.load_manifest('unused', '0.8')
for branch in ('main', 'develop', 'release/1.0', 'hotfix/1.0.1'):
with self.subTest(profile=profile, branch=branch), mock.patch.object(pipeline, 'git', side_effect=self.git_result):
result = pipeline.frontend_template(config, branch, '')
job = result['workflows']['test_only']['jobs'][0]['qqq-orb/' + prefix + 'test_only']
self.assertNotIn('branch_type', job)
self.assertEqual(job['filters']['branches'], {'ignore': 'automation/qbit-rc-pending'})
self.paths = b'package.json\0'
with mock.patch.object(pipeline, 'git', side_effect=self.git_result):
result = pipeline.frontend_template(config, 'develop', '')
self.assertIn('qqq-orb/' + prefix + 'publish', result['workflows']['publish_snapshot']['jobs'][0])
self.paths = b'.qqq-ci.yml\0'
with mock.patch.object(pipeline, 'git', return_value=b'verified-head\n'):
result = pipeline.frontend_template(config, 'main', 'v1.2.3')
job = result['workflows']['publish_release']['jobs'][0]['qqq-orb/' + prefix + 'publish']
self.assertEqual(job['branch_type'], 'release')
def test_application_changes_and_unknown_files_publish_normally(self):
for paths in (b'pom.xml\0', b'.qqq-ci.yml\0src/Main.java\0', b'.github/workflows/custom-release.yml\0', b'', None):
self.paths = paths
with mock.patch.object(pipeline, 'git', side_effect=self.git_result):
self.assertFalse(pipeline.proven_ci_maintenance('release/0.1', ''))
def test_schema_caller_migration_is_maintenance_but_schema_inputs_are_not(self):
self.paths = b'.github/workflows/schema-drift.yml\0'
with mock.patch.object(pipeline, 'git', side_effect=self.git_result):
self.assertTrue(pipeline.proven_ci_maintenance('release/0.1', ''))
for path in (b'pom.xml\0', b'src/test/resources/schema.yml\0', b'src/test/java/SchemaDriftTest.java\0'):
self.paths = b'.github/workflows/schema-drift.yml\0' + path
self.assertFalse(pipeline.proven_ci_maintenance('release/0.1', ''))
def test_merge_root_and_unavailable_history_do_not_suppress_release(self):
for parents in (None, b'a'*40+b'\n', self.parents.rstrip()+b' '+b'c'*40+b'\n'):
self.parents = parents
with mock.patch.object(pipeline, 'git', side_effect=self.git_result):
self.assertFalse(pipeline.proven_ci_maintenance('release/0.1', ''))
def test_tags_and_release_requests_do_not_suppress_release(self):
with mock.patch.object(pipeline, 'git', side_effect=self.git_result):
self.assertFalse(pipeline.proven_ci_maintenance('main', 'v1.2.3'))
for subject in (b'Merge develop for next RC\n', b'fix: application\n', None):
self.subject = subject
self.assertFalse(pipeline.proven_ci_maintenance('release/0.1', ''))
if __name__ == '__main__':
unittest.main()