apply-ddl.test.mjs
4.11 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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { test } from 'node:test'
import assert from 'node:assert/strict'
import { assertSafeDbTarget, parseEnv, resolveDbConfig } from './apply-ddl.mjs'
test('parseEnv ignores comments, trims, keeps special chars literally', () => {
const env = parseEnv('# c\nDB_PASS=p@ss$word!\nDB_NAME = erp \n')
assert.equal(env.DB_PASS, 'p@ss$word!')
assert.equal(env.DB_NAME, 'erp')
})
test('parseEnv does NOT expand variables', () => {
const env = parseEnv('A=1\nB=${A}\nC=$A\nD=$(whoami)\nE=`id`\n')
assert.equal(env.B, '${A}')
assert.equal(env.C, '$A')
assert.equal(env.D, '$(whoami)')
assert.equal(env.E, '`id`')
})
test('parseEnv skips blank lines and comment lines', () => {
const env = parseEnv('\n \n# comment\nK=v\n # indented comment\n')
assert.deepEqual(Object.keys(env), ['K'])
assert.equal(env.K, 'v')
})
test('parseEnv strips one layer of matching quotes', () => {
const env = parseEnv(`Q1="hello world"\nQ2='a=b=c'\nQ3="$keep"\n`)
assert.equal(env.Q1, 'hello world')
assert.equal(env.Q2, 'a=b=c')
assert.equal(env.Q3, '$keep')
})
test('parseEnv keeps = signs inside the value', () => {
const env = parseEnv('URL=mysql://u:p@h:3306/db?x=1&y=2\n')
assert.equal(env.URL, 'mysql://u:p@h:3306/db?x=1&y=2')
})
test('parseEnv strips an optional leading export', () => {
const env = parseEnv('export DB_USER=root\n')
assert.equal(env.DB_USER, 'root')
})
test('parseEnv tolerates CRLF line endings', () => {
const env = parseEnv('A=1\r\nB=2\r\n')
assert.equal(env.A, '1')
assert.equal(env.B, '2')
})
test('parseEnv ignores lines without an = sign', () => {
const env = parseEnv('NOEQUALS\nK=v\n')
assert.deepEqual(Object.keys(env), ['K'])
})
test('parseEnv on empty / non-string input returns empty object', () => {
assert.deepEqual(parseEnv(''), {})
assert.deepEqual(parseEnv(undefined), {})
assert.deepEqual(parseEnv(null), {})
})
// ── resolveDbConfig(M1:DB_SCHEMA 是插件契约的 schema 键)─────────
test('resolveDbConfig maps DB_SCHEMA to database (plugin canonical key)', () => {
const c = resolveDbConfig({ DB_SCHEMA: 'erp_test', DB_USER: 'u', DB_PASS: 'p', DB_HOST: 'db.local', DB_PORT: '3307' })
assert.equal(c.database, 'erp_test')
assert.equal(c.host, 'db.local')
assert.equal(c.port, 3307)
assert.equal(c.user, 'u')
assert.equal(c.password, 'p')
})
test('resolveDbConfig honors DB_NAME / MYSQL_DATABASE aliases', () => {
assert.equal(resolveDbConfig({ DB_NAME: 'a' }).database, 'a')
assert.equal(resolveDbConfig({ MYSQL_DATABASE: 'b' }).database, 'b')
// DB_SCHEMA wins over aliases
assert.equal(resolveDbConfig({ DB_SCHEMA: 's', DB_NAME: 'a' }).database, 's')
})
test('resolveDbConfig fails closed when no schema key is present (M1)', () => {
assert.throws(() => resolveDbConfig({ DB_USER: 'root' }, '.env.local'), /DB_SCHEMA/)
})
test('resolveDbConfig applies sane defaults for host/port/user/password', () => {
const c = resolveDbConfig({ DB_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({ DB_SCHEMA: 'erp_test', DB_PORT: 'abc' }), /DB_PORT/)
assert.throws(() => resolveDbConfig({ DB_SCHEMA: 'erp_test', DB_PORT: '70000' }), /DB_PORT/)
})
test('assertSafeDbTarget allows local and explicitly allowlisted test targets', () => {
assert.equal(assertSafeDbTarget({ host: 'localhost', database: 'erp_test' }), true)
assert.equal(
assertSafeDbTarget({
host: 'mysql.dev.internal',
database: 'erp_dev',
env: { TEST_DB_ALLOWED_HOSTS: 'mysql.dev.internal' },
}),
true
)
})
test('assertSafeDbTarget rejects prod-looking or injectable targets', () => {
assert.throws(
() => assertSafeDbTarget({ host: 'prod.db.internal', database: 'erp_test' }),
/非白名单 host/
)
assert.throws(
() => assertSafeDbTarget({ host: 'localhost', database: 'erp_prod' }),
/不像测试\/开发库/
)
assert.throws(
() => assertSafeDbTarget({ host: 'localhost', database: 'erp_test`; DROP DATABASE prod; --' }),
/只能包含/
)
})