forked from coder/code-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhelpers.ts
More file actions
138 lines (126 loc) · 4.43 KB
/
Copy pathhelpers.ts
File metadata and controls
138 lines (126 loc) · 4.43 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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import { logger } from "@coder/logger"
import { promises as fs } from "fs"
import * as net from "net"
import * as os from "os"
import * as path from "path"
import { CodeServer, CodeServerPage } from "../e2e/models/CodeServer"
import { REVERSE_PROXY_PORT, REVERSE_PROXY_BASE_PATH } from "./constants"
/**
* Spy on the logger and console and replace with mock implementations to
* suppress the output.
*/
export function mockLogger() {
jest.spyOn(logger, "debug").mockImplementation()
jest.spyOn(logger, "error").mockImplementation()
jest.spyOn(logger, "info").mockImplementation()
jest.spyOn(logger, "trace").mockImplementation()
jest.spyOn(logger, "warn").mockImplementation()
jest.spyOn(console, "log").mockImplementation()
jest.spyOn(console, "debug").mockImplementation()
jest.spyOn(console, "error").mockImplementation()
jest.spyOn(console, "info").mockImplementation()
jest.spyOn(console, "trace").mockImplementation()
jest.spyOn(console, "warn").mockImplementation()
}
/**
* Clean up directories left by a test. It is recommended to do this when a test
* starts to avoid potentially accumulating infinite test directories.
*/
export async function clean(testName: string): Promise<void> {
const dir = path.join(os.tmpdir(), `code-server/tests/${testName}`)
await fs.rm(dir, { force: true, recursive: true })
}
/**
* Create a uniquely named temporary directory for a test.
*
* `tmpdir` should usually be preceeded by at least one call to `clean`.
*/
export async function tmpdir(testName: string): Promise<string> {
const dir = path.join(os.tmpdir(), `code-server/tests/${testName}`)
await fs.mkdir(dir, { recursive: true })
return await fs.mkdtemp(path.join(dir, `${testName}-`), { encoding: "utf8" })
}
/**
* @description Helper function to use an environment variable.
*
* @returns an array (similar to useState in React) with a function
* to set the value and reset the value
*/
export function useEnv(key: string): [(nextValue: string | undefined) => string | undefined, () => void] {
const initialValue = process.env[key]
const setValue = (nextValue: string | undefined) => (process.env[key] = nextValue)
// Node automatically converts undefined to string 'undefined'
// when assigning an environment variable.
// which is why we need to delete it if it's supposed to be undefined
// Source: https://stackoverflow.com/a/60147167
const resetValue = () => {
if (initialValue !== undefined) {
process.env[key] = initialValue
} else {
delete process.env[key]
}
}
return [setValue, resetValue]
}
/**
* Helper function to get a random port.
*
* Source: https://github.com/sindresorhus/get-port/blob/main/index.js#L23-L33
*/
export const getAvailablePort = (options?: net.ListenOptions): Promise<number> =>
new Promise((resolve, reject) => {
const server = net.createServer()
server.unref()
server.on("error", reject)
server.listen(options, () => {
// NOTE@jsjoeio: not a huge fan of the type assertion
// but it works for now.
const { port } = server.address() as net.AddressInfo
server.close(() => {
resolve(port)
})
})
})
/**
* Return a timer that will not reject as long as it is disposed or continually
* reset before the delay elapses.
*/
export function idleTimer(message: string, reject: (error: Error) => void, delay = 5000) {
const start = () => setTimeout(() => reject(new Error(message)), delay)
let timeout = start()
return {
reset: () => {
clearTimeout(timeout)
timeout = start()
},
dispose: () => {
clearTimeout(timeout)
},
}
}
/**
* A helper function which returns a boolean indicating whether
* the given address is AddressInfo and has .address
* and a .port property.
*/
export function isAddressInfo(address: unknown): address is net.AddressInfo {
return (
address !== null &&
typeof address !== "string" &&
(address as net.AddressInfo).port !== undefined &&
(address as net.AddressInfo).address !== undefined
)
}
/**
* If using a proxy, return the address of the proxy.
*
* Otherwise, return the direct address of code-server.
*/
export async function getMaybeProxiedCodeServer(codeServer: CodeServerPage | CodeServer): Promise<string> {
const address = await codeServer.address()
if (process.env.USE_PROXY === "1") {
const uri = new URL(address)
return `http://${uri.hostname}:${REVERSE_PROXY_PORT}/${uri.port}/${REVERSE_PROXY_BASE_PATH}/`
}
return address
}