Files
yidaima/RuoYi-Vue/ruoyi-ui/test/pluginRegistryView.test.mjs

249 lines
11 KiB
JavaScript

import test from 'node:test'
import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..')
const read = path => readFileSync(resolve(root, path), 'utf8')
test('plugin registry api exposes status and immutable publication operations', () => {
const api = read('src/api/generator/plugin.js')
for (const name of [
'getPluginRegistryStatus',
'probePluginSqlTarget',
'getPluginDeliveryVerification',
'createPluginDeliveryRehearsal',
'listPluginDeliveryRehearsals',
'getPluginDeliveryRehearsal',
'startPluginDeliveryRehearsal',
'listPluginDeliveryRehearsalAttempts',
'getPluginDeliveryRehearsalAttempt',
'abortPluginDeliveryRehearsalAttempt',
'reconcilePluginDeliveryRehearsalAttempt',
'comparePluginDeliveryRehearsalAttempts',
'getPluginDeliveryReleaseGate',
'getPluginRegistryReadiness',
'bootstrapPluginRegistry',
'listPlugins',
'getPlugin',
'addPlugin',
'updatePlugin',
'createPluginVersion',
'publishPluginVersion',
'rollbackPluginVersion',
'preflightPluginTransition',
'executePluginTransition',
'retryPluginTransition',
'compensatePluginTransition',
'requestPluginTransitionApproval',
'listPluginTransitionApprovals',
'approvePluginTransitionApproval',
'revokePluginTransitionApproval',
'getPluginTransitionExecutions',
'reconcilePluginTransitionExecution'
]) {
assert.equal(api.includes(`export function ${name}`), true, `${name} should be exported`)
}
assert.match(api, /plugin\/registry-status/)
assert.match(api, /plugin\/sql-target\/probe/)
assert.match(api, /plugin\/delivery-verification/)
assert.match(api, /plugin\/delivery-rehearsals/)
assert.match(api, /delivery-rehearsals\/\$\{rehearsalId\}/)
assert.match(api, /delivery-rehearsals\/\$\{rehearsalId\}\/attempts/)
assert.match(api, /attempts\/\$\{attemptId\}\/abort/)
assert.match(api, /attempts\/\$\{attemptId\}\/reconcile/)
assert.match(api, /attempt-comparison/)
assert.match(api, /release-gate/)
assert.match(api, /baselineAttemptId, candidateAttemptId/)
assert.match(api, /sql-target\/probe', method: 'post'/)
assert.match(api, /plugin\/readiness/)
assert.match(api, /plugin\/bootstrap/)
assert.match(api, /versions\/\$\{pluginVersionId\}\/publish/)
assert.match(api, /versions\/\$\{pluginVersionId\}\/rollback/)
assert.match(api, /transitions\/\$\{transitionId\}\/preflight/)
assert.match(api, /params: \{ executionMode \}/)
assert.match(api, /transitions\/\$\{transitionId\}\/execute/)
assert.match(api, /transitions\/\$\{transitionId\}\/retry/)
assert.match(api, /transitions\/\$\{transitionId\}\/compensate/)
assert.match(api, /executePluginTransition\(pluginId, transitionId, data\)/)
assert.match(api, /retryPluginTransition\(pluginId, transitionId, data\)/)
assert.match(api, /compensatePluginTransition\(pluginId, transitionId, data\)/)
assert.match(api, /transitions\/\$\{transitionId\}\/approvals`/)
assert.match(api, /approvals\/\$\{approvalId\}\/approve/)
assert.match(api, /approvals\/\$\{approvalId\}\/revoke/)
assert.match(api, /executions\/\$\{executionId\}\/reconcile/)
})
test('plugin registry view manages installed definitions and release lifecycle', () => {
const view = read('src/views/generator/plugin/index.vue')
assert.match(view, /name: 'PluginRegistry'/)
assert.match(view, /registryStatus\.databaseEnabled/)
assert.match(view, /registryReadiness\.readyReleaseCount/)
assert.match(view, /bootstrapPluginRegistry/)
assert.match(view, /readinessStateLabel/)
assert.match(view, /contributionReversible/)
assert.match(view, /IRREVERSIBLE_CONTRIBUTION/)
assert.match(view, /installedManifests/)
assert.match(view, /createPluginVersion/)
assert.match(view, /publishPluginVersion/)
assert.match(view, /rollbackPluginVersion/)
assert.match(view, /detail\.transitions/)
assert.match(view, /transitionOperationLabel/)
assert.match(view, /inspectTransitionPlan/)
assert.match(view, /transitionFingerprint/)
assert.match(view, /latestExecutionStatus/)
assert.match(view, /runTransition/)
assert.match(view, /openExecutionHistory/)
assert.match(view, /executionDialogOpen/)
assert.match(view, /reconcilePluginTransitionExecution/)
assert.match(view, /reconcileExecution/)
assert.match(view, /outbox\.status/)
assert.match(view, /deliveryCount/)
assert.match(view, /leaseUntil/)
assert.match(view, /QUEUED/)
assert.match(view, /PROCESSING/)
assert.match(view, /DELIVERED/)
assert.match(view, /已入队/)
assert.match(view, /dry-run:v1/)
assert.match(view, /sql-jdbc:v1/)
assert.match(view, /permission-jdbc:v1/)
assert.match(view, /menu-jdbc:v1/)
assert.match(view, /executorCode/)
assert.match(view, /routed:v1/)
assert.match(view, /executionEnvironmentCode/)
assert.match(view, /routingFingerprint/)
assert.match(view, /approvalRequiredForNonDryRun/)
assert.match(view, /approvalSeparationEnabled/)
assert.match(view, /approvalRequestTtlMinutes/)
assert.match(view, /approvalValidityMinutes/)
assert.match(view, /realExecutorConfigured/)
assert.match(view, /executorRoutes/)
assert.match(view, /expectedTransitionFingerprint/)
assert.match(view, /expectedRoutingFingerprint/)
assert.match(view, /environmentCode/)
assert.match(view, /approvalId/)
assert.match(view, /requestPluginTransitionApproval/)
assert.match(view, /listPluginTransitionApprovals/)
assert.match(view, /approvePluginTransitionApproval/)
assert.match(view, /revokePluginTransitionApproval/)
assert.match(view, /preflightPluginTransition/)
assert.match(view, /approvalPreflight/)
assert.match(view, /executableApprovals/)
assert.match(view, /preflightStateLabel/)
assert.match(view, /approvalPreflight\.routes/)
assert.match(view, /requestReason/)
assert.match(view, /requesterRoles/)
assert.match(view, /approverRoles/)
assert.match(view, /approvalReason/)
assert.match(view, /\$prompt/)
assert.match(view, /approvedBy/)
assert.match(view, /approvedAt/)
assert.match(view, /step\.row\.executorCode/)
assert.match(view, /sqlTargetReady/)
assert.match(view, /sqlTargetEnvironmentCode/)
assert.match(view, /sqlTargetCatalog/)
assert.match(view, /probePluginSqlTarget/)
assert.match(view, /sqlTargetProbeLoading/)
assert.match(view, /sqlTargetProbe/)
assert.match(view, /probeSqlTarget/)
assert.match(view, /NOT_CHECKED/)
assert.match(view, /LEDGER_UNAVAILABLE/)
assert.match(view, /PERMISSION_LEDGER_UNAVAILABLE/)
assert.match(view, /permissionLedgerRequired/)
assert.match(view, /permissionLedgerReady/)
assert.match(view, /MENU_LEDGER_UNAVAILABLE/)
assert.match(view, /menuLedgerRequired/)
assert.match(view, /menuLedgerReady/)
assert.match(view, /INVALID_CONFIGURATION/)
assert.doesNotMatch(view, /registryStatus\.jdbcUrl/)
assert.doesNotMatch(view, /registryStatus\.username/)
assert.doesNotMatch(view, /registryStatus\.password/)
assert.match(view, /class="manifest-view"/)
assert.match(view, /generator:plugin:publish/)
assert.match(view, /generator:plugin:rollback/)
assert.match(view, /Conflicting|Manifest/)
assert.doesNotMatch(view, /<textarea/)
const runStart = view.indexOf(' runTransition(row, action)')
const runEnd = view.indexOf(' availableTransitionAction(row)', runStart)
const runTransition = view.slice(runStart, runEnd)
assert.match(runTransition, /approvalId/)
assert.match(runTransition, /preflightPluginTransition/)
assert.match(runTransition, /preflight\.approvalRequired/)
assert.doesNotMatch(runTransition, /approvalReason/)
assert.doesNotMatch(runTransition, /registryStatus\.realExecutorConfigured/)
})
test('delivery verification view exposes the routed target snapshot', () => {
const view = read('src/views/generator/delivery/index.vue')
assert.match(view, /name: 'DeliveryVerification'/)
assert.match(view, /getPluginDeliveryVerification/)
assert.match(view, /executionEnvironmentCode/)
assert.match(view, /routingFingerprint/)
assert.match(view, /executorRoutes/)
assert.match(view, /approvalRequiredForNonDryRun/)
assert.match(view, /approvalSeparationEnabled/)
assert.match(view, /approvalValidityMinutes/)
assert.match(view, /approvalRequestTtlMinutes/)
assert.match(view, /status\.checks/)
assert.match(view, /databaseRegistryEnabled/)
assert.match(view, /acceptanceCheckLabel/)
assert.match(view, /部署验收/)
assert.match(view, /permissionLedgerReady/)
assert.match(view, /menuLedgerReady/)
assert.match(view, /MENU_LEDGER_UNAVAILABLE/)
assert.match(view, /createPluginDeliveryRehearsal/)
assert.match(view, /listPluginDeliveryRehearsals/)
assert.match(view, /getPluginDeliveryRehearsal/)
assert.match(view, /rehearsalRuns/)
assert.match(view, /selectedRehearsal/)
assert.match(view, /acceptanceFingerprint/)
assert.match(view, /scenarioFingerprint/)
assert.match(view, /acceptanceSnapshot/)
assert.match(view, /requiredEvidence/)
assert.match(view, /PLAN_ONLY/)
assert.match(view, /创建验收快照/)
assert.match(view, /部署演练报告/)
assert.match(view, /startPluginDeliveryRehearsal/)
assert.match(view, /listPluginDeliveryRehearsalAttempts/)
assert.match(view, /getPluginDeliveryRehearsalAttempt/)
assert.match(view, /abortPluginDeliveryRehearsalAttempt/)
assert.match(view, /reconcilePluginDeliveryRehearsalAttempt/)
assert.match(view, /comparePluginDeliveryRehearsalAttempts/)
assert.match(view, /getPluginDeliveryReleaseGate/)
assert.match(view, /rehearsalAttempts/)
assert.match(view, /selectedAttempt/)
assert.match(view, /LOCAL_H2/)
assert.match(view, /sandboxFingerprint/)
assert.match(view, /evidenceFingerprint/)
assert.match(view, /outbox\.status/)
assert.match(view, /deliveryCount/)
assert.match(view, /lastHeartbeatAt/)
assert.match(view, /leaseUntil/)
assert.match(view, /beginAttemptPolling/)
assert.match(view, /releaseGate\.checks/)
assert.match(view, /baselineSemanticFingerprint/)
assert.match(view, /candidateSemanticFingerprint/)
assert.match(view, /发布门禁/)
assert.match(view, /语义对比/)
assert.match(view, /持久队列/)
assert.match(view, /formatEvidence/)
assert.match(view, /启动本地 H2 演练/)
assert.match(view, /本地 H2 演练证据/)
assert.doesNotMatch(view, /executePluginTransition/)
assert.doesNotMatch(view, /jdbc:h2/)
assert.doesNotMatch(view, /leaseToken/)
assert.doesNotMatch(view, /jdbcUrl/)
assert.doesNotMatch(view, /username/)
assert.doesNotMatch(view, /password/)
})
test('plugin registry menu publishes every controller permission', () => {
const sql = read('../sql/plugin_registry_menu.sql')
for (const permission of ['list', 'query', 'add', 'edit', 'version', 'publish', 'rollback', 'bootstrap', 'execute', 'approve']) {
assert.match(sql, new RegExp(`generator:plugin:${permission}`))
}
assert.match(sql, /generator\/plugin\/index/)
})