mirror of https://github.com/coder/code-server.git
fix: wrap socket in proxy before passing to vscode (#4840)
* chore: add ipc hook to e2e script * refactor: allow codeServerArgs in e2e tests * feat: add --cert e2e extension test * fix: wrap websocket in proxy * fixup: remvoe ignoreHTTPSErrors * fixup: make codeServerArgs readonly * fixup! add back ignoreHTTPSErrors
This commit is contained in:
parent
b26cce589f
commit
e3e9f052c4
|
@ -17,7 +17,7 @@
|
||||||
"release:github-draft": "./ci/build/release-github-draft.sh",
|
"release:github-draft": "./ci/build/release-github-draft.sh",
|
||||||
"release:github-assets": "./ci/build/release-github-assets.sh",
|
"release:github-assets": "./ci/build/release-github-assets.sh",
|
||||||
"release:prep": "./ci/build/release-prep.sh",
|
"release:prep": "./ci/build/release-prep.sh",
|
||||||
"test:e2e": "./ci/dev/test-e2e.sh",
|
"test:e2e": "VSCODE_IPC_HOOK_CLI= ./ci/dev/test-e2e.sh",
|
||||||
"test:standalone-release": "./ci/build/test-standalone-release.sh",
|
"test:standalone-release": "./ci/build/test-standalone-release.sh",
|
||||||
"test:unit": "./ci/dev/test-unit.sh --forceExit --detectOpenHandles",
|
"test:unit": "./ci/dev/test-unit.sh --forceExit --detectOpenHandles",
|
||||||
"test:scripts": "./ci/dev/test-scripts.sh",
|
"test:scripts": "./ci/dev/test-scripts.sh",
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { logError } from "../../common/util"
|
||||||
import { toVsCodeArgs } from "../cli"
|
import { toVsCodeArgs } from "../cli"
|
||||||
import { isDevMode } from "../constants"
|
import { isDevMode } from "../constants"
|
||||||
import { authenticated, ensureAuthenticated, redirect, self } from "../http"
|
import { authenticated, ensureAuthenticated, redirect, self } from "../http"
|
||||||
|
import { SocketProxyProvider } from "../socket"
|
||||||
import { loadAMDModule } from "../util"
|
import { loadAMDModule } from "../util"
|
||||||
import { Router as WsRouter } from "../wsRouter"
|
import { Router as WsRouter } from "../wsRouter"
|
||||||
import { errorHandler } from "./errors"
|
import { errorHandler } from "./errors"
|
||||||
|
@ -13,6 +14,7 @@ export class CodeServerRouteWrapper {
|
||||||
/** Assigned in `ensureCodeServerLoaded` */
|
/** Assigned in `ensureCodeServerLoaded` */
|
||||||
private _codeServerMain!: CodeServerLib.IServerAPI
|
private _codeServerMain!: CodeServerLib.IServerAPI
|
||||||
private _wsRouterWrapper = WsRouter()
|
private _wsRouterWrapper = WsRouter()
|
||||||
|
private _socketProxyProvider = new SocketProxyProvider()
|
||||||
public router = express.Router()
|
public router = express.Router()
|
||||||
|
|
||||||
public get wsRouter() {
|
public get wsRouter() {
|
||||||
|
@ -77,9 +79,10 @@ export class CodeServerRouteWrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private $proxyWebsocket = async (req: WebsocketRequest) => {
|
private $proxyWebsocket = async (req: WebsocketRequest) => {
|
||||||
this._codeServerMain.handleUpgrade(req, req.socket)
|
const wrappedSocket = await this._socketProxyProvider.createProxy(req.ws)
|
||||||
|
this._codeServerMain.handleUpgrade(req, wrappedSocket)
|
||||||
|
|
||||||
req.socket.resume()
|
req.ws.resume()
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
@ -130,5 +133,6 @@ export class CodeServerRouteWrapper {
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
this._codeServerMain?.dispose()
|
this._codeServerMain?.dispose()
|
||||||
|
this._socketProxyProvider.stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,15 @@ import { CodeServer, CodeServerPage } from "./models/CodeServer"
|
||||||
*
|
*
|
||||||
* If `includeCredentials` is `true` page requests will be authenticated.
|
* If `includeCredentials` is `true` page requests will be authenticated.
|
||||||
*/
|
*/
|
||||||
export const describe = (name: string, includeCredentials: boolean, fn: (codeServer: CodeServer) => void) => {
|
export const describe = (
|
||||||
|
name: string,
|
||||||
|
includeCredentials: boolean,
|
||||||
|
codeServerArgs: string[],
|
||||||
|
fn: (codeServer: CodeServer) => void,
|
||||||
|
) => {
|
||||||
test.describe(name, () => {
|
test.describe(name, () => {
|
||||||
// This will spawn on demand so nothing is necessary on before.
|
// This will spawn on demand so nothing is necessary on before.
|
||||||
const codeServer = new CodeServer(name)
|
const codeServer = new CodeServer(name, codeServerArgs)
|
||||||
|
|
||||||
// Kill code-server after the suite has ended. This may happen even without
|
// Kill code-server after the suite has ended. This may happen even without
|
||||||
// doing it explicitly but it seems prudent to be sure.
|
// doing it explicitly but it seems prudent to be sure.
|
||||||
|
@ -36,6 +41,9 @@ export const describe = (name: string, includeCredentials: boolean, fn: (codeSer
|
||||||
authenticated: includeCredentials,
|
authenticated: includeCredentials,
|
||||||
// This provides a cookie that authenticates with code-server.
|
// This provides a cookie that authenticates with code-server.
|
||||||
storageState: includeCredentials ? storageState : {},
|
storageState: includeCredentials ? storageState : {},
|
||||||
|
// NOTE@jsjoeio some tests use --cert which uses a self-signed certificate
|
||||||
|
// without this option, those tests will fail.
|
||||||
|
ignoreHTTPSErrors: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
fn(codeServer)
|
fn(codeServer)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { describe, test, expect } from "./baseFixture"
|
import { describe, test, expect } from "./baseFixture"
|
||||||
|
|
||||||
describe("CodeServer", true, () => {
|
describe("CodeServer", true, [], () => {
|
||||||
test("should navigate to home page", async ({ codeServerPage }) => {
|
test("should navigate to home page", async ({ codeServerPage }) => {
|
||||||
// We navigate codeServer before each test
|
// We navigate codeServer before each test
|
||||||
// and we start the test with a storage state
|
// and we start the test with a storage state
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { describe, test } from "./baseFixture"
|
import { describe, test } from "./baseFixture"
|
||||||
|
|
||||||
describe("Extensions", true, () => {
|
function runTestExtensionTests() {
|
||||||
// This will only work if the test extension is loaded into code-server.
|
// This will only work if the test extension is loaded into code-server.
|
||||||
test("should have access to VSCODE_PROXY_URI", async ({ codeServerPage }) => {
|
test("should have access to VSCODE_PROXY_URI", async ({ codeServerPage }) => {
|
||||||
const address = await codeServerPage.address()
|
const address = await codeServerPage.address()
|
||||||
|
@ -9,4 +9,12 @@ describe("Extensions", true, () => {
|
||||||
|
|
||||||
await codeServerPage.page.waitForSelector(`text=${address}/proxy/{{port}}`)
|
await codeServerPage.page.waitForSelector(`text=${address}/proxy/{{port}}`)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("Extensions", true, [], () => {
|
||||||
|
runTestExtensionTests()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("Extensions with --cert", true, ["--cert"], () => {
|
||||||
|
runTestExtensionTests()
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { describe, test, expect } from "./baseFixture"
|
||||||
|
|
||||||
// This test is to make sure the globalSetup works as expected
|
// This test is to make sure the globalSetup works as expected
|
||||||
// meaning globalSetup ran and stored the storageState
|
// meaning globalSetup ran and stored the storageState
|
||||||
describe("globalSetup", true, () => {
|
describe("globalSetup", true, [], () => {
|
||||||
test("should keep us logged in using the storageState", async ({ codeServerPage }) => {
|
test("should keep us logged in using the storageState", async ({ codeServerPage }) => {
|
||||||
// Make sure the editor actually loaded
|
// Make sure the editor actually loaded
|
||||||
expect(await codeServerPage.isEditorVisible()).toBe(true)
|
expect(await codeServerPage.isEditorVisible()).toBe(true)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { PASSWORD } from "../utils/constants"
|
import { PASSWORD } from "../utils/constants"
|
||||||
import { describe, test, expect } from "./baseFixture"
|
import { describe, test, expect } from "./baseFixture"
|
||||||
|
|
||||||
describe("login", false, () => {
|
describe("login", false, [], () => {
|
||||||
test("should see the login page", async ({ codeServerPage }) => {
|
test("should see the login page", async ({ codeServerPage }) => {
|
||||||
// It should send us to the login page
|
// It should send us to the login page
|
||||||
expect(await codeServerPage.page.title()).toBe("code-server login")
|
expect(await codeServerPage.page.title()).toBe("code-server login")
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// NOTE@jsjoeio commenting out until we can figure out what's wrong
|
// NOTE@jsjoeio commenting out until we can figure out what's wrong
|
||||||
// import { describe, test, expect } from "./baseFixture"
|
// import { describe, test, expect } from "./baseFixture"
|
||||||
|
|
||||||
// describe("logout", true, () => {
|
// describe("logout", true, [], () => {
|
||||||
// test("should be able logout", async ({ codeServerPage }) => {
|
// test("should be able logout", async ({ codeServerPage }) => {
|
||||||
// // Recommended by Playwright for async navigation
|
// // Recommended by Playwright for async navigation
|
||||||
// // https://github.com/microsoft/playwright/issues/1987#issuecomment-620182151
|
// // https://github.com/microsoft/playwright/issues/1987#issuecomment-620182151
|
||||||
|
|
|
@ -31,7 +31,7 @@ export class CodeServer {
|
||||||
public readonly logger: Logger
|
public readonly logger: Logger
|
||||||
private closed = false
|
private closed = false
|
||||||
|
|
||||||
constructor(name: string) {
|
constructor(name: string, private readonly codeServerArgs: string[]) {
|
||||||
this.logger = logger.named(name)
|
this.logger = logger.named(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +78,7 @@ export class CodeServer {
|
||||||
"node",
|
"node",
|
||||||
[
|
[
|
||||||
process.env.CODE_SERVER_TEST_ENTRY || ".",
|
process.env.CODE_SERVER_TEST_ENTRY || ".",
|
||||||
|
...this.codeServerArgs,
|
||||||
// Using port zero will spawn on a random port.
|
// Using port zero will spawn on a random port.
|
||||||
"--bind-addr",
|
"--bind-addr",
|
||||||
"127.0.0.1:0",
|
"127.0.0.1:0",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { describe, test, expect } from "./baseFixture"
|
import { describe, test, expect } from "./baseFixture"
|
||||||
|
|
||||||
describe("Open Help > About", true, () => {
|
describe("Open Help > About", true, [], () => {
|
||||||
test("should see code-server version in about dialog", async ({ codeServerPage }) => {
|
test("should see code-server version in about dialog", async ({ codeServerPage }) => {
|
||||||
// Open using the menu.
|
// Open using the menu.
|
||||||
await codeServerPage.navigateMenus(["Help", "About"])
|
await codeServerPage.navigateMenus(["Help", "About"])
|
||||||
|
|
|
@ -4,7 +4,7 @@ import util from "util"
|
||||||
import { clean, tmpdir } from "../utils/helpers"
|
import { clean, tmpdir } from "../utils/helpers"
|
||||||
import { describe, expect, test } from "./baseFixture"
|
import { describe, expect, test } from "./baseFixture"
|
||||||
|
|
||||||
describe("Integrated Terminal", true, () => {
|
describe("Integrated Terminal", true, [], () => {
|
||||||
const testName = "integrated-terminal"
|
const testName = "integrated-terminal"
|
||||||
test.beforeAll(async () => {
|
test.beforeAll(async () => {
|
||||||
await clean(testName)
|
await clean(testName)
|
||||||
|
|
Loading…
Reference in New Issue