Skip to content

Commit 705e821

Browse files
jsjoeioGirlBossRushcode-asher
authored
fix(testing): revert change & fix playwright tests (#4310)
* fix(testing): revert change & fix playwright tests * fix(constants): add type to import statement * refactor(e2e): delete browser test This test was originally added to ensure playwright was working. At this point, we know it works so removing this test because it doesn't help with anything specific to code-server and only adds unnecessary code to the codebase plus increases the e2e test job duration. * chore(e2e): use 1 worker for e2e test I don't know if it's a resources issue, playwright, or code-server but it seems like the e2e tests choke when multiple workers are used. This change is okay because our CI runner only has 2 cores so it would only use 1 worker anyway, but by specifying it in our playwright config, we ensure more stability in our e2e tests working correctly. See these PRs: - #3263 - #4310 * revert(vscode): add missing route with redirect * chore(vscode): update to latest fork * Touch up compilation step. * Bump vendor. * Fix VS Code minification step * Move ClientConfiguration to common Common code must not import Node code as it is imported by the browser. * Ensure lib directory exists before curling cURL errors now because VS Code was moved and the directory does not exist. * Update incorrect e2e test help output Revert workers change as well; this can be overridden when desired. * Add back extension compilation step * Include missing resources in release This includes a favicon, for example. I opted to include the entire directory to make sure we do not miss anything. Some of the other stuff looks potentially useful (like completions). * Set quality property in product configuration When httpWebWorkerExtensionHostIframe.html is fetched it uses the web endpoint template (in which we do not include the commit) but if the quality is not set it prepends the commit to the web endpoint instead. The new static endpoint does not use/handle commits so this 404s. Long-term we might want to make the new static endpoint use commits like the old one but we will also need to update the various other static URLs to include the commit. For now I just fixed this by adding the quality since: 1. Probably faster than trying to find and update all static uses. 2. VS Code probably expects it anyway. 3. Gives us better control over the endpoint. * Update VS Code This fixes several build issues. * Bump vscode. * Bump. * Bump. * Use CLI directly. * Update tests to reflect new upstream behavior. * Move unit tests to after the build Our code has new dependencies on VS Code that are pulled in when the unit tests run. Because of this we need to build VS Code before running the unit tests (as it only pulls built code). * Upgrade proxy-agent dependencies This resolves a security report with one of its dependencies (vm2). * Symlink VS Code output directory before unit tests This is necessary now that we import from the out directory. * Fix issues surrounding persistent processes between tests. * Update VS Code cache directories These were renamed so the cached paths need to be updated. I changed the key as well to force a rebuild. * Move test symlink to script This way it works for local testing as well. I had to use out-build instead of out-vscode-server-min because Jest throws some obscure error about a handlebars haste map. * Fix listening on a socket * Update VS Code It contains fixes for missing files in the build. * Standardize disposals * Dispose HTTP server Shares code with the test HTTP server. For now it is a function but maybe we should make it a class that is extended by tests. * Dispose app on exit * Fix logging link errors Unfortunately the logger currently chokes when provided with error objects. Also for some reason the bracketed text was not displaying... * Update regex used by e2e to extract address The address was recently changed to use URL which seems to add a trailing slash when using toString, causing the regex match to fail. * Log browser console in e2e tests * Add base back to login page This is used to set cookies when using a base path. * Remove login page test The file this was testing no longer exists. * Use path.posix for static base Since this is a web path and not platform-dependent. * Add test for invalid password Co-authored-by: Teffen Ellis <[email protected]> Co-authored-by: Asher <[email protected]>
1 parent 0e97a94 commit 705e821

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1534
-1974
lines changed

.github/workflows/ci.yaml

+16-13
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ jobs:
1919
name: Pre-build checks
2020
runs-on: ubuntu-latest
2121
timeout-minutes: 15
22-
env:
23-
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
2422
steps:
2523
- name: Checkout repo
2624
uses: actions/checkout@v2
@@ -54,14 +52,6 @@ jobs:
5452
run: yarn lint
5553
if: success()
5654

57-
- name: Run code-server unit tests
58-
run: yarn test:unit
59-
if: success()
60-
61-
- name: Upload coverage report to Codecov
62-
run: yarn coverage
63-
if: success()
64-
6555
audit-ci:
6656
name: Run audit-ci
6757
needs: prebuild
@@ -98,6 +88,8 @@ jobs:
9888
needs: prebuild
9989
runs-on: ubuntu-latest
10090
timeout-minutes: 30
91+
env:
92+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
10193
steps:
10294
- uses: actions/checkout@v2
10395
with:
@@ -146,14 +138,25 @@ jobs:
146138
path: |
147139
vendor/modules/code-oss-dev/.build
148140
vendor/modules/code-oss-dev/out-build
149-
vendor/modules/code-oss-dev/out-vscode
150-
vendor/modules/code-oss-dev/out-vscode-min
151-
key: vscode-build-${{ steps.vscode-rev.outputs.rev }}
141+
vendor/modules/code-oss-dev/out-vscode-server
142+
vendor/modules/code-oss-dev/out-vscode-server-min
143+
key: vscode-server-build-${{ steps.vscode-rev.outputs.rev }}
152144

153145
- name: Build vscode
154146
if: steps.cache-vscode.outputs.cache-hit != 'true'
155147
run: yarn build:vscode
156148

149+
# Our code imports code from VS Code's `out` directory meaning VS Code
150+
# must be built before running these tests.
151+
# TODO: Move to its own step?
152+
- name: Run code-server unit tests
153+
run: yarn test:unit
154+
if: success()
155+
156+
- name: Upload coverage report to Codecov
157+
run: yarn coverage
158+
if: success()
159+
157160
# The release package does not contain any native modules
158161
# and is neutral to architecture/os/libc version.
159162
- name: Create release package

ci/build/build-code-server.sh

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ main() {
2020
source ./ci/lib.sh
2121
OS="$(uname | tr '[:upper:]' '[:lower:]')"
2222

23+
mkdir -p ./lib
24+
2325
if ! [ -f ./lib/coder-cloud-agent ]; then
2426
echo "Downloading the cloud agent..."
2527

ci/build/build-release.sh

+4-4
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ EOF
6868
bundle_vscode() {
6969
mkdir -p "$VSCODE_OUT_PATH"
7070
rsync "$VSCODE_SRC_PATH/yarn.lock" "$VSCODE_OUT_PATH"
71-
rsync "$VSCODE_SRC_PATH/out-vscode${MINIFY:+-min}/" "$VSCODE_OUT_PATH/out"
71+
rsync "$VSCODE_SRC_PATH/out-vscode-server${MINIFY:+-min}/" "$VSCODE_OUT_PATH/out"
7272

7373
rsync "$VSCODE_SRC_PATH/.build/extensions/" "$VSCODE_OUT_PATH/extensions"
7474
if [ "$KEEP_MODULES" = 0 ]; then
@@ -80,9 +80,8 @@ bundle_vscode() {
8080
rsync "$VSCODE_SRC_PATH/extensions/yarn.lock" "$VSCODE_OUT_PATH/extensions"
8181
rsync "$VSCODE_SRC_PATH/extensions/postinstall.js" "$VSCODE_OUT_PATH/extensions"
8282

83-
mkdir -p "$VSCODE_OUT_PATH/resources/"{linux,web}
84-
rsync "$VSCODE_SRC_PATH/resources/linux/" "$VSCODE_OUT_PATH/resources/linux/"
85-
rsync "$VSCODE_SRC_PATH/resources/web/" "$VSCODE_OUT_PATH/resources/web/"
83+
mkdir -p "$VSCODE_OUT_PATH/resources/"
84+
rsync "$VSCODE_SRC_PATH/resources/" "$VSCODE_OUT_PATH/resources/"
8685

8786
# Add the commit and date and enable telemetry. This just makes telemetry
8887
# available; telemetry can still be disabled by flag or setting.
@@ -91,6 +90,7 @@ bundle_vscode() {
9190
{
9291
"enableTelemetry": true,
9392
"commit": "$(git rev-parse HEAD)",
93+
"quality": "stable",
9494
"date": $(jq -n 'now | todate')
9595
}
9696
EOF

ci/build/build-vscode.sh

+3-7
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,9 @@ main() {
1111

1212
cd vendor/modules/code-oss-dev
1313

14-
yarn gulp compile-build compile-extensions-build compile-extension-media compile-web
15-
16-
yarn gulp optimize --gulpfile ./coder.js
17-
18-
if [[ $MINIFY ]]; then
19-
yarn gulp minify --gulpfile ./coder.js
20-
fi
14+
# extensions-ci compiles extensions and includes their media.
15+
# compile-web compiles web extensions. TODO: Unsure if used.
16+
yarn gulp extensions-ci compile-web "vscode-server${MINIFY:+-min}"
2117
}
2218

2319
main "$@"

ci/build/npm-postinstall.sh

+3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ main() {
5757
esac
5858

5959
OS="$(uname | tr '[:upper:]' '[:lower:]')"
60+
61+
mkdir -p ./lib
62+
6063
if curl -fsSL "https://github.com/cdr/cloud-agent/releases/latest/download/cloud-agent-$OS-$ARCH" -o ./lib/coder-cloud-agent; then
6164
chmod +x ./lib/coder-cloud-agent
6265
else

ci/dev/test-e2e.sh

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
33

4+
help() {
5+
echo >&2 " You can build with 'yarn watch' or you can build a release"
6+
echo >&2 " For example: 'yarn build && yarn build:vscode && KEEP_MODULES=1 yarn release'"
7+
echo >&2 " Then 'CODE_SERVER_TEST_ENTRY=./release yarn test:e2e'"
8+
echo >&2 " You can manually run that release with 'node ./release'"
9+
}
10+
411
main() {
512
cd "$(dirname "$0")/../.."
613

@@ -21,13 +28,13 @@ main() {
2128
# wrong (native modules version issues, incomplete build, etc).
2229
if [[ ! -d $dir/out ]]; then
2330
echo >&2 "No code-server build detected"
24-
echo >&2 "You can build it with 'yarn build' or 'yarn watch'"
31+
help
2532
exit 1
2633
fi
2734

2835
if [[ ! -d $dir/vendor/modules/code-oss-dev/out ]]; then
2936
echo >&2 "No VS Code build detected"
30-
echo >&2 "You can build it with 'yarn build:vscode' or 'yarn watch'"
37+
help
3138
exit 1
3239
fi
3340

ci/dev/test-unit.sh

+16-2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,26 @@ set -euo pipefail
33

44
main() {
55
cd "$(dirname "$0")/../.."
6-
cd test/unit/node/test-plugin
6+
7+
source ./ci/lib.sh
8+
9+
pushd test/unit/node/test-plugin
710
make -s out/index.js
11+
popd
12+
13+
# Our code imports from `out` in order to work during development but if you
14+
# have only built for production you will have not have this directory. In
15+
# that case symlink `out` to a production build directory.
16+
local vscode="vendor/modules/code-oss-dev"
17+
local link="$vscode/out"
18+
local target="out-build"
19+
if [[ ! -e $link ]] && [[ -d $vscode/$target ]]; then
20+
ln -s "$target" "$link"
21+
fi
22+
823
# We must keep jest in a sub-directory. See ../../test/package.json for more
924
# information. We must also run it from the root otherwise coverage will not
1025
# include our source files.
11-
cd "$OLDPWD"
1226
CS_DISABLE_PLUGINS=true ./test/node_modules/.bin/jest "$@"
1327
}
1428

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"release:prep": "./ci/build/release-prep.sh",
2020
"test:e2e": "./ci/dev/test-e2e.sh",
2121
"test:standalone-release": "./ci/build/test-standalone-release.sh",
22-
"test:unit": "./ci/dev/test-unit.sh",
22+
"test:unit": "./ci/dev/test-unit.sh --forceExit --detectOpenHandles",
2323
"test:scripts": "./ci/dev/test-scripts.sh",
2424
"package": "./ci/build/build-packages.sh",
2525
"postinstall": "./ci/dev/postinstall.sh",

src/browser/pages/login.html

+9
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ <h1 class="main">Welcome to code-server</h1>
3030
<div class="content">
3131
<form class="login-form" method="post">
3232
<input class="user" type="text" autocomplete="username" />
33+
<input id="base" type="hidden" name="base" value="/" />
3334
<div class="field">
3435
<input
3536
required
@@ -47,5 +48,13 @@ <h1 class="main">Welcome to code-server</h1>
4748
</div>
4849
</div>
4950
</div>
51+
<script>
52+
// Inform the backend about the path since the proxy might have rewritten
53+
// it out of the headers and cookies must be set with absolute paths.
54+
const el = document.getElementById("base")
55+
if (el) {
56+
el.value = window.location.pathname
57+
}
58+
</script>
5059
</body>
5160
</html>

src/common/emitter.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { logger } from "@coder/logger"
77
export type Callback<T, R = void | Promise<void>> = (t: T, p: Promise<void>) => R
88

99
export interface Disposable {
10-
dispose(): void
10+
dispose(): void | Promise<void>
1111
}
1212

1313
export interface Event<T> {

src/common/util.ts

+1-30
Original file line numberDiff line numberDiff line change
@@ -50,35 +50,6 @@ export const resolveBase = (base?: string): string => {
5050
return normalize(url.pathname)
5151
}
5252

53-
/**
54-
* Get client-side configuration embedded in the HTML or query params.
55-
*/
56-
export const getClientConfiguration = <T extends CodeServerLib.ClientConfiguration>(): T => {
57-
let config: T
58-
try {
59-
config = JSON.parse(document.getElementById("coder-options")!.getAttribute("data-settings")!)
60-
} catch (error) {
61-
config = {} as T
62-
}
63-
64-
// You can also pass options in stringified form to the options query
65-
// variable. Options provided here will override the ones in the options
66-
// element.
67-
const params = new URLSearchParams(location.search)
68-
const queryOpts = params.get("options")
69-
if (queryOpts) {
70-
config = {
71-
...config,
72-
...JSON.parse(queryOpts),
73-
}
74-
}
75-
76-
config.base = resolveBase(config.base)
77-
config.csStaticBase = resolveBase(config.csStaticBase)
78-
79-
return config
80-
}
81-
8253
/**
8354
* Wrap the value in an array if it's not already an array. If the value is
8455
* undefined return an empty array.
@@ -94,7 +65,7 @@ export const arrayify = <T>(value?: T | T[]): T[] => {
9465
}
9566

9667
// TODO: Might make sense to add Error handling to the logger itself.
97-
export function logError(logger: { error: (msg: string) => void }, prefix: string, err: Error | string): void {
68+
export function logError(logger: { error: (msg: string) => void }, prefix: string, err: unknown): void {
9869
if (err instanceof Error) {
9970
logger.error(`${prefix}: ${err.message} ${err.stack}`)
10071
} else {

src/node/app.ts

+30-12
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,24 @@ import express, { Express } from "express"
44
import { promises as fs } from "fs"
55
import http from "http"
66
import * as httpolyglot from "httpolyglot"
7+
import { Disposable } from "../common/emitter"
78
import * as util from "../common/util"
89
import { DefaultedArgs } from "./cli"
10+
import { disposer } from "./http"
911
import { isNodeJSErrnoException } from "./util"
1012
import { handleUpgrade } from "./wsRouter"
1113

1214
type ListenOptions = Pick<DefaultedArgs, "socket" | "port" | "host">
1315

16+
export interface App extends Disposable {
17+
/** Handles regular HTTP requests. */
18+
router: Express
19+
/** Handles websocket requests. */
20+
wsRouter: Express
21+
/** The underlying HTTP server. */
22+
server: http.Server
23+
}
24+
1425
const listen = (server: http.Server, { host, port, socket }: ListenOptions) => {
1526
return new Promise<void>(async (resolve, reject) => {
1627
server.on("error", reject)
@@ -41,41 +52,48 @@ const listen = (server: http.Server, { host, port, socket }: ListenOptions) => {
4152
/**
4253
* Create an Express app and an HTTP/S server to serve it.
4354
*/
44-
export const createApp = async (args: DefaultedArgs): Promise<[Express, Express, http.Server]> => {
45-
const app = express()
46-
47-
app.use(compression())
55+
export const createApp = async (args: DefaultedArgs): Promise<App> => {
56+
const router = express()
57+
router.use(compression())
4858

4959
const server = args.cert
5060
? httpolyglot.createServer(
5161
{
5262
cert: args.cert && (await fs.readFile(args.cert.value)),
5363
key: args["cert-key"] && (await fs.readFile(args["cert-key"])),
5464
},
55-
app,
65+
router,
5666
)
57-
: http.createServer(app)
67+
: http.createServer(router)
68+
69+
const dispose = disposer(server)
5870

5971
await listen(server, args)
6072

61-
const wsApp = express()
62-
handleUpgrade(wsApp, server)
73+
const wsRouter = express()
74+
handleUpgrade(wsRouter, server)
6375

64-
return [app, wsApp, server]
76+
return { router, wsRouter, server, dispose }
6577
}
6678

6779
/**
6880
* Get the address of a server as a string (protocol *is* included) while
6981
* ensuring there is one (will throw if there isn't).
82+
*
83+
* The address might be a URL or it might be a pipe or socket path.
7084
*/
71-
export const ensureAddress = (server: http.Server): string => {
85+
export const ensureAddress = (server: http.Server, protocol: string): URL | string => {
7286
const addr = server.address()
87+
7388
if (!addr) {
74-
throw new Error("server has no address")
89+
throw new Error("Server has no address")
7590
}
91+
7692
if (typeof addr !== "string") {
77-
return `http://${addr.address}:${addr.port}`
93+
return new URL(`${protocol}://${addr.address}:${addr.port}`)
7894
}
95+
96+
// If this is a string then it is a pipe or Unix socket.
7997
return addr
8098
}
8199

0 commit comments

Comments
 (0)