-
Notifications
You must be signed in to change notification settings - Fork 0
/
test.ts
114 lines (99 loc) · 3.04 KB
/
test.ts
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
import { env } from 'node:process'
import {
execSync,
spawn,
ChildProcessWithoutNullStreams
} from 'node:child_process'
import makeDebug from 'debug'
import waitPort from 'wait-port'
const debug = makeDebug('utils/test')
export interface Options {
env?: NodeJS.ProcessEnv
port?: number
source?: string
target?: string
}
const DEFAULT = {
env,
port: 8080,
source: 'dist/bundle.js',
target: 'entryPoint'
}
/**
* Spawns a child process that will launch the Functions Framework (basically a
* HTTP server) on the specified port.
*
* @experimental
*
* @see [Integration tests - Cloud Functions](https://cloud.google.com/functions/docs/testing/test-background#integration_tests)
* @see [Configure the Functions Framework](https://github.com/GoogleCloudPlatform/functions-framework-nodejs#configure-the-functions-framework)
* @see [killport](https://github.com/splendourhui/killport)
*/
export const spawnFunctionsFramework = async (options?: Options) => {
const env = (options && options.env) || DEFAULT.env
const port = (options && options.port) || DEFAULT.port
const source = (options && options.source) || DEFAULT.source
const target = (options && options.target) || DEFAULT.target
const npx = execSync('which npx').toString().trim()
const args = [
'functions-framework',
'--source',
`${source}`,
'--target',
`${target}`,
'--signature-type',
'http',
'--port',
`${port}`
]
const child = spawn(npx, args, { env })
debug(
'functions-framework HTTP server is serving %s (entry point %s) on port %d',
source,
target,
port
)
debug('child process args %s', JSON.stringify(args, null, 2))
child.on('kill-functions-framework-process', () => {
const stdout = execSync(`lsof -i tcp:${port}`).toString()
debug('processes listening on port %d\n%s', port, stdout)
const lines = stdout.trim().split('\n').slice(1)
lines.forEach((line, i) => {
debug('STDOUT line[%d] %s', i, line.trim())
const row = line.trim().split(/\s+/)
const pid = parseInt(row[1])
const user = row[2]
// const protocol = row[7]
const name = row[8]
// https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=http&page=2
if (name === '*:http-alt') {
debug('send SIGTERM to PID %d (user %s)', pid, user)
process.kill(pid, 'SIGTERM')
}
})
})
debug(
'child process PID %d is listening to these events: %s',
child.pid,
JSON.stringify(child.eventNames(), null, 2)
)
debug('BEFORE waitPort (port %d)', port)
await waitPort({ host: 'localhost', port })
debug('AFTER waitPort (port %d)', port)
return child
}
export const killFunctionsFramework = (
child: ChildProcessWithoutNullStreams
) => {
child.emit('kill-functions-framework-process')
// kill the child process itself
child.kill('SIGTERM')
}
export const sleep = async (ms: number) => {
let id: NodeJS.Timeout
return new Promise<NodeJS.Timeout>((resolve) => {
id = setTimeout(() => {
resolve(id)
}, ms)
})
}