apply-ddl.test.mjs
4.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import { test } from 'node:test'
import assert from 'node:assert/strict'
import { spawnSync } from 'node:child_process'
import { fileURLToPath } from 'node:url'
import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { resolveDbConfig, resolveMysql2Path } from './apply-ddl.mjs'
const APPLY = fileURLToPath(new URL('./apply-ddl.mjs', import.meta.url))
// ── resolveDbConfig(直接读 config-vars.yaml 解析后的 database: 段)─────────
test('resolveDbConfig maps the database section to mysql2 settings', () => {
const c = resolveDbConfig({
database: { host: 'db.local', port: '3307', user: 'u', password: 'p@ss', schema: 'erp_test' },
})
assert.equal(c.host, 'db.local')
assert.equal(c.port, 3307)
assert.equal(c.user, 'u')
assert.equal(c.password, 'p@ss')
assert.equal(c.database, 'erp_test')
})
test('resolveDbConfig fails closed when database.schema is missing (M1)', () => {
assert.throws(() => resolveDbConfig({ database: { user: 'root' } }, 'config-vars.yaml'), /database\.schema/)
assert.throws(() => resolveDbConfig({}), /database\.schema/)
})
test('resolveDbConfig applies sane defaults for host/port/user/password', () => {
const c = resolveDbConfig({ database: { schema: 's' } })
assert.equal(c.host, '127.0.0.1')
assert.equal(c.port, 3306)
assert.equal(c.user, 'root')
assert.equal(c.password, '')
})
test('resolveDbConfig rejects invalid ports', () => {
assert.throws(() => resolveDbConfig({ database: { schema: 'erp_test', port: 'abc' } }), /database\.port/)
assert.throws(() => resolveDbConfig({ database: { schema: 'erp_test', port: '70000' } }), /database\.port/)
})
test('resolveDbConfig rejects unfilled 【人工填写】 placeholders as incomplete config', () => {
const base = { host: 'h', port: '3306', user: 'u', password: 'p', schema: 's' }
assert.throws(() => resolveDbConfig({ database: { ...base, schema: '【人工填写:schema 名】' } }), /仍是占位/)
assert.throws(() => resolveDbConfig({ database: { ...base, host: '【人工填写:MySQL host】' } }), /仍是占位/)
assert.throws(() => resolveDbConfig({ database: { ...base, user: '【人工填写:账号】' } }), /仍是占位/)
assert.throws(() => resolveDbConfig({ database: { ...base, password: '【人工填写:密码】' } }), /仍是占位/)
})
test('resolveDbConfig allows an explicit empty database.password', () => {
const c = resolveDbConfig({ database: { host: '127.0.0.1', port: '3306', user: 'root', password: '', schema: 'erp_dev' } })
assert.equal(c.password, '')
assert.equal(c.database, 'erp_dev')
})
// ── DDL-6:缺文件应退出码 2(用法/路径错),与 db-init C.2 文档及 validate-ddl 对齐 ──
test('apply-ddl CLI exits 2 when the config file does not exist (DDL-6)', () => {
const r = spawnSync('node', [APPLY, '/no/such/config-vars.yaml', '/no/such/V1.sql'], { encoding: 'utf8' })
assert.equal(r.status, 2, 'missing config file should be exit 2, not 1 — stderr: ' + r.stderr)
})
test('apply-ddl CLI exits 2 when the DDL file does not exist (DDL-6)', () => {
// config exists (this very test file stands in as an existing path), DDL does not
const r = spawnSync('node', [APPLY, APPLY, '/no/such/V1.sql'], { encoding: 'utf8' })
assert.equal(r.status, 2, 'missing DDL file should be exit 2 — stderr: ' + r.stderr)
})
test('apply-ddl CLI exits 2 on missing arguments (existing behavior preserved)', () => {
const r = spawnSync('node', [APPLY], { encoding: 'utf8' })
assert.equal(r.status, 2)
})
// ── H2:mysql2 必须从「目标项目」解析,而非插件自身目录 ────────────────────
// ESM 裸说明符按 importer 解析;apply-ddl.mjs 住在插件目录,若直接 import('mysql2/promise')
// 则永远看不到目标项目 `npm i mysql2` 的安装。resolveMysql2Path 用 createRequire(目标根) 修正。
test('resolveMysql2Path resolves mysql2/promise from the target project dir (H2)', () => {
const dir = mkdtempSync(join(tmpdir(), 'erp-m2-'))
mkdirSync(join(dir, 'node_modules', 'mysql2'), { recursive: true })
writeFileSync(join(dir, 'node_modules', 'mysql2', 'package.json'),
JSON.stringify({ name: 'mysql2', version: '0.0.0', exports: { './promise': './promise.js' } }))
writeFileSync(join(dir, 'node_modules', 'mysql2', 'promise.js'), 'export default {}')
const p = resolveMysql2Path(dir)
assert.match(p, /node_modules[\\/]mysql2[\\/]promise\.js$/, 'got: ' + p)
})
test('resolveMysql2Path throws when mysql2 is absent in the target project (H2)', () => {
const dir = mkdtempSync(join(tmpdir(), 'erp-m2-empty-'))
assert.throws(() => resolveMysql2Path(dir))
})