w-orm-mongodb 1.1.42 → 1.1.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -4
- package/dist/w-orm-mongodb.umd.js +2 -2
- package/dist/w-orm-mongodb.umd.js.map +1 -1
- package/docs/WOrmMongodb.html +311 -15
- package/docs/WOrmMongodb.mjs.html +261 -9
- package/docs/index.html +2 -2
- package/g-basic.mjs +7 -1
- package/g-gfs.mjs +7 -1
- package/package.json +1 -1
- package/src/WOrmMongodb.mjs +259 -7
- package/test/api-basic.test.mjs +386 -0
- package/test/api-insertbulk-rs.test.mjs +290 -0
- package/test/lib/api-setup.mjs +93 -12
- package/toolg/gDistRollup.mjs +1 -1
package/test/lib/api-setup.mjs
CHANGED
|
@@ -45,6 +45,13 @@ let genUrl = (port) => {
|
|
|
45
45
|
return `mongodb://${ctUser}:${ctPassword}@127.0.0.1:${port}`
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
//genUrlRs, replica set容器之連線字串
|
|
49
|
+
//directConnection=true係因容器內之replica set成員位址為127.0.0.1:27017, 由宿主機依該位址連不到,
|
|
50
|
+
//故不可令驅動走成員探索, 須直連本次映射之對外埠
|
|
51
|
+
let genUrlRs = (port) => {
|
|
52
|
+
return `mongodb://127.0.0.1:${port}/?directConnection=true`
|
|
53
|
+
}
|
|
54
|
+
|
|
48
55
|
//probeReady, 以mongodb驅動直連容器對外埠試跑ping
|
|
49
56
|
//不使用容器內mongosh, 因mongo映像初始化期間會先啟動僅監聽unix socket之臨時服務,
|
|
50
57
|
//容器內探測會提早回報就緒, 直連TCP方為測試實際所走路徑
|
|
@@ -64,10 +71,28 @@ let probeReady = async (port) => {
|
|
|
64
71
|
return ok
|
|
65
72
|
}
|
|
66
73
|
|
|
67
|
-
//
|
|
74
|
+
//probeReadyRs, replica set容器須等到本節點成為PRIMARY方可寫入
|
|
75
|
+
let probeReadyRs = async (port) => {
|
|
76
|
+
let client = new mongodb.MongoClient(genUrlRs(port), { serverSelectionTimeoutMS: 2000 })
|
|
77
|
+
let ok = false
|
|
78
|
+
try {
|
|
79
|
+
let hello = await client.db('admin').command({ hello: 1 })
|
|
80
|
+
ok = hello.isWritablePrimary === true
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
ok = false
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
await client.close().catch(() => {})
|
|
87
|
+
}
|
|
88
|
+
return ok
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
//runContainer, 創建容器並回傳對外埠
|
|
68
92
|
//對外埠由getFreePort動態取得, 避免與既有MongoDB服務搶27017, 亦避免多測試檔並行時互搶同一埠
|
|
69
|
-
//
|
|
70
|
-
|
|
93
|
+
//getFreePort取得之埠於關閉監聽至docker實際綁定之間可能已被他者佔用, 多測試檔並行時尤其容易發生,
|
|
94
|
+
//故綁定失敗即改取新埠重試
|
|
95
|
+
let runContainer = async (ctName, genArgs) => {
|
|
71
96
|
|
|
72
97
|
//check docker
|
|
73
98
|
await docker(['version', '--format', '{{.Server.Version}}'])
|
|
@@ -78,8 +103,7 @@ let startContainer = async (ctName) => {
|
|
|
78
103
|
//清除前次殘留容器
|
|
79
104
|
await docker(['rm', '-f', ctName]).catch(() => {})
|
|
80
105
|
|
|
81
|
-
//run
|
|
82
|
-
//多測試檔並行時尤其容易發生, 故綁定失敗即改取新埠重試
|
|
106
|
+
//run
|
|
83
107
|
let ctPort = null
|
|
84
108
|
let nTry = 10
|
|
85
109
|
for (let i = 0; i < nTry; i++) {
|
|
@@ -89,7 +113,7 @@ let startContainer = async (ctName) => {
|
|
|
89
113
|
|
|
90
114
|
//run
|
|
91
115
|
let err = null
|
|
92
|
-
await docker(
|
|
116
|
+
await docker(genArgs(ctPort))
|
|
93
117
|
.catch((e) => {
|
|
94
118
|
err = e
|
|
95
119
|
})
|
|
@@ -111,20 +135,75 @@ let startContainer = async (ctName) => {
|
|
|
111
135
|
|
|
112
136
|
}
|
|
113
137
|
|
|
114
|
-
|
|
115
|
-
|
|
138
|
+
return ctPort
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
//waitReady, 輪詢至就緒, 首次需拉取映像故給予較長時間
|
|
142
|
+
let waitReady = async (fnProbe, port, msgErr) => {
|
|
116
143
|
for (let i = 0; i < 90; i++) {
|
|
117
|
-
let ok = await
|
|
144
|
+
let ok = await fnProbe(port)
|
|
118
145
|
if (ok) {
|
|
119
|
-
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
await delay(2000)
|
|
149
|
+
}
|
|
150
|
+
throw new Error(msgErr)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
//startContainer, 創建standalone容器並等待服務就緒, 回傳容器對外埠
|
|
154
|
+
//mongo映像以MONGO_INITDB_ROOT_USERNAME、MONGO_INITDB_ROOT_PASSWORD即建妥帳號, 無須另跑建置語句
|
|
155
|
+
let startContainer = async (ctName) => {
|
|
156
|
+
|
|
157
|
+
//run
|
|
158
|
+
let ctPort = await runContainer(ctName, (port) => {
|
|
159
|
+
return ['run', '-d', '--rm', '--name', ctName, '-e', `MONGO_INITDB_ROOT_USERNAME=${ctUser}`, '-e', `MONGO_INITDB_ROOT_PASSWORD=${ctPassword}`, '-p', `${port}:27017`, ctImage]
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
//waitReady
|
|
163
|
+
await waitReady(probeReady, ctPort, 'mongodb容器啟動逾時')
|
|
164
|
+
|
|
165
|
+
return ctPort
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
//startContainerRs, 創建replica set容器並等待PRIMARY就緒, 回傳容器對外埠
|
|
169
|
+
//交易須replica set或分片叢集方可用, standalone不支援, 故驗證交易路徑須另起本容器
|
|
170
|
+
//本容器不開啟認證: --replSet配合MONGO_INITDB_ROOT_*須另備keyFile以供成員間內部認證, 於測試無必要
|
|
171
|
+
let startContainerRs = async (ctName) => {
|
|
172
|
+
|
|
173
|
+
//run
|
|
174
|
+
let ctPort = await runContainer(ctName, (port) => {
|
|
175
|
+
return ['run', '-d', '--rm', '--name', ctName, '-p', `${port}:27017`, ctImage, '--replSet', 'rs0', '--bind_ip_all']
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
//等待服務可回應, 此時尚未initiate故非PRIMARY
|
|
179
|
+
let up = false
|
|
180
|
+
for (let i = 0; i < 90; i++) {
|
|
181
|
+
let ok = await docker(['exec', ctName, 'mongosh', '--quiet', '--eval', 'db.adminCommand({ping:1}).ok'])
|
|
182
|
+
.then(() => true)
|
|
183
|
+
.catch(() => false)
|
|
184
|
+
if (ok) {
|
|
185
|
+
up = true
|
|
120
186
|
break
|
|
121
187
|
}
|
|
122
188
|
await delay(2000)
|
|
123
189
|
}
|
|
124
|
-
if (!
|
|
125
|
-
throw new Error('mongodb容器啟動逾時')
|
|
190
|
+
if (!up) {
|
|
191
|
+
throw new Error('mongodb replica set容器啟動逾時')
|
|
126
192
|
}
|
|
127
193
|
|
|
194
|
+
//initiate, 單成員之replica set即足以啟用交易
|
|
195
|
+
await docker(['exec', ctName, 'mongosh', '--quiet', '--eval', 'rs.initiate({_id:"rs0",members:[{_id:0,host:"127.0.0.1:27017"}]})'])
|
|
196
|
+
.catch((err) => {
|
|
197
|
+
//已initiate者再次呼叫會報AlreadyInitialized, 屬正常
|
|
198
|
+
let msg = `${err.stderr || ''}${err.message || ''}`
|
|
199
|
+
if (msg.indexOf('AlreadyInitialized') < 0) {
|
|
200
|
+
throw err
|
|
201
|
+
}
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
//waitReady, 等待本節點成為PRIMARY
|
|
205
|
+
await waitReady(probeReadyRs, ctPort, 'mongodb replica set選舉逾時')
|
|
206
|
+
|
|
128
207
|
return ctPort
|
|
129
208
|
}
|
|
130
209
|
|
|
@@ -137,6 +216,8 @@ let stopContainer = async (ctName) => {
|
|
|
137
216
|
export {
|
|
138
217
|
delay,
|
|
139
218
|
genUrl,
|
|
219
|
+
genUrlRs,
|
|
140
220
|
startContainer,
|
|
221
|
+
startContainerRs,
|
|
141
222
|
stopContainer
|
|
142
223
|
}
|