@platformatic/runtime 0.31.0 → 0.32.0
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 +1 -1
- package/fixtures/dbAppWithMigrationError/migrations/001.do.sql +4 -0
- package/fixtures/dbAppWithMigrationError/migrations/001.undo.sql +1 -0
- package/fixtures/dbAppWithMigrationError/platformatic.db.json +28 -0
- package/fixtures/dbAppWithMigrationError/plugin.js +5 -0
- package/fixtures/leven/.env.sample +4 -0
- package/fixtures/leven/platformatic.runtime.json +12 -0
- package/fixtures/leven/services/deeply-spittle/platformatic.service.json +25 -0
- package/fixtures/leven/services/deeply-spittle/plugins/example.js +6 -0
- package/fixtures/leven/services/deeply-spittle/routes/root.js +8 -0
- package/fixtures/leven/services/rainy-empire/platformatic.composer.json +21 -0
- package/fixtures/no-env.service.json +25 -0
- package/lib/app.js +17 -10
- package/lib/config.js +12 -3
- package/lib/message-port-writable.js +8 -0
- package/lib/schema.js +8 -1
- package/package.json +11 -9
- package/test/app.test.js +32 -0
- package/test/cli/compile-2.test.mjs +69 -0
- package/test/cli/compile.test.mjs +2 -22
- package/test/cli/helper.mjs +20 -0
- package/test/config.test.js +8 -0
- package/test/start.test.js +29 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @platformatic/runtime
|
|
2
2
|
|
|
3
|
-
Check out the full documentation for Platformatic Runtime on [our website](https://
|
|
3
|
+
Check out the full documentation for Platformatic Runtime on [our website](https://docs.platformatic.dev/docs/getting-started/quick-start-guide).
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
DROP TABLE movies;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://platformatic.dev/schemas/v0.30.0/db",
|
|
3
|
+
"server": {
|
|
4
|
+
"hostname": "127.0.0.1",
|
|
5
|
+
"port": 3042
|
|
6
|
+
},
|
|
7
|
+
"migrations": {
|
|
8
|
+
"autoApply": true,
|
|
9
|
+
"dir": "migrations",
|
|
10
|
+
"table": "versions"
|
|
11
|
+
},
|
|
12
|
+
"types": {
|
|
13
|
+
"autogenerate": false
|
|
14
|
+
},
|
|
15
|
+
"plugins": {
|
|
16
|
+
"paths": [
|
|
17
|
+
"plugin.js"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"db": {
|
|
21
|
+
"connectionString": "sqlite://db.sqlite",
|
|
22
|
+
"graphql": true,
|
|
23
|
+
"ignore": {
|
|
24
|
+
"versions": true
|
|
25
|
+
},
|
|
26
|
+
"events": false
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://platformatic.dev/schemas/v0.31.0/service",
|
|
3
|
+
"server": {
|
|
4
|
+
"hostname": "{PLT_SERVER_HOSTNAME}",
|
|
5
|
+
"port": "{PORT}",
|
|
6
|
+
"logger": {
|
|
7
|
+
"level": "{PLT_SERVER_LOGGER_LEVEL}"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"service": {
|
|
11
|
+
"openapi": true
|
|
12
|
+
},
|
|
13
|
+
"plugins": {
|
|
14
|
+
"paths": [
|
|
15
|
+
{
|
|
16
|
+
"path": "./plugins",
|
|
17
|
+
"encapsulate": false,
|
|
18
|
+
"options": {
|
|
19
|
+
"example": "{PLT_EXAMPLE}"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"./routes"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="@platformatic/service" />
|
|
2
|
+
'use strict'
|
|
3
|
+
/** @param {import('fastify').FastifyInstance} fastify */
|
|
4
|
+
module.exports = async function (fastify, opts) {
|
|
5
|
+
fastify.get('/', async (request, reply) => {
|
|
6
|
+
return { hello: fastify.example }
|
|
7
|
+
})
|
|
8
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://platformatic.dev/schemas/v0.31.0/composer",
|
|
3
|
+
"server": {
|
|
4
|
+
"hostname": "{PLT_SERVER_HOSTNAME}",
|
|
5
|
+
"port": "{PORT}",
|
|
6
|
+
"logger": {
|
|
7
|
+
"level": "{PLT_SERVER_LOGGER_LEVEL}"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"composer": {
|
|
11
|
+
"services": [
|
|
12
|
+
{
|
|
13
|
+
"id": "deeply-splitte",
|
|
14
|
+
"openapi": {
|
|
15
|
+
"url": "/documentation/json"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"watch": false
|
|
21
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://platformatic.dev/schemas/v0.31.0/service",
|
|
3
|
+
"server": {
|
|
4
|
+
"hostname": "{PLT_SERVER_HOSTNAME}",
|
|
5
|
+
"port": "{PORT}",
|
|
6
|
+
"logger": {
|
|
7
|
+
"level": "{PLT_SERVER_LOGGER_LEVEL}"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"service": {
|
|
11
|
+
"openapi": true
|
|
12
|
+
},
|
|
13
|
+
"plugins": {
|
|
14
|
+
"paths": [
|
|
15
|
+
{
|
|
16
|
+
"path": "./plugins",
|
|
17
|
+
"encapsulate": false,
|
|
18
|
+
"options": {
|
|
19
|
+
"example": "{PLT_EXAMPLE}"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"./routes"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
}
|
package/lib/app.js
CHANGED
|
@@ -24,7 +24,9 @@ class PlatformaticApp {
|
|
|
24
24
|
this.server = null
|
|
25
25
|
this.#started = false
|
|
26
26
|
this.#originalWatch = null
|
|
27
|
-
this.#logger = logger
|
|
27
|
+
this.#logger = logger.child({
|
|
28
|
+
name: this.appConfig.id
|
|
29
|
+
})
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
getStatus () {
|
|
@@ -148,12 +150,19 @@ class PlatformaticApp {
|
|
|
148
150
|
async #initializeConfig () {
|
|
149
151
|
const appConfig = this.appConfig
|
|
150
152
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
153
|
+
let _config
|
|
154
|
+
try {
|
|
155
|
+
_config = await loadConfig({}, ['-c', appConfig.config], null, {
|
|
156
|
+
watch: true,
|
|
157
|
+
onMissingEnv (key) {
|
|
158
|
+
return appConfig.localServiceEnvVars.get(key)
|
|
159
|
+
}
|
|
160
|
+
})
|
|
161
|
+
} catch (err) {
|
|
162
|
+
this.#logAndExit(err)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
this.config = _config
|
|
157
166
|
const { configManager } = this.config
|
|
158
167
|
|
|
159
168
|
function applyOverrides () {
|
|
@@ -206,9 +215,7 @@ class PlatformaticApp {
|
|
|
206
215
|
#setuplogger (configManager) {
|
|
207
216
|
// Set the logger if not present (and the config supports it).
|
|
208
217
|
if (configManager.current.server) {
|
|
209
|
-
const childLogger = this.#logger.child({
|
|
210
|
-
name: this.appConfig.id
|
|
211
|
-
}, { level: configManager.current.server.logger?.level || 'info' })
|
|
218
|
+
const childLogger = this.#logger.child({}, { level: configManager.current.server.logger?.level || 'info' })
|
|
212
219
|
configManager.current.server.logger = childLogger
|
|
213
220
|
}
|
|
214
221
|
}
|
package/lib/config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const { readFile, readdir } = require('node:fs/promises')
|
|
3
3
|
const { basename, join, resolve: pathResolve } = require('node:path')
|
|
4
|
+
const { closest } = require('fastest-levenshtein')
|
|
4
5
|
const Topo = require('@hapi/topo')
|
|
5
6
|
const ConfigManager = require('@platformatic/config')
|
|
6
7
|
const { schema } = require('./schema')
|
|
@@ -71,6 +72,15 @@ async function _transformConfig (configManager) {
|
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
|
|
75
|
+
function missingDependencyErrorMessage (clientName, service, configManager) {
|
|
76
|
+
const closestName = closest(clientName, [...configManager.current.serviceMap.keys()])
|
|
77
|
+
let errorMsg = `service '${service.id}' has unknown dependency: '${clientName}'.`
|
|
78
|
+
if (closestName) {
|
|
79
|
+
errorMsg += ` Did you mean '${closestName}'?`
|
|
80
|
+
}
|
|
81
|
+
return errorMsg
|
|
82
|
+
}
|
|
83
|
+
|
|
74
84
|
async function parseClientsAndComposer (configManager) {
|
|
75
85
|
for (let i = 0; i < configManager.current.services.length; ++i) {
|
|
76
86
|
const service = configManager.current.services[i]
|
|
@@ -86,8 +96,7 @@ async function parseClientsAndComposer (configManager) {
|
|
|
86
96
|
const dependency = configManager.current.serviceMap.get(clientName)
|
|
87
97
|
|
|
88
98
|
if (dependency === undefined) {
|
|
89
|
-
|
|
90
|
-
throw new Error(`service '${service.id}' has unknown dependency: '${clientName}'`)
|
|
99
|
+
throw new Error(missingDependencyErrorMessage(clientName, service, configManager))
|
|
91
100
|
}
|
|
92
101
|
|
|
93
102
|
dependency.dependents.push(service.id)
|
|
@@ -170,7 +179,7 @@ async function parseClientsAndComposer (configManager) {
|
|
|
170
179
|
|
|
171
180
|
/* c8 ignore next 4 */
|
|
172
181
|
if (dependency === undefined) {
|
|
173
|
-
reject(new Error(
|
|
182
|
+
reject(new Error(missingDependencyErrorMessage(clientName, service, configManager)))
|
|
174
183
|
return
|
|
175
184
|
}
|
|
176
185
|
|
|
@@ -11,6 +11,14 @@ class MessagePortWritable extends Writable {
|
|
|
11
11
|
this.metadata = opts.metadata
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
_write (chunk, encoding, callback) {
|
|
15
|
+
this.port.postMessage({
|
|
16
|
+
metadata: this.metadata,
|
|
17
|
+
logs: [chunk.toString().trim()]
|
|
18
|
+
})
|
|
19
|
+
process.nextTick(callback)
|
|
20
|
+
}
|
|
21
|
+
|
|
14
22
|
_writev (chunks, callback) {
|
|
15
23
|
// Process the logs here before trying to send them across the thread
|
|
16
24
|
// boundary. Sometimes the chunks have an undocumented method on them
|
package/lib/schema.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"standard": "^17.1.0",
|
|
25
25
|
"tsd": "^0.28.1",
|
|
26
26
|
"typescript": "^5.1.6",
|
|
27
|
-
"@platformatic/sql-
|
|
28
|
-
"@platformatic/sql-
|
|
27
|
+
"@platformatic/sql-graphql": "0.32.0",
|
|
28
|
+
"@platformatic/sql-mapper": "0.32.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@hapi/topo": "^6.0.2",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"commist": "^3.2.0",
|
|
34
34
|
"desm": "^1.3.0",
|
|
35
35
|
"es-main": "^1.2.0",
|
|
36
|
+
"fastest-levenshtein": "^1.0.16",
|
|
36
37
|
"fastify": "^4.18.0",
|
|
37
38
|
"fastify-undici-dispatcher": "^0.4.1",
|
|
38
39
|
"help-me": "^4.2.0",
|
|
@@ -40,11 +41,11 @@
|
|
|
40
41
|
"pino": "^8.14.1",
|
|
41
42
|
"pino-pretty": "^10.0.0",
|
|
42
43
|
"undici": "^5.22.1",
|
|
43
|
-
"@platformatic/composer": "0.
|
|
44
|
-
"@platformatic/config": "0.
|
|
45
|
-
"@platformatic/db": "0.
|
|
46
|
-
"@platformatic/service": "0.
|
|
47
|
-
"@platformatic/utils": "0.
|
|
44
|
+
"@platformatic/composer": "0.32.0",
|
|
45
|
+
"@platformatic/config": "0.32.0",
|
|
46
|
+
"@platformatic/db": "0.32.0",
|
|
47
|
+
"@platformatic/service": "0.32.0",
|
|
48
|
+
"@platformatic/utils": "0.32.0"
|
|
48
49
|
},
|
|
49
50
|
"standard": {
|
|
50
51
|
"ignore": [
|
|
@@ -53,7 +54,8 @@
|
|
|
53
54
|
]
|
|
54
55
|
},
|
|
55
56
|
"scripts": {
|
|
56
|
-
"test": "npm run lint &&
|
|
57
|
+
"test": "npm run lint && node --test && tsd",
|
|
58
|
+
"coverage": "npm run lint && c8 -x fixtures -x test node --test && tsd",
|
|
57
59
|
"lint": "standard | snazzy"
|
|
58
60
|
}
|
|
59
61
|
}
|
package/test/app.test.js
CHANGED
|
@@ -308,3 +308,35 @@ test('restarts on config change without overriding the configManager', async (t)
|
|
|
308
308
|
}
|
|
309
309
|
assert.strictEqual(configManager, app.server.platformatic.configManager)
|
|
310
310
|
})
|
|
311
|
+
|
|
312
|
+
test('logs errors if an env variable is missing', async (t) => {
|
|
313
|
+
const { logger, stream } = getLoggerAndStream()
|
|
314
|
+
const configFile = join(fixturesDir, 'no-env.service.json')
|
|
315
|
+
const config = {
|
|
316
|
+
id: 'no-env',
|
|
317
|
+
config: configFile,
|
|
318
|
+
path: fixturesDir,
|
|
319
|
+
entrypoint: true,
|
|
320
|
+
hotReload: true
|
|
321
|
+
}
|
|
322
|
+
const app = new PlatformaticApp(config, null, logger)
|
|
323
|
+
|
|
324
|
+
t.mock.method(process, 'exit', () => {
|
|
325
|
+
throw new Error('exited')
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
await assert.rejects(async () => {
|
|
329
|
+
await app.start()
|
|
330
|
+
}, /exited/)
|
|
331
|
+
assert.strictEqual(process.exit.mock.calls.length, 1)
|
|
332
|
+
assert.strictEqual(process.exit.mock.calls[0].arguments[0], 1)
|
|
333
|
+
|
|
334
|
+
stream.end()
|
|
335
|
+
const lines = []
|
|
336
|
+
for await (const line of stream) {
|
|
337
|
+
lines.push(line)
|
|
338
|
+
}
|
|
339
|
+
const lastLine = lines[lines.length - 1]
|
|
340
|
+
assert.strictEqual(lastLine.name, 'no-env')
|
|
341
|
+
assert.strictEqual(lastLine.msg, 'Cannot parse config file. Cannot read properties of undefined (reading \'get\')')
|
|
342
|
+
})
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import { join } from 'desm'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { cliPath, delDir } from './helper.mjs'
|
|
6
|
+
import { execa } from 'execa'
|
|
7
|
+
import { mkdtemp, cp, mkdir } from 'node:fs/promises'
|
|
8
|
+
|
|
9
|
+
const base = join(import.meta.url, '..', 'tmp')
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
await mkdir(base, { recursive: true })
|
|
13
|
+
} catch {
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
test('compile with tsconfig custom flags', async (t) => {
|
|
17
|
+
const tmpDir = await mkdtemp(path.join(base, 'test-runtime-compile-'))
|
|
18
|
+
const prev = process.cwd()
|
|
19
|
+
process.chdir(tmpDir)
|
|
20
|
+
t.after(() => {
|
|
21
|
+
process.chdir(prev)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
t.after(delDir(tmpDir))
|
|
25
|
+
|
|
26
|
+
const folder = join(import.meta.url, '..', '..', 'fixtures', 'typescript-custom-flags')
|
|
27
|
+
await cp(folder, tmpDir, { recursive: true })
|
|
28
|
+
|
|
29
|
+
const { stdout } = await execa(cliPath, ['compile'])
|
|
30
|
+
|
|
31
|
+
const lines = stdout.split('\n').map(JSON.parse)
|
|
32
|
+
const expected = [{
|
|
33
|
+
name: 'movies',
|
|
34
|
+
msg: 'Typescript compilation completed successfully.'
|
|
35
|
+
}, {
|
|
36
|
+
name: 'titles',
|
|
37
|
+
msg: 'Typescript compilation completed successfully.'
|
|
38
|
+
}]
|
|
39
|
+
|
|
40
|
+
for (let i = 0; i < expected.length; i++) {
|
|
41
|
+
assert.deepStrictEqual(lines[i].name, expected[i].name)
|
|
42
|
+
assert.deepStrictEqual(lines[i].msg, expected[i].msg)
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('compile single service', async (t) => {
|
|
47
|
+
const tmpDir = await mkdtemp(path.join(base, 'test-runtime-compile-'))
|
|
48
|
+
const prev = process.cwd()
|
|
49
|
+
process.chdir(tmpDir)
|
|
50
|
+
t.after(() => {
|
|
51
|
+
process.chdir(prev)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
t.after(delDir(tmpDir))
|
|
55
|
+
|
|
56
|
+
const folder = join(import.meta.url, '..', '..', 'fixtures', 'typescript', 'services', 'movies')
|
|
57
|
+
await cp(folder, tmpDir, { recursive: true })
|
|
58
|
+
|
|
59
|
+
const { stdout } = await execa(cliPath, ['compile'])
|
|
60
|
+
|
|
61
|
+
const lines = stdout.split('\n').map(JSON.parse)
|
|
62
|
+
const expected = [{
|
|
63
|
+
msg: 'Typescript compilation completed successfully.'
|
|
64
|
+
}]
|
|
65
|
+
|
|
66
|
+
for (let i = 0; i < expected.length; i++) {
|
|
67
|
+
assert.deepStrictEqual(lines[i].msg, expected[i].msg)
|
|
68
|
+
}
|
|
69
|
+
})
|
|
@@ -2,10 +2,9 @@ import { test } from 'node:test'
|
|
|
2
2
|
import assert from 'node:assert'
|
|
3
3
|
import { join } from 'desm'
|
|
4
4
|
import path from 'node:path'
|
|
5
|
-
import { cliPath } from './helper.mjs'
|
|
5
|
+
import { cliPath, delDir } from './helper.mjs'
|
|
6
6
|
import { execa } from 'execa'
|
|
7
|
-
import { mkdtemp,
|
|
8
|
-
import { setTimeout as sleep } from 'node:timers/promises'
|
|
7
|
+
import { mkdtemp, cp, mkdir } from 'node:fs/promises'
|
|
9
8
|
|
|
10
9
|
const base = join(import.meta.url, '..', 'tmp')
|
|
11
10
|
|
|
@@ -14,25 +13,6 @@ try {
|
|
|
14
13
|
} catch {
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
function delDir (tmpDir) {
|
|
18
|
-
return async function () {
|
|
19
|
-
// We give up after 10s.
|
|
20
|
-
// This is because on Windows, it's very hard to delete files if the file
|
|
21
|
-
// system is not collaborating.
|
|
22
|
-
for (let i = 0; i < 10; i++) {
|
|
23
|
-
try {
|
|
24
|
-
await rm(tmpDir, { recursive: true, force: true })
|
|
25
|
-
break
|
|
26
|
-
} catch (err) {
|
|
27
|
-
if (err.code === 'EBUSY') {
|
|
28
|
-
await sleep(1000)
|
|
29
|
-
continue
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
16
|
test('compile without tsconfigs', async () => {
|
|
37
17
|
const config = join(import.meta.url, '..', '..', 'fixtures', 'configs', 'monorepo.json')
|
|
38
18
|
await execa(cliPath, ['compile', '-c', config])
|
package/test/cli/helper.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { Agent, setGlobalDispatcher } from 'undici'
|
|
|
3
3
|
import { execa } from 'execa'
|
|
4
4
|
import split from 'split2'
|
|
5
5
|
import { join } from 'desm'
|
|
6
|
+
import { rm } from 'node:fs/promises'
|
|
6
7
|
|
|
7
8
|
setGlobalDispatcher(new Agent({
|
|
8
9
|
keepAliveTimeout: 10,
|
|
@@ -44,3 +45,22 @@ export async function start (...args) {
|
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
}
|
|
48
|
+
|
|
49
|
+
export function delDir (tmpDir) {
|
|
50
|
+
return async function () {
|
|
51
|
+
console.time('delDir')
|
|
52
|
+
// We give up after 10s.
|
|
53
|
+
// This is because on Windows, it's very hard to delete files if the file
|
|
54
|
+
// system is not collaborating.
|
|
55
|
+
try {
|
|
56
|
+
await rm(tmpDir, { recursive: true, force: true })
|
|
57
|
+
} catch (err) {
|
|
58
|
+
if (err.code !== 'EBUSY') {
|
|
59
|
+
throw err
|
|
60
|
+
} else {
|
|
61
|
+
console.log('Could not delete directory, retrying', tmpDir)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
console.timeEnd('delDir')
|
|
65
|
+
}
|
|
66
|
+
}
|
package/test/config.test.js
CHANGED
|
@@ -55,6 +55,14 @@ test('performs a topological sort on services depending on allowCycles', async (
|
|
|
55
55
|
await loadConfig({}, ['-c', configFile], platformaticRuntime)
|
|
56
56
|
})
|
|
57
57
|
})
|
|
58
|
+
|
|
59
|
+
await t.test('throws by adding the most probable service ', async () => {
|
|
60
|
+
const configFile = join(fixturesDir, 'leven', 'platformatic.runtime.json')
|
|
61
|
+
|
|
62
|
+
await assert.rejects(async () => {
|
|
63
|
+
await loadConfig({}, ['-c', configFile], platformaticRuntime)
|
|
64
|
+
}, 'service \'rainy-empire\' has unordered dependency: \'deeply-splitte\'. Did you mean \'deeply-spittle\'?')
|
|
65
|
+
})
|
|
58
66
|
})
|
|
59
67
|
|
|
60
68
|
test('can resolve service id from client package.json if not provided', async () => {
|
package/test/start.test.js
CHANGED
|
@@ -8,6 +8,7 @@ const { MessageChannel } = require('node:worker_threads')
|
|
|
8
8
|
const { request } = require('undici')
|
|
9
9
|
const { loadConfig } = require('@platformatic/service')
|
|
10
10
|
const { buildServer, platformaticRuntime } = require('..')
|
|
11
|
+
const { wrapConfigInRuntimeConfig } = require('../lib/config')
|
|
11
12
|
const { startWithConfig } = require('../lib/start')
|
|
12
13
|
const fixturesDir = join(__dirname, '..', 'fixtures')
|
|
13
14
|
|
|
@@ -67,7 +68,7 @@ test('composer', async (t) => {
|
|
|
67
68
|
const res = await request(entryUrl)
|
|
68
69
|
|
|
69
70
|
assert.strictEqual(res.statusCode, 200)
|
|
70
|
-
assert.deepStrictEqual(await res.body.json(), { message: 'Welcome to Platformatic! Please visit https://
|
|
71
|
+
assert.deepStrictEqual(await res.body.json(), { message: 'Welcome to Platformatic! Please visit https://docs.platformatic.dev' })
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
{
|
|
@@ -156,3 +157,30 @@ test('handles uncaught exceptions with db app', async (t) => {
|
|
|
156
157
|
|
|
157
158
|
assert.strictEqual(exitCode, 42)
|
|
158
159
|
})
|
|
160
|
+
|
|
161
|
+
test('logs errors during db migrations', async (t) => {
|
|
162
|
+
const configFile = join(fixturesDir, 'dbAppWithMigrationError', 'platformatic.db.json')
|
|
163
|
+
const config = await loadConfig({}, ['-c', configFile], 'db')
|
|
164
|
+
const runtimeConfig = await wrapConfigInRuntimeConfig(config)
|
|
165
|
+
const { port1, port2 } = new MessageChannel()
|
|
166
|
+
runtimeConfig.current.loggingPort = port2
|
|
167
|
+
runtimeConfig.current.loggingMetadata = { foo: 1, bar: 2 }
|
|
168
|
+
const runtime = await startWithConfig(runtimeConfig)
|
|
169
|
+
const messages = []
|
|
170
|
+
|
|
171
|
+
port1.on('message', (msg) => {
|
|
172
|
+
messages.push(msg)
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
await assert.rejects(async () => {
|
|
176
|
+
await runtime.start()
|
|
177
|
+
}, /The runtime exited before the operation completed/)
|
|
178
|
+
|
|
179
|
+
assert.strictEqual(messages.length, 2)
|
|
180
|
+
assert.deepStrictEqual(messages[0].metadata, runtimeConfig.current.loggingMetadata)
|
|
181
|
+
assert.strictEqual(messages[0].logs.length, 1)
|
|
182
|
+
assert.match(messages[0].logs[0], /running 001.do.sql/)
|
|
183
|
+
assert.deepStrictEqual(messages[1].metadata, runtimeConfig.current.loggingMetadata)
|
|
184
|
+
assert.strictEqual(messages[1].logs.length, 1)
|
|
185
|
+
assert.match(messages[1].logs[0], /near \\"fiddlesticks\\": syntax error/)
|
|
186
|
+
})
|