@@ -15,39 +15,11 @@ import {
1515} from "node:fs" ;
1616import { tmpdir } from "node:os" ;
1717import { join } from "node:path" ;
18+ import { gzipSync } from "node:zlib" ;
1819import { afterEach , beforeEach , describe , expect , test } from "vitest" ;
1920
2021const installScript = join ( import . meta. dirname , ".." , ".." , "install" ) ;
21-
22- describe ( "install script" , ( ) => {
23- let testDir : string ;
24- let binDir : string ;
25- let installDir : string ;
26- let env : NodeJS . ProcessEnv ;
27-
28- beforeEach ( ( ) => {
29- testDir = mkdtempSync ( join ( tmpdir ( ) , "sentry-install-test-" ) ) ;
30- binDir = join ( testDir , "bin" ) ;
31- installDir = join ( testDir , "installed bin" ) ;
32- mkdirSync ( binDir , { recursive : true } ) ;
33- mkdirSync ( join ( testDir , "home" ) ) ;
34- env = {
35- PATH : `${ binDir } :/usr/bin:/bin:/usr/sbin:/sbin` ,
36- HOME : join ( testDir , "home" ) ,
37- SENTRY_INSTALL_DIR : installDir ,
38- SENTRY_CLI_NO_TELEMETRY : "1" ,
39- SENTRY_TEST_DIR : testDir ,
40- SENTRY_TEST_INSTALL_SCRIPT : installScript ,
41- TMPDIR : testDir ,
42- } ;
43-
44- // The artifact records each invocation and emulates setup's binary copy and
45- // POSIX cleanup. Every install location and output is inside the fixture.
46- writeFileSync (
47- join ( binDir , "curl" ) ,
48- `#!/usr/bin/env bash
49- cat <<'SCRIPT'
50- #!/usr/bin/env bash
22+ const downloadedExecutable = `#!/usr/bin/env bash
5123set -euo pipefail
5224record_tty() {
5325 for fd in 0 1 2; do
@@ -76,7 +48,35 @@ printf '%s\\n' "$@" >> "$SENTRY_TEST_DIR/post-args"
7648printf '%s\\n' "$0" >> "$SENTRY_TEST_DIR/post-binary"
7749record_tty 3> "$SENTRY_TEST_DIR/post-tty"
7850exit "\${SENTRY_TEST_POST_EXIT:-0}"
79- SCRIPT
51+ ` ;
52+
53+ describe ( "install script" , ( ) => {
54+ let testDir : string ;
55+ let binDir : string ;
56+ let installDir : string ;
57+ let env : NodeJS . ProcessEnv ;
58+
59+ beforeEach ( ( ) => {
60+ testDir = mkdtempSync ( join ( tmpdir ( ) , "sentry-install-test-" ) ) ;
61+ binDir = join ( testDir , "bin" ) ;
62+ installDir = join ( testDir , "installed bin" ) ;
63+ mkdirSync ( binDir , { recursive : true } ) ;
64+ mkdirSync ( join ( testDir , "home" ) ) ;
65+ env = {
66+ PATH : `${ binDir } :/usr/bin:/bin:/usr/sbin:/sbin` ,
67+ HOME : join ( testDir , "home" ) ,
68+ SENTRY_INSTALL_DIR : installDir ,
69+ SENTRY_CLI_NO_TELEMETRY : "1" ,
70+ SENTRY_TEST_DIR : testDir ,
71+ SENTRY_TEST_INSTALL_SCRIPT : installScript ,
72+ TMPDIR : testDir ,
73+ } ;
74+
75+ writeFileSync (
76+ join ( binDir , "curl" ) ,
77+ `#!/usr/bin/env bash
78+ cat <<'SCRIPT'
79+ ${ downloadedExecutable } SCRIPT
8080`
8181 ) ;
8282 chmodSync ( join ( binDir , "curl" ) , 0o755 ) ;
@@ -95,6 +95,87 @@ SCRIPT
9595 : [ ] ;
9696 }
9797
98+ function configureNightlyDownload ( redirect : boolean ) : void {
99+ const platform = process . platform === "darwin" ? "darwin" : "linux" ;
100+ const architecture = process . arch === "arm64" ? "arm64" : "x64" ;
101+ const assetName = `sentry-${ platform } -${ architecture } .gz` ;
102+ const gzipPath = join ( testDir , assetName ) ;
103+ const manifest = JSON . stringify ( {
104+ version : "nightly-test" ,
105+ layers : [
106+ {
107+ mediaType : "application/vnd.oci.image.layer.v1.tar" ,
108+ digest : "sha256:test" ,
109+ annotations : { "org.opencontainers.image.title" : assetName } ,
110+ } ,
111+ ] ,
112+ } ) ;
113+
114+ writeFileSync ( gzipPath , gzipSync ( downloadedExecutable ) ) ;
115+ env . SENTRY_TEST_GZIP = gzipPath ;
116+ env . SENTRY_TEST_NIGHTLY_REDIRECT = redirect ? "1" : "0" ;
117+ writeFileSync (
118+ join ( binDir , "curl" ) ,
119+ `#!/usr/bin/env bash
120+ set -euo pipefail
121+ url="\${!#}"
122+ case "$url" in
123+ *"/token?"*)
124+ printf '{"token":"test-token"}'
125+ ;;
126+ *"/manifests/nightly")
127+ cat <<'JSON'
128+ ${ manifest }
129+ JSON
130+ ;;
131+ "https://objects.example/nightly.gz")
132+ for arg in "$@"; do
133+ if [[ "$arg" == Authorization:* ]]; then
134+ exit 90
135+ fi
136+ done
137+ cat "$SENTRY_TEST_GZIP"
138+ ;;
139+ *"/blobs/"*)
140+ headers=""
141+ output=""
142+ while [[ $# -gt 0 ]]; do
143+ case "$1" in
144+ -D) headers="$2"; shift 2 ;;
145+ -o) output="$2"; shift 2 ;;
146+ *) shift ;;
147+ esac
148+ done
149+ if [[ "$SENTRY_TEST_NIGHTLY_REDIRECT" == "1" ]]; then
150+ printf 'HTTP/1.1 307 Temporary Redirect\\r\\nLocation: https://objects.example/nightly.gz\\r\\n\\r\\n' > "$headers"
151+ : > "$output"
152+ printf '307'
153+ else
154+ printf 'HTTP/1.1 200 OK\\r\\n\\r\\n' > "$headers"
155+ cp "$SENTRY_TEST_GZIP" "$output"
156+ printf '200'
157+ fi
158+ ;;
159+ *)
160+ exit 91
161+ ;;
162+ esac
163+ `
164+ ) ;
165+ chmodSync ( join ( binDir , "curl" ) , 0o755 ) ;
166+ writeFileSync (
167+ join ( binDir , "gunzip" ) ,
168+ `#!/usr/bin/env bash
169+ set -euo pipefail
170+ if [[ $# -gt 0 && "$1" != "-c" ]]; then
171+ exit 64
172+ fi
173+ exec /usr/bin/gunzip "$@"
174+ `
175+ ) ;
176+ chmodSync ( join ( binDir , "gunzip" ) , 0o755 ) ;
177+ }
178+
98179 /** Run curl-style piped installation in a real controlling terminal. */
99180 function runInTerminal (
100181 options : { redirect ?: string ; detached ?: boolean } = { }
@@ -171,6 +252,31 @@ process.exitCode = result.status ?? 1;
171252 expect ( existsSync ( join ( installDir , "sentry" ) ) ) . toBe ( true ) ;
172253 } ) ;
173254
255+ test . each ( [
256+ { response : "direct HTTP 200 response" , redirect : false } ,
257+ { response : "HTTP redirect" , redirect : true } ,
258+ ] ) ( "installs nightly from a $response" , ( { redirect } ) => {
259+ configureNightlyDownload ( redirect ) ;
260+ const result = spawnSync (
261+ "bash" ,
262+ [ installScript , "--version" , "nightly" , "--no-modify-path" ] ,
263+ { env, encoding : "utf8" , timeout : 10_000 }
264+ ) ;
265+
266+ expect ( result . status , result . stdout + result . stderr ) . toBe ( 0 ) ;
267+ expect ( recorded ( "setup-args" ) ) . toEqual ( [
268+ "cli" ,
269+ "setup" ,
270+ "--install" ,
271+ "--method" ,
272+ "curl" ,
273+ "--channel" ,
274+ "nightly" ,
275+ "--no-modify-path" ,
276+ ] ) ;
277+ expect ( existsSync ( join ( installDir , "sentry" ) ) ) . toBe ( true ) ;
278+ } ) ;
279+
174280 test ( "connects setup to the controlling terminal without launching another process" , ( ) => {
175281 const result = runInTerminal ( ) ;
176282 expect ( result . status , result . stdout + result . stderr ) . toBe ( 0 ) ;
0 commit comments