-
Notifications
You must be signed in to change notification settings - Fork 5.2k
/
jsr_tests.rs
396 lines (346 loc) · 11.8 KB
/
jsr_tests.rs
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
use deno_core::serde_json::json;
use deno_core::serde_json::Value;
use deno_lockfile::Lockfile;
use test_util as util;
use url::Url;
use util::assert_contains;
use util::assert_not_contains;
use util::TestContextBuilder;
#[test]
fn fast_check_cache() {
let test_context = TestContextBuilder::for_jsr().use_temp_cwd().build();
let deno_dir = test_context.deno_dir();
let temp_dir = test_context.temp_dir();
let type_check_cache_path = deno_dir.path().join("check_cache_v1");
temp_dir.write(
"main.ts",
r#"import { add } from "jsr:@denotest/add@1";
const value: number = add(1, 2);
console.log(value);"#,
);
temp_dir.path().join("deno.json").write_json(&json!({
"vendor": true
}));
test_context
.new_command()
.args("check main.ts")
.run()
.skip_output_check();
type_check_cache_path.remove_file();
let check_debug_cmd = test_context
.new_command()
.args("check --log-level=debug main.ts");
let output = check_debug_cmd.run();
assert_contains!(
output.combined_output(),
"Using FastCheck cache for: @denotest/add@1.0.0"
);
// modify the file in the vendor folder
let vendor_dir = temp_dir.path().join("vendor");
let pkg_dir = vendor_dir.join("http_127.0.0.1_4250/@denotest/add/1.0.0/");
pkg_dir
.join("mod.ts")
.append("\nexport * from './other.ts';");
let nested_pkg_file = pkg_dir.join("other.ts");
nested_pkg_file.write("export function other(): string { return ''; }");
// invalidated
let output = check_debug_cmd.run();
assert_not_contains!(
output.combined_output(),
"Using FastCheck cache for: @denotest/add@1.0.0"
);
// ensure cache works
let output = check_debug_cmd.run();
assert_contains!(output.combined_output(), "Already type checked.");
let building_fast_check_msg = "Building fast check graph";
assert_not_contains!(output.combined_output(), building_fast_check_msg);
// now validated
type_check_cache_path.remove_file();
let output = check_debug_cmd.run();
assert_contains!(output.combined_output(), building_fast_check_msg);
assert_contains!(
output.combined_output(),
"Using FastCheck cache for: @denotest/add@1.0.0"
);
// cause a fast check error in the nested package
nested_pkg_file
.append("\nexport function asdf(a: number) { let err: number = ''; return Math.random(); }");
check_debug_cmd.run().skip_output_check();
// ensure the cache still picks it up for this file
type_check_cache_path.remove_file();
let output = check_debug_cmd.run();
assert_contains!(output.combined_output(), building_fast_check_msg);
assert_contains!(
output.combined_output(),
"Using FastCheck cache for: @denotest/add@1.0.0"
);
// see that the type checking error in the internal function gets surfaced with --all
test_context
.new_command()
.args("check --all main.ts")
.run()
.assert_matches_text(
"Check file:///[WILDCARD]main.ts
error: TS2322 [ERROR]: Type 'string' is not assignable to type 'number'.
export function asdf(a: number) { let err: number = ''; return Math.random(); }
~~~
at http://127.0.0.1:4250/@denotest/add/1.0.0/other.ts:2:39
",
)
.assert_exit_code(1);
// now fix the package
nested_pkg_file.write("export function test() {}");
let output = check_debug_cmd.run();
assert_contains!(output.combined_output(), building_fast_check_msg);
assert_not_contains!(
output.combined_output(),
"Using FastCheck cache for: @denotest/add@1.0.0"
);
// finally ensure it uses the cache
type_check_cache_path.remove_file();
let output = check_debug_cmd.run();
assert_contains!(output.combined_output(), building_fast_check_msg);
assert_contains!(
output.combined_output(),
"Using FastCheck cache for: @denotest/add@1.0.0"
);
}
#[test]
fn specifiers_in_lockfile() {
let test_context = TestContextBuilder::for_jsr().use_temp_cwd().build();
let temp_dir = test_context.temp_dir();
temp_dir.write(
"main.ts",
r#"import version from "jsr:@denotest/no-module-graph@0.1";
console.log(version);"#,
);
temp_dir.write("deno.json", "{}"); // to automatically create a lockfile
test_context
.new_command()
.args("run --quiet main.ts")
.run()
.assert_matches_text("0.1.1\n");
let lockfile_path = temp_dir.path().join("deno.lock");
let mut lockfile = Lockfile::new(lockfile_path.to_path_buf(), false).unwrap();
*lockfile
.content
.packages
.specifiers
.get_mut("jsr:@denotest/no-module-graph@0.1")
.unwrap() = "jsr:@denotest/no-module-graph@0.1.0".to_string();
lockfile_path.write(lockfile.as_json_string());
test_context
.new_command()
.args("run --quiet main.ts")
.run()
.assert_matches_text("0.1.0\n");
}
#[test]
fn reload_info_not_found_cache_but_exists_remote() {
fn remove_version(registry_json: &mut Value, version: &str) {
registry_json
.as_object_mut()
.unwrap()
.get_mut("versions")
.unwrap()
.as_object_mut()
.unwrap()
.remove(version);
}
fn remove_version_for_package(
deno_dir: &util::TempDir,
package: &str,
version: &str,
) {
let specifier =
Url::parse(&format!("http://127.0.0.1:4250/{}/meta.json", package))
.unwrap();
let registry_json_path = deno_dir
.path()
.join("deps")
.join(deno_cache_dir::url_to_filename(&specifier).unwrap());
let mut registry_json = registry_json_path.read_json_value();
remove_version(&mut registry_json, version);
registry_json_path.write_json(®istry_json);
}
// This tests that when a local machine doesn't have a version
// specified in a dependency that exists in the npm registry
let test_context = TestContextBuilder::for_jsr().use_temp_cwd().build();
let deno_dir = test_context.deno_dir();
let temp_dir = test_context.temp_dir();
temp_dir.write(
"main.ts",
"import { add } from 'jsr:@denotest/add@1'; console.log(add(1, 2));",
);
// cache successfully to the deno_dir
let output = test_context.new_command().args("cache main.ts").run();
output.assert_matches_text(concat!(
"Download http://127.0.0.1:4250/@denotest/add/meta.json\n",
"Download http://127.0.0.1:4250/@denotest/add/1.0.0_meta.json\n",
"Download http://127.0.0.1:4250/@denotest/add/1.0.0/mod.ts\n",
));
// modify the package information in the cache to remove the latest version
remove_version_for_package(deno_dir, "@denotest/add", "1.0.0");
// should error when `--cache-only` is used now because the version is not in the cache
let output = test_context
.new_command()
.args("run --cached-only main.ts")
.run();
output.assert_exit_code(1);
output.assert_matches_text("error: Failed to resolve version constraint. Try running again without --cached-only
at file:///[WILDCARD]main.ts:1:21
");
// now try running without it, it should download the package now
test_context
.new_command()
.args("run main.ts")
.run()
.assert_matches_text(concat!(
"Download http://127.0.0.1:4250/@denotest/add/meta.json\n",
"Download http://127.0.0.1:4250/@denotest/add/1.0.0_meta.json\n",
"3\n",
))
.assert_exit_code(0);
}
#[test]
fn lockfile_bad_package_integrity() {
let test_context = TestContextBuilder::for_jsr().use_temp_cwd().build();
let temp_dir = test_context.temp_dir();
temp_dir.write(
"main.ts",
r#"import version from "jsr:@denotest/no-module-graph@0.1";
console.log(version);"#,
);
temp_dir.write("deno.json", "{}"); // to automatically create a lockfile
test_context
.new_command()
.args("run --quiet main.ts")
.run()
.assert_matches_text("0.1.1\n");
let lockfile_path = temp_dir.path().join("deno.lock");
let mut lockfile = Lockfile::new(lockfile_path.to_path_buf(), false).unwrap();
let pkg_name = "@denotest/no-module-graph@0.1.1";
let original_integrity = get_lockfile_pkg_integrity(&lockfile, pkg_name);
set_lockfile_pkg_integrity(&mut lockfile, pkg_name, "bad_integrity");
lockfile_path.write(lockfile.as_json_string());
let actual_integrity =
test_context.get_jsr_package_integrity("@denotest/no-module-graph/0.1.1");
let integrity_check_failed_msg = format!("error: Integrity check failed for http://127.0.0.1:4250/@denotest/no-module-graph/0.1.1_meta.json
Actual: {}
Expected: bad_integrity
at file:///[WILDCARD]/main.ts:1:21
", actual_integrity);
test_context
.new_command()
.args("run --quiet main.ts")
.run()
.assert_matches_text(&integrity_check_failed_msg)
.assert_exit_code(1);
// now try with a vendor folder
temp_dir
.path()
.join("deno.json")
.write_json(&json!({ "vendor": true }));
// should fail again
test_context
.new_command()
.args("run --quiet main.ts")
.run()
.assert_matches_text(&integrity_check_failed_msg)
.assert_exit_code(1);
// now update to the correct integrity
set_lockfile_pkg_integrity(&mut lockfile, pkg_name, &original_integrity);
lockfile_path.write(lockfile.as_json_string());
// should pass now
test_context
.new_command()
.args("run --quiet main.ts")
.run()
.assert_matches_text("0.1.1\n")
.assert_exit_code(0);
// now update to a bad integrity again
set_lockfile_pkg_integrity(&mut lockfile, pkg_name, "bad_integrity");
lockfile_path.write(lockfile.as_json_string());
// shouldn't matter because we have a vendor folder
test_context
.new_command()
.args("run --quiet main.ts")
.run()
.assert_matches_text("0.1.1\n")
.assert_exit_code(0);
// now remove the vendor dir and it should fail again
temp_dir.path().join("vendor").remove_dir_all();
test_context
.new_command()
.args("run --quiet main.ts")
.run()
.assert_matches_text(&integrity_check_failed_msg)
.assert_exit_code(1);
}
#[test]
fn bad_manifest_checksum() {
let test_context = TestContextBuilder::for_jsr().use_temp_cwd().build();
let temp_dir = test_context.temp_dir();
temp_dir.write(
"main.ts",
r#"import { add } from "jsr:@denotest/bad-manifest-checksum@1.0.0";
console.log(add);"#,
);
// test it properly checks the checksum on download
test_context
.new_command()
.args("run main.ts")
.run()
.assert_matches_text(
"Download http://127.0.0.1:4250/@denotest/bad-manifest-checksum/meta.json
Download http://127.0.0.1:4250/@denotest/bad-manifest-checksum/1.0.0_meta.json
Download http://127.0.0.1:4250/@denotest/bad-manifest-checksum/1.0.0/mod.ts
error: Integrity check failed.
Actual: 9a30ac96b5d5c1b67eca69e1e2cf0798817d9578c8d7d904a81a67b983b35cba
Expected: bad-checksum
at file:///[WILDCARD]main.ts:1:21
",
)
.assert_exit_code(1);
// test it properly checks the checksum when loading from the cache
test_context
.new_command()
.args("run main.ts")
.run()
.assert_matches_text(
// ideally the two error messages would be the same... this one comes from
// deno_cache and the one above comes from deno_graph. The thing is, in deno_cache
// (source of this error) it makes sense to include the url in the error message
// because it's not always used in the context of deno_graph
"error: Integrity check failed for http://127.0.0.1:4250/@denotest/bad-manifest-checksum/1.0.0/mod.ts
Actual: 9a30ac96b5d5c1b67eca69e1e2cf0798817d9578c8d7d904a81a67b983b35cba
Expected: bad-checksum
at file:///[WILDCARD]main.ts:1:21
",
)
.assert_exit_code(1);
}
fn get_lockfile_pkg_integrity(lockfile: &Lockfile, pkg_name: &str) -> String {
lockfile
.content
.packages
.jsr
.get(pkg_name)
.unwrap()
.integrity
.clone()
}
fn set_lockfile_pkg_integrity(
lockfile: &mut Lockfile,
pkg_name: &str,
integrity: &str,
) {
lockfile
.content
.packages
.jsr
.get_mut(pkg_name)
.unwrap()
.integrity = integrity.to_string();
}