From 92bf2c976068b513256a909cbe8822e460c96524 Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 5 May 2021 10:16:01 -0500 Subject: [PATCH 1/5] Add dev mode constant --- src/node/constants.ts | 1 + src/node/routes/vscode.ts | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/node/constants.ts b/src/node/constants.ts index c198f8fb3..d36f9a24a 100644 --- a/src/node/constants.ts +++ b/src/node/constants.ts @@ -20,3 +20,4 @@ export const version = pkg.version || "development" export const commit = pkg.commit || "development" export const rootPath = path.resolve(__dirname, "../..") export const tmpdir = path.join(os.tmpdir(), "code-server") +export const isDevMode = commit === "development" diff --git a/src/node/routes/vscode.ts b/src/node/routes/vscode.ts index 0d9c63096..287216ecc 100644 --- a/src/node/routes/vscode.ts +++ b/src/node/routes/vscode.ts @@ -7,7 +7,7 @@ import * as ipc from "../../../typings/ipc" import { Emitter } from "../../common/emitter" import { HttpCode, HttpError } from "../../common/http" import { getFirstString } from "../../common/util" -import { commit, rootPath, version } from "../constants" +import { isDevMode, rootPath, version } from "../constants" import { authenticated, ensureAuthenticated, redirect, replaceTemplates } from "../http" import { getMediaMime, pathToFsPath } from "../util" import { VscodeProvider } from "../vscode" @@ -31,7 +31,7 @@ router.get("/", async (req, res) => { try { return await vscode.initialize({ args: req.args, remoteAuthority: req.headers.host || "" }, req.query) } catch (error) { - const devMessage = commit === "development" ? "It might not have finished compiling." : "" + const devMessage = isDevMode ? "It might not have finished compiling." : "" throw new Error(`VS Code failed to load. ${devMessage} ${error.message}`) } })(), @@ -44,7 +44,7 @@ router.get("/", async (req, res) => { req, // Uncomment prod blocks if not in development. TODO: Would this be // better as a build step? Or maintain two HTML files again? - commit !== "development" ? content.replace(//g, "") : content, + !isDevMode ? content.replace(//g, "") : content, { authed: req.args.auth !== "none", disableTelemetry: !!req.args["disable-telemetry"], From 083400b50a2983c05f81a41f38afd2c61350ed08 Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 4 May 2021 16:46:08 -0500 Subject: [PATCH 2/5] Add flag to enable permessage-deflate --- src/node/cli.ts | 9 +++++++++ src/node/entry.ts | 16 ++++++++++++++++ src/node/routes/vscode.ts | 14 +++++++++++--- test/unit/cli.test.ts | 5 +++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/node/cli.ts b/src/node/cli.ts index 461a2e186..8278dfedb 100644 --- a/src/node/cli.ts +++ b/src/node/cli.ts @@ -6,6 +6,11 @@ import * as path from "path" import { Args as VsArgs } from "../../typings/ipc" import { canConnect, generateCertificate, generatePassword, humanPath, paths } from "./util" +export enum Feature { + /** Web socket compression. */ + PermessageDeflate = "permessage-deflate", +} + export enum AuthType { Password = "password", None = "none", @@ -35,6 +40,7 @@ export interface Args extends VsArgs { "cert-key"?: string "disable-telemetry"?: boolean "disable-update-check"?: boolean + enable?: string[] help?: boolean host?: string json?: boolean @@ -128,6 +134,9 @@ const options: Options> = { "Disable update check. Without this flag, code-server checks every 6 hours against the latest github release and \n" + "then notifies you once every week that a new release is available.", }, + // --enable can be used to enable experimental features. These features + // provide no guarantees. + enable: { type: "string[]" }, help: { type: "boolean", short: "h", description: "Show this output." }, json: { type: "boolean" }, open: { type: "boolean", description: "Open in browser on startup. Does not work remotely." }, diff --git a/src/node/entry.ts b/src/node/entry.ts index b7b61b8f4..12d74da36 100644 --- a/src/node/entry.ts +++ b/src/node/entry.ts @@ -8,6 +8,7 @@ import { createApp, ensureAddress } from "./app" import { AuthType, DefaultedArgs, + Feature, optionDescriptions, parse, readConfigFile, @@ -146,6 +147,21 @@ const main = async (args: DefaultedArgs): Promise => { } } + if (args.enable && args.enable.length > 0) { + logger.info("Enabling the following experimental features:") + args.enable.forEach((feature) => { + if (Object.values(Feature).includes(feature as Feature)) { + logger.info(` - "${feature}"`) + } else { + logger.error(` X "${feature}" (unknown feature)`) + } + }) + // TODO: Could be nice to add wrapping to the logger? + logger.info( + " The code-server project does not provide stability guarantees or commit to fixing bugs relating to these experimental features. When filing bug reports, please ensure that you can reproduce the bug with all experimental features turned off.", + ) + } + if (!args.socket && args.open) { // The web socket doesn't seem to work if browsing with 0.0.0.0. const openAddress = serverAddress.replace("://0.0.0.0", "://localhost") diff --git a/src/node/routes/vscode.ts b/src/node/routes/vscode.ts index 287216ecc..40c63e92b 100644 --- a/src/node/routes/vscode.ts +++ b/src/node/routes/vscode.ts @@ -7,6 +7,7 @@ import * as ipc from "../../../typings/ipc" import { Emitter } from "../../common/emitter" import { HttpCode, HttpError } from "../../common/http" import { getFirstString } from "../../common/util" +import { Feature } from "../cli" import { isDevMode, rootPath, version } from "../constants" import { authenticated, ensureAuthenticated, redirect, replaceTemplates } from "../http" import { getMediaMime, pathToFsPath } from "../util" @@ -209,14 +210,21 @@ wsRouter.ws("/", ensureAuthenticated, async (req) => { `Sec-WebSocket-Accept: ${reply}`, ] + // See if the browser reports it supports web socket compression. // TODO: Parse this header properly. const extensions = req.headers["sec-websocket-extensions"] - const permessageDeflate = extensions ? extensions.includes("permessage-deflate") : false - if (permessageDeflate) { + const isCompressionSupported = extensions ? extensions.includes("permessage-deflate") : false + + // TODO: For now we only use compression if the user enables it. + const isCompressionEnabled = !!req.args.enable?.includes(Feature.PermessageDeflate) + + const useCompression = isCompressionEnabled && isCompressionSupported + if (useCompression) { + // This response header tells the browser the server supports compression. responseHeaders.push("Sec-WebSocket-Extensions: permessage-deflate; server_max_window_bits=15") } req.ws.write(responseHeaders.join("\r\n") + "\r\n\r\n") - await vscode.sendWebsocket(req.ws, req.query, permessageDeflate) + await vscode.sendWebsocket(req.ws, req.query, useCompression) }) diff --git a/test/unit/cli.test.ts b/test/unit/cli.test.ts index 38d8dc7b9..6d4fcafb1 100644 --- a/test/unit/cli.test.ts +++ b/test/unit/cli.test.ts @@ -39,6 +39,10 @@ describe("parser", () => { it("should parse all available options", () => { expect( parse([ + "--enable", + "feature1", + "--enable", + "feature2", "--bind-addr=192.169.0.1:8080", "--auth", "none", @@ -82,6 +86,7 @@ describe("parser", () => { cert: { value: path.resolve("baz"), }, + enable: ["feature1", "feature2"], "extensions-dir": path.resolve("foo"), "extra-builtin-extensions-dir": [path.resolve("bazzle")], "extra-extensions-dir": [path.resolve("nozzle")], From c96fb65308bf8ff6749457abf331fa8417647704 Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 5 May 2021 11:51:09 -0500 Subject: [PATCH 3/5] Split some entry methods into main This is so they can be unit tested. --- src/node/entry.ts | 168 +--------------------------------------------- src/node/main.ts | 163 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+), 165 deletions(-) create mode 100644 src/node/main.ts diff --git a/src/node/entry.ts b/src/node/entry.ts index 12d74da36..24a557e1c 100644 --- a/src/node/entry.ts +++ b/src/node/entry.ts @@ -1,14 +1,5 @@ -import { field, logger } from "@coder/logger" -import * as cp from "child_process" -import http from "http" -import * as path from "path" -import { CliMessage, OpenCommandPipeArgs } from "../../typings/ipc" -import { plural } from "../common/util" -import { createApp, ensureAddress } from "./app" +import { logger } from "@coder/logger" import { - AuthType, - DefaultedArgs, - Feature, optionDescriptions, parse, readConfigFile, @@ -16,164 +7,11 @@ import { shouldOpenInExistingInstance, shouldRunVsCodeCli, } from "./cli" -import { coderCloudBind } from "./coder_cloud" import { commit, version } from "./constants" +import { openInExistingInstance, runCodeServer, runVsCodeCli } from "./main" import * as proxyAgent from "./proxy_agent" -import { register } from "./routes" -import { humanPath, isFile, open } from "./util" import { isChild, wrapper } from "./wrapper" -export const runVsCodeCli = (args: DefaultedArgs): void => { - logger.debug("forking vs code cli...") - const vscode = cp.fork(path.resolve(__dirname, "../../lib/vscode/out/vs/server/fork"), [], { - env: { - ...process.env, - CODE_SERVER_PARENT_PID: process.pid.toString(), - }, - }) - vscode.once("message", (message: any) => { - logger.debug("got message from VS Code", field("message", message)) - if (message.type !== "ready") { - logger.error("Unexpected response waiting for ready response", field("type", message.type)) - process.exit(1) - } - const send: CliMessage = { type: "cli", args } - vscode.send(send) - }) - vscode.once("error", (error) => { - logger.error("Got error from VS Code", field("error", error)) - process.exit(1) - }) - vscode.on("exit", (code) => process.exit(code || 0)) -} - -export const openInExistingInstance = async (args: DefaultedArgs, socketPath: string): Promise => { - const pipeArgs: OpenCommandPipeArgs & { fileURIs: string[] } = { - type: "open", - folderURIs: [], - fileURIs: [], - forceReuseWindow: args["reuse-window"], - forceNewWindow: args["new-window"], - } - - for (let i = 0; i < args._.length; i++) { - const fp = path.resolve(args._[i]) - if (await isFile(fp)) { - pipeArgs.fileURIs.push(fp) - } else { - pipeArgs.folderURIs.push(fp) - } - } - - if (pipeArgs.forceNewWindow && pipeArgs.fileURIs.length > 0) { - logger.error("--new-window can only be used with folder paths") - process.exit(1) - } - - if (pipeArgs.folderURIs.length === 0 && pipeArgs.fileURIs.length === 0) { - logger.error("Please specify at least one file or folder") - process.exit(1) - } - - const vscode = http.request( - { - path: "/", - method: "POST", - socketPath, - }, - (response) => { - response.on("data", (message) => { - logger.debug("got message from VS Code", field("message", message.toString())) - }) - }, - ) - vscode.on("error", (error: unknown) => { - logger.error("got error from VS Code", field("error", error)) - }) - vscode.write(JSON.stringify(pipeArgs)) - vscode.end() -} - -const main = async (args: DefaultedArgs): Promise => { - logger.info(`code-server ${version} ${commit}`) - - logger.info(`Using user-data-dir ${humanPath(args["user-data-dir"])}`) - logger.trace(`Using extensions-dir ${humanPath(args["extensions-dir"])}`) - - if (args.auth === AuthType.Password && !args.password && !args["hashed-password"]) { - throw new Error( - "Please pass in a password via the config file or environment variable ($PASSWORD or $HASHED_PASSWORD)", - ) - } - - const [app, wsApp, server] = await createApp(args) - const serverAddress = ensureAddress(server) - await register(app, wsApp, server, args) - - logger.info(`Using config file ${humanPath(args.config)}`) - logger.info(`HTTP server listening on ${serverAddress} ${args.link ? "(randomized by --link)" : ""}`) - - if (args.auth === AuthType.Password) { - logger.info(" - Authentication is enabled") - if (args.usingEnvPassword) { - logger.info(" - Using password from $PASSWORD") - } else if (args.usingEnvHashedPassword) { - logger.info(" - Using password from $HASHED_PASSWORD") - } else { - logger.info(` - Using password from ${humanPath(args.config)}`) - } - } else { - logger.info(` - Authentication is disabled ${args.link ? "(disabled by --link)" : ""}`) - } - - if (args.cert) { - logger.info(` - Using certificate for HTTPS: ${humanPath(args.cert.value)}`) - } else { - logger.info(` - Not serving HTTPS ${args.link ? "(disabled by --link)" : ""}`) - } - - if (args["proxy-domain"].length > 0) { - logger.info(` - ${plural(args["proxy-domain"].length, "Proxying the following domain")}:`) - args["proxy-domain"].forEach((domain) => logger.info(` - *.${domain}`)) - } - - if (args.link) { - try { - await coderCloudBind(serverAddress.replace(/^https?:\/\//, ""), args.link.value) - logger.info(" - Connected to cloud agent") - } catch (err) { - logger.error(err.message) - wrapper.exit(1) - } - } - - if (args.enable && args.enable.length > 0) { - logger.info("Enabling the following experimental features:") - args.enable.forEach((feature) => { - if (Object.values(Feature).includes(feature as Feature)) { - logger.info(` - "${feature}"`) - } else { - logger.error(` X "${feature}" (unknown feature)`) - } - }) - // TODO: Could be nice to add wrapping to the logger? - logger.info( - " The code-server project does not provide stability guarantees or commit to fixing bugs relating to these experimental features. When filing bug reports, please ensure that you can reproduce the bug with all experimental features turned off.", - ) - } - - if (!args.socket && args.open) { - // The web socket doesn't seem to work if browsing with 0.0.0.0. - const openAddress = serverAddress.replace("://0.0.0.0", "://localhost") - try { - await open(openAddress) - logger.info(`Opened ${openAddress}`) - } catch (error) { - logger.error("Failed to open", field("address", openAddress), field("error", error)) - } - } -} - async function entry(): Promise { proxyAgent.monkeyPatch(false) @@ -186,7 +24,7 @@ async function entry(): Promise { if (isChild(wrapper)) { const args = await wrapper.handshake() wrapper.preventExit() - return main(args) + return runCodeServer(args) } const cliArgs = parse(process.argv.slice(2)) diff --git a/src/node/main.ts b/src/node/main.ts new file mode 100644 index 000000000..240831c20 --- /dev/null +++ b/src/node/main.ts @@ -0,0 +1,163 @@ +import { field, logger } from "@coder/logger" +import * as cp from "child_process" +import http from "http" +import * as path from "path" +import { CliMessage, OpenCommandPipeArgs } from "../../typings/ipc" +import { plural } from "../common/util" +import { createApp, ensureAddress } from "./app" +import { AuthType, DefaultedArgs, Feature } from "./cli" +import { coderCloudBind } from "./coder_cloud" +import { commit, version } from "./constants" +import { register } from "./routes" +import { humanPath, isFile, open } from "./util" +import { wrapper } from "./wrapper" + +export const runVsCodeCli = (args: DefaultedArgs): void => { + logger.debug("forking vs code cli...") + const vscode = cp.fork(path.resolve(__dirname, "../../lib/vscode/out/vs/server/fork"), [], { + env: { + ...process.env, + CODE_SERVER_PARENT_PID: process.pid.toString(), + }, + }) + vscode.once("message", (message: any) => { + logger.debug("got message from VS Code", field("message", message)) + if (message.type !== "ready") { + logger.error("Unexpected response waiting for ready response", field("type", message.type)) + process.exit(1) + } + const send: CliMessage = { type: "cli", args } + vscode.send(send) + }) + vscode.once("error", (error) => { + logger.error("Got error from VS Code", field("error", error)) + process.exit(1) + }) + vscode.on("exit", (code) => process.exit(code || 0)) +} + +export const openInExistingInstance = async (args: DefaultedArgs, socketPath: string): Promise => { + const pipeArgs: OpenCommandPipeArgs & { fileURIs: string[] } = { + type: "open", + folderURIs: [], + fileURIs: [], + forceReuseWindow: args["reuse-window"], + forceNewWindow: args["new-window"], + } + + for (let i = 0; i < args._.length; i++) { + const fp = path.resolve(args._[i]) + if (await isFile(fp)) { + pipeArgs.fileURIs.push(fp) + } else { + pipeArgs.folderURIs.push(fp) + } + } + + if (pipeArgs.forceNewWindow && pipeArgs.fileURIs.length > 0) { + logger.error("--new-window can only be used with folder paths") + process.exit(1) + } + + if (pipeArgs.folderURIs.length === 0 && pipeArgs.fileURIs.length === 0) { + logger.error("Please specify at least one file or folder") + process.exit(1) + } + + const vscode = http.request( + { + path: "/", + method: "POST", + socketPath, + }, + (response) => { + response.on("data", (message) => { + logger.debug("got message from VS Code", field("message", message.toString())) + }) + }, + ) + vscode.on("error", (error: unknown) => { + logger.error("got error from VS Code", field("error", error)) + }) + vscode.write(JSON.stringify(pipeArgs)) + vscode.end() +} + +export const runCodeServer = async (args: DefaultedArgs): Promise => { + logger.info(`code-server ${version} ${commit}`) + + logger.info(`Using user-data-dir ${humanPath(args["user-data-dir"])}`) + logger.trace(`Using extensions-dir ${humanPath(args["extensions-dir"])}`) + + if (args.auth === AuthType.Password && !args.password && !args["hashed-password"]) { + throw new Error( + "Please pass in a password via the config file or environment variable ($PASSWORD or $HASHED_PASSWORD)", + ) + } + + const [app, wsApp, server] = await createApp(args) + const serverAddress = ensureAddress(server) + await register(app, wsApp, server, args) + + logger.info(`Using config file ${humanPath(args.config)}`) + logger.info(`HTTP server listening on ${serverAddress} ${args.link ? "(randomized by --link)" : ""}`) + if (args.auth === AuthType.Password) { + logger.info(" - Authentication is enabled") + if (args.usingEnvPassword) { + logger.info(" - Using password from $PASSWORD") + } else if (args.usingEnvHashedPassword) { + logger.info(" - Using password from $HASHED_PASSWORD") + } else { + logger.info(` - Using password from ${humanPath(args.config)}`) + } + } else { + logger.info(` - Authentication is disabled ${args.link ? "(disabled by --link)" : ""}`) + } + + if (args.cert) { + logger.info(` - Using certificate for HTTPS: ${humanPath(args.cert.value)}`) + } else { + logger.info(` - Not serving HTTPS ${args.link ? "(disabled by --link)" : ""}`) + } + + if (args["proxy-domain"].length > 0) { + logger.info(` - ${plural(args["proxy-domain"].length, "Proxying the following domain")}:`) + args["proxy-domain"].forEach((domain) => logger.info(` - *.${domain}`)) + } + + if (args.link) { + try { + await coderCloudBind(serverAddress.replace(/^https?:\/\//, ""), args.link.value) + logger.info(" - Connected to cloud agent") + } catch (err) { + logger.error(err.message) + wrapper.exit(1) + } + } + + if (args.enable && args.enable.length > 0) { + logger.info("Enabling the following experimental features:") + args.enable.forEach((feature) => { + if (Object.values(Feature).includes(feature as Feature)) { + logger.info(` - "${feature}"`) + } else { + logger.error(` X "${feature}" (unknown feature)`) + } + }) + // TODO: Could be nice to add wrapping to the logger? + logger.info( + " The code-server project does not provide stability guarantees or commit to fixing bugs relating to these experimental features. When filing bug reports, please ensure that you can reproduce the bug with all experimental features turned off.", + ) + } + + if (!args.socket && args.open) { + // The web socket doesn't seem to work if browsing with 0.0.0.0. + const openAddress = serverAddress.replace("://0.0.0.0", "://localhost") + try { + await open(openAddress) + logger.info(`Opened ${openAddress}`) + } catch (error) { + logger.error("Failed to open", field("address", openAddress), field("error", error)) + } + } +} From 20e70cfa053e5f3847ab7409e5cc9abd8f0c8187 Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 5 May 2021 11:56:19 -0500 Subject: [PATCH 4/5] Remove try from main All it does is log and exit which is what the caller will be doing on an error anyway (see entry). --- src/node/main.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/node/main.ts b/src/node/main.ts index 240831c20..1409a4409 100644 --- a/src/node/main.ts +++ b/src/node/main.ts @@ -10,7 +10,6 @@ import { coderCloudBind } from "./coder_cloud" import { commit, version } from "./constants" import { register } from "./routes" import { humanPath, isFile, open } from "./util" -import { wrapper } from "./wrapper" export const runVsCodeCli = (args: DefaultedArgs): void => { logger.debug("forking vs code cli...") @@ -126,13 +125,8 @@ export const runCodeServer = async (args: DefaultedArgs): Promise => { } if (args.link) { - try { - await coderCloudBind(serverAddress.replace(/^https?:\/\//, ""), args.link.value) - logger.info(" - Connected to cloud agent") - } catch (err) { - logger.error(err.message) - wrapper.exit(1) - } + await coderCloudBind(serverAddress.replace(/^https?:\/\//, ""), args.link.value) + logger.info(" - Connected to cloud agent") } if (args.enable && args.enable.length > 0) { From a882be574887367b378658535d2414e09e591ad5 Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 5 May 2021 12:20:38 -0500 Subject: [PATCH 5/5] Refactor integration tests to use main entry point --- src/node/entry.ts | 3 ++- src/node/main.ts | 4 +++- test/unit/health.test.ts | 4 ++-- test/unit/proxy.test.ts | 10 +++++----- test/utils/integration.ts | 16 +++++----------- 5 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/node/entry.ts b/src/node/entry.ts index 24a557e1c..4b186fefd 100644 --- a/src/node/entry.ts +++ b/src/node/entry.ts @@ -24,7 +24,8 @@ async function entry(): Promise { if (isChild(wrapper)) { const args = await wrapper.handshake() wrapper.preventExit() - return runCodeServer(args) + await runCodeServer(args) + return } const cliArgs = parse(process.argv.slice(2)) diff --git a/src/node/main.ts b/src/node/main.ts index 1409a4409..e00364135 100644 --- a/src/node/main.ts +++ b/src/node/main.ts @@ -82,7 +82,7 @@ export const openInExistingInstance = async (args: DefaultedArgs, socketPath: st vscode.end() } -export const runCodeServer = async (args: DefaultedArgs): Promise => { +export const runCodeServer = async (args: DefaultedArgs): Promise => { logger.info(`code-server ${version} ${commit}`) logger.info(`Using user-data-dir ${humanPath(args["user-data-dir"])}`) @@ -154,4 +154,6 @@ export const runCodeServer = async (args: DefaultedArgs): Promise => { logger.error("Failed to open", field("address", openAddress), field("error", error)) } } + + return server } diff --git a/test/unit/health.test.ts b/test/unit/health.test.ts index a8bdfb195..2c5fc0b75 100644 --- a/test/unit/health.test.ts +++ b/test/unit/health.test.ts @@ -12,7 +12,7 @@ describe("health", () => { }) it("/healthz", async () => { - ;[, , codeServer] = await integration.setup(["--auth=none"], "") + codeServer = await integration.setup(["--auth=none"], "") const resp = await codeServer.fetch("/healthz") expect(resp.status).toBe(200) const json = await resp.json() @@ -20,7 +20,7 @@ describe("health", () => { }) it("/healthz (websocket)", async () => { - ;[, , codeServer] = await integration.setup(["--auth=none"], "") + codeServer = await integration.setup(["--auth=none"], "") const ws = codeServer.ws("/healthz") const message = await new Promise((resolve, reject) => { ws.on("error", console.error) diff --git a/test/unit/proxy.test.ts b/test/unit/proxy.test.ts index c5969ebfd..a9c1554e6 100644 --- a/test/unit/proxy.test.ts +++ b/test/unit/proxy.test.ts @@ -37,7 +37,7 @@ describe("proxy", () => { e.get("/wsup", (req, res) => { res.json("asher is the best") }) - ;[, , codeServer] = await integration.setup(["--auth=none"], "") + codeServer = await integration.setup(["--auth=none"], "") const resp = await codeServer.fetch(proxyPath) expect(resp.status).toBe(200) const json = await resp.json() @@ -48,7 +48,7 @@ describe("proxy", () => { e.get(absProxyPath, (req, res) => { res.json("joe is the best") }) - ;[, , codeServer] = await integration.setup(["--auth=none"], "") + codeServer = await integration.setup(["--auth=none"], "") const resp = await codeServer.fetch(absProxyPath) expect(resp.status).toBe(200) const json = await resp.json() @@ -62,7 +62,7 @@ describe("proxy", () => { e.post("/finale", (req, res) => { res.json("redirect success") }) - ;[, , codeServer] = await integration.setup(["--auth=none"], "") + codeServer = await integration.setup(["--auth=none"], "") const resp = await codeServer.fetch(proxyPath, { method: "POST", }) @@ -78,7 +78,7 @@ describe("proxy", () => { e.post(finalePath, (req, res) => { res.json("redirect success") }) - ;[, , codeServer] = await integration.setup(["--auth=none"], "") + codeServer = await integration.setup(["--auth=none"], "") const resp = await codeServer.fetch(absProxyPath, { method: "POST", }) @@ -91,7 +91,7 @@ describe("proxy", () => { e.post("/wsup", (req, res) => { res.json(req.body) }) - ;[, , codeServer] = await integration.setup(["--auth=none"], "") + codeServer = await integration.setup(["--auth=none"], "") const resp = await codeServer.fetch(proxyPath, { method: "post", body: JSON.stringify("coder is the best"), diff --git a/test/utils/integration.ts b/test/utils/integration.ts index c5101d0fb..1ad7b44d9 100644 --- a/test/utils/integration.ts +++ b/test/utils/integration.ts @@ -1,21 +1,15 @@ -import * as express from "express" -import { createApp } from "../../src/node/app" -import { parse, setDefaults, parseConfigFile, DefaultedArgs } from "../../src/node/cli" -import { register } from "../../src/node/routes" +import { parse, parseConfigFile, setDefaults } from "../../src/node/cli" +import { runCodeServer } from "../../src/node/main" import * as httpserver from "./httpserver" -export async function setup( - argv: string[], - configFile?: string, -): Promise<[express.Application, express.Application, httpserver.HttpServer, DefaultedArgs]> { +export async function setup(argv: string[], configFile?: string): Promise { argv = ["--bind-addr=localhost:0", ...argv] const cliArgs = parse(argv) const configArgs = parseConfigFile(configFile || "", "test/integration.ts") const args = await setDefaults(cliArgs, configArgs) - const [app, wsApp, server] = await createApp(args) - await register(app, wsApp, server, args) + const server = await runCodeServer(args) - return [app, wsApp, new httpserver.HttpServer(server), args] + return new httpserver.HttpServer(server) }