authorgravatar for pat.github@tullmann.orgPat Tullmann <pat.github@tullmann.org> 2024-09-16 21:52:28-07:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-02-20 08:44:09+01:00
logd0e288ab1856a02d0556b9ceadd6fc6337ada905
tree60e5e2b63f36b02a209960cdb159551d9dfec3d3
parent8d824dfdd06c6b0f307c6ea41dfdf316acf4a662

lib/std/posix/test.zig: enable disabled tests using CWD

Four tests in lib/std/posix/test.zig were disabled because they created fixed-name files in the current working directory, and this caused problems if tests were running in parallel with other build's tests. This PR fixes those tests to all use `std.testing.tmpDir` to create unique temporary names and directories. Also clean the tests up to more consistently use `defer` to clean up, or to just rely on tmpDir cleanup to remove individual files. Working on these tests revealed a bunch of stale WASI code paths in posix.zig, fixed by replacing stale `wast.AT.FDCWD` references with just `AT.FDCWD`. Fixes #14968.

2 files changed, 109 insertions(+), 108 deletions(-)

lib/std/posix.zig+8-8
......@@ -2104,7 +2104,7 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!
21042104 if (native_os == .windows) {
21052105 @compileError("symlink is not supported on Windows; use std.os.windows.CreateSymbolicLink instead");
21062106 } else if (native_os == .wasi and !builtin.link_libc) {
2107 return symlinkat(target_path, wasi.AT.FDCWD, sym_link_path);
2107 return symlinkat(target_path, AT.FDCWD, sym_link_path);
21082108 }
21092109 const target_path_c = try toPosixPath(target_path);
21102110 const sym_link_path_c = try toPosixPath(sym_link_path);
......@@ -2274,7 +2274,7 @@ pub fn linkZ(oldpath: [*:0]const u8, newpath: [*:0]const u8) LinkError!void {
22742274/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
22752275pub fn link(oldpath: []const u8, newpath: []const u8) LinkError!void {
22762276 if (native_os == .wasi and !builtin.link_libc) {
2277 return linkat(wasi.AT.FDCWD, oldpath, wasi.AT.FDCWD, newpath, 0) catch |err| switch (err) {
2277 return linkat(AT.FDCWD, oldpath, AT.FDCWD, newpath, 0) catch |err| switch (err) {
22782278 error.NotDir => unreachable, // link() does not support directories
22792279 else => |e| return e,
22802280 };
......@@ -2411,7 +2411,7 @@ pub const UnlinkError = error{
24112411/// See also `unlinkZ`.
24122412pub fn unlink(file_path: []const u8) UnlinkError!void {
24132413 if (native_os == .wasi and !builtin.link_libc) {
2414 return unlinkat(wasi.AT.FDCWD, file_path, 0) catch |err| switch (err) {
2414 return unlinkat(AT.FDCWD, file_path, 0) catch |err| switch (err) {
24152415 error.DirNotEmpty => unreachable, // only occurs when targeting directories
24162416 else => |e| return e,
24172417 };
......@@ -2605,7 +2605,7 @@ pub const RenameError = error{
26052605/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
26062606pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {
26072607 if (native_os == .wasi and !builtin.link_libc) {
2608 return renameat(wasi.AT.FDCWD, old_path, wasi.AT.FDCWD, new_path);
2608 return renameat(AT.FDCWD, old_path, AT.FDCWD, new_path);
26092609 } else if (native_os == .windows) {
26102610 const old_path_w = try windows.sliceToPrefixedFileW(null, old_path);
26112611 const new_path_w = try windows.sliceToPrefixedFileW(null, new_path);
......@@ -3000,7 +3000,7 @@ pub const MakeDirError = error{
30003000/// On other platforms, `dir_path` is an opaque sequence of bytes with no particular encoding.
30013001pub fn mkdir(dir_path: []const u8, mode: mode_t) MakeDirError!void {
30023002 if (native_os == .wasi and !builtin.link_libc) {
3003 return mkdirat(wasi.AT.FDCWD, dir_path, mode);
3003 return mkdirat(AT.FDCWD, dir_path, mode);
30043004 } else if (native_os == .windows) {
30053005 const dir_path_w = try windows.sliceToPrefixedFileW(null, dir_path);
30063006 return mkdirW(dir_path_w.span(), mode);
......@@ -3089,7 +3089,7 @@ pub const DeleteDirError = error{
30893089/// On other platforms, `dir_path` is an opaque sequence of bytes with no particular encoding.
30903090pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
30913091 if (native_os == .wasi and !builtin.link_libc) {
3092 return unlinkat(wasi.AT.FDCWD, dir_path, AT.REMOVEDIR) catch |err| switch (err) {
3092 return unlinkat(AT.FDCWD, dir_path, AT.REMOVEDIR) catch |err| switch (err) {
30933093 error.FileSystem => unreachable, // only occurs when targeting files
30943094 error.IsDir => unreachable, // only occurs when targeting files
30953095 else => |e| return e,
......@@ -3278,7 +3278,7 @@ pub const ReadLinkError = error{
32783278/// On other platforms, the result is an opaque sequence of bytes with no particular encoding.
32793279pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
32803280 if (native_os == .wasi and !builtin.link_libc) {
3281 return readlinkat(wasi.AT.FDCWD, file_path, out_buffer);
3281 return readlinkat(AT.FDCWD, file_path, out_buffer);
32823282 } else if (native_os == .windows) {
32833283 const file_path_w = try windows.sliceToPrefixedFileW(null, file_path);
32843284 return readlinkW(file_path_w.span(), out_buffer);
......@@ -4893,7 +4893,7 @@ pub fn access(path: []const u8, mode: u32) AccessError!void {
48934893 _ = try windows.GetFileAttributesW(path_w.span().ptr);
48944894 return;
48954895 } else if (native_os == .wasi and !builtin.link_libc) {
4896 return faccessat(wasi.AT.FDCWD, path, mode, 0);
4896 return faccessat(AT.FDCWD, path, mode, 0);
48974897 }
48984898 const path_c = try toPosixPath(path);
48994899 return accessZ(&path_c, mode);
lib/std/posix/test.zig+101-100
......@@ -44,13 +44,12 @@ test "check WASI CWD" {
4444 }
4545}
4646
47test "chdir smoke test" {
47test "chdir absolute parent" {
4848 if (native_os == .wasi) return error.SkipZigTest;
4949
50 if (true) {
51 // https://github.com/ziglang/zig/issues/14968
52 return error.SkipZigTest;
53 }
50 // Restore default CWD at end of test.
51 const orig_cwd = try fs.cwd().openDir(".", .{});
52 defer orig_cwd.setAsCwd() catch unreachable;
5453
5554 // Get current working directory path
5655 var old_cwd_buf: [fs.max_path_bytes]u8 = undefined;
......@@ -65,47 +64,46 @@ test "chdir smoke test" {
6564 }
6665
6766 // Next, change current working directory to one level above
68 if (native_os != .wasi) { // WASI does not support navigating outside of Preopens
69 const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute
70 try posix.chdir(parent);
67 const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute
68 try posix.chdir(parent);
7169
72 // Restore cwd because process may have other tests that do not tolerate chdir.
73 defer posix.chdir(old_cwd) catch unreachable;
70 var new_cwd_buf: [fs.max_path_bytes]u8 = undefined;
71 const new_cwd = try posix.getcwd(new_cwd_buf[0..]);
72 try expect(mem.eql(u8, parent, new_cwd));
73}
7474
75 var new_cwd_buf: [fs.max_path_bytes]u8 = undefined;
76 const new_cwd = try posix.getcwd(new_cwd_buf[0..]);
77 try expect(mem.eql(u8, parent, new_cwd));
78 }
75test "chdir relative" {
76 if (native_os == .wasi) return error.SkipZigTest;
7977
80 // Next, change current working directory to a temp directory one level below
81 {
82 // Create a tmp directory
83 var tmp_dir_buf: [fs.max_path_bytes]u8 = undefined;
84 const tmp_dir_path = path: {
85 var allocator = std.heap.FixedBufferAllocator.init(&tmp_dir_buf);
86 break :path try fs.path.resolve(allocator.allocator(), &[_][]const u8{ old_cwd, "zig-test-tmp" });
87 };
88 var tmp_dir = try fs.cwd().makeOpenPath("zig-test-tmp", .{});
78 var tmp = tmpDir(.{});
79 defer tmp.cleanup();
8980
90 // Change current working directory to tmp directory
91 try posix.chdir("zig-test-tmp");
81 // Restore default CWD at end of test.
82 const orig_cwd = try fs.cwd().openDir(".", .{});
83 defer orig_cwd.setAsCwd() catch unreachable;
9284
93 var new_cwd_buf: [fs.max_path_bytes]u8 = undefined;
94 const new_cwd = try posix.getcwd(new_cwd_buf[0..]);
85 // Use the tmpDir parent_dir as the "base" for the test. Then cd into the child
86 try tmp.parent_dir.setAsCwd();
9587
96 // On Windows, fs.path.resolve returns an uppercase drive letter, but the drive letter returned by getcwd may be lowercase
97 var resolved_cwd_buf: [fs.max_path_bytes]u8 = undefined;
98 const resolved_cwd = path: {
99 var allocator = std.heap.FixedBufferAllocator.init(&resolved_cwd_buf);
100 break :path try fs.path.resolve(allocator.allocator(), &[_][]const u8{new_cwd});
101 };
102 try expect(mem.eql(u8, tmp_dir_path, resolved_cwd));
88 // Capture base working directory path, to build expected full path
89 var base_cwd_buf: [fs.max_path_bytes]u8 = undefined;
90 const base_cwd = try posix.getcwd(base_cwd_buf[0..]);
10391
104 // Restore cwd because process may have other tests that do not tolerate chdir.
105 tmp_dir.close();
106 posix.chdir(old_cwd) catch unreachable;
107 try fs.cwd().deleteDir("zig-test-tmp");
108 }
92 const dir_name = &tmp.sub_path;
93 const expected_path = try fs.path.resolve(a, &.{ base_cwd, dir_name });
94 defer a.free(expected_path);
95
96 // change current working directory to new directory
97 try posix.chdir(dir_name);
98
99 var new_cwd_buf: [fs.max_path_bytes]u8 = undefined;
100 const new_cwd = try posix.getcwd(new_cwd_buf[0..]);
101
102 // On Windows, fs.path.resolve returns an uppercase drive letter, but the drive letter returned by getcwd may be lowercase
103 const resolved_cwd = try fs.path.resolve(a, &.{new_cwd});
104 defer a.free(resolved_cwd);
105
106 try expect(mem.eql(u8, expected_path, resolved_cwd));
109107}
110108
111109test "open smoke test" {
......@@ -222,44 +220,42 @@ test "openat smoke test" {
222220}
223221
224222test "symlink with relative paths" {
225 if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
223 if (native_os == .wasi) return error.SkipZigTest; // Can symlink, but can't change into tmpDir
226224
227 if (true) {
228 // https://github.com/ziglang/zig/issues/14968
229 return error.SkipZigTest;
230 }
231 const cwd = fs.cwd();
232 cwd.deleteFile("file.txt") catch {};
233 cwd.deleteFile("symlinked") catch {};
225 var tmp = tmpDir(.{});
226 defer tmp.cleanup();
227
228 const target_name = "symlink-target";
229 const symlink_name = "symlinker";
234230
235 // First, try relative paths in cwd
236 try cwd.writeFile(.{ .sub_path = "file.txt", .data = "nonsense" });
231 // Restore default CWD at end of test.
232 const orig_cwd = try fs.cwd().openDir(".", .{});
233 defer orig_cwd.setAsCwd() catch unreachable;
234
235 // Create the target file
236 try tmp.dir.writeFile(.{ .sub_path = target_name, .data = "nonsense" });
237
238 // Want to test relative paths, so cd into the tmpdir for this test
239 try tmp.dir.setAsCwd();
237240
238241 if (native_os == .windows) {
239 std.os.windows.CreateSymbolicLink(
240 cwd.fd,
241 &[_]u16{ 's', 'y', 'm', 'l', 'i', 'n', 'k', 'e', 'd' },
242 &[_:0]u16{ 'f', 'i', 'l', 'e', '.', 't', 'x', 't' },
243 false,
244 ) catch |err| switch (err) {
242 const wtarget_name = try std.unicode.wtf8ToWtf16LeAllocZ(a, target_name);
243 const wsymlink_name = try std.unicode.wtf8ToWtf16LeAllocZ(a, symlink_name);
244 defer a.free(wtarget_name);
245 defer a.free(wsymlink_name);
246
247 std.os.windows.CreateSymbolicLink(tmp.dir.fd, wsymlink_name, wtarget_name, false) catch |err| switch (err) {
245248 // Symlink requires admin privileges on windows, so this test can legitimately fail.
246 error.AccessDenied => {
247 try cwd.deleteFile("file.txt");
248 try cwd.deleteFile("symlinked");
249 return error.SkipZigTest;
250 },
249 error.AccessDenied => return error.SkipZigTest,
251250 else => return err,
252251 };
253252 } else {
254 try posix.symlink("file.txt", "symlinked");
253 try posix.symlink(target_name, symlink_name);
255254 }
256255
257256 var buffer: [fs.max_path_bytes]u8 = undefined;
258 const given = try posix.readlink("symlinked", buffer[0..]);
259 try expect(mem.eql(u8, "file.txt", given));
260
261 try cwd.deleteFile("file.txt");
262 try cwd.deleteFile("symlinked");
257 const given = try posix.readlink(symlink_name, buffer[0..]);
258 try expect(mem.eql(u8, target_name, given));
263259}
264260
265261test "readlink on Windows" {
......@@ -277,90 +273,95 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
277273}
278274
279275test "link with relative paths" {
280 if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
276 if (native_os == .wasi) return error.SkipZigTest; // Can link, but can't change into tmpDir
277 if (builtin.cpu.arch == .riscv32 and builtin.os.tag == .linux and !builtin.link_libc) return error.SkipZigTest; // No `fstat()`.
281278
282279 switch (native_os) {
283280 .wasi, .linux, .solaris, .illumos => {},
284281 else => return error.SkipZigTest,
285282 }
286 if (true) {
287 // https://github.com/ziglang/zig/issues/14968
288 return error.SkipZigTest;
289 }
290 var cwd = fs.cwd();
291283
292 cwd.deleteFile("example.txt") catch {};
293 cwd.deleteFile("new.txt") catch {};
284 var tmp = tmpDir(.{});
285 defer tmp.cleanup();
286
287 // Restore default CWD at end of test.
288 const orig_cwd = try fs.cwd().openDir(".", .{});
289 defer orig_cwd.setAsCwd() catch unreachable;
290
291 const target_name = "link-target";
292 const link_name = "newlink";
293
294 try tmp.dir.writeFile(.{ .sub_path = target_name, .data = "example" });
294295
295 try cwd.writeFile(.{ .sub_path = "example.txt", .data = "example" });
296 try posix.link("example.txt", "new.txt");
296 // Test 1: create the relative link from inside tmp
297 try tmp.dir.setAsCwd();
298 try posix.link(target_name, link_name);
297299
298 const efd = try cwd.openFile("example.txt", .{});
300 // Verify
301 const efd = try tmp.dir.openFile(target_name, .{});
299302 defer efd.close();
300303
301 const nfd = try cwd.openFile("new.txt", .{});
304 const nfd = try tmp.dir.openFile(link_name, .{});
302305 defer nfd.close();
303306
304307 {
305308 const estat = try posix.fstat(efd.handle);
306309 const nstat = try posix.fstat(nfd.handle);
307
308310 try testing.expectEqual(estat.ino, nstat.ino);
309311 try testing.expectEqual(@as(@TypeOf(nstat.nlink), 2), nstat.nlink);
310312 }
311313
312 try posix.unlink("new.txt");
314 // Test 2: Remove the link and see the stats update
315 try posix.unlink(link_name);
313316
314317 {
315318 const estat = try posix.fstat(efd.handle);
316319 try testing.expectEqual(@as(@TypeOf(estat.nlink), 1), estat.nlink);
317320 }
318
319 try cwd.deleteFile("example.txt");
320321}
321322
322323test "linkat with different directories" {
323 if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
324 if (builtin.cpu.arch == .riscv32 and builtin.os.tag == .linux and !builtin.link_libc) return error.SkipZigTest; // No `fstatat()`.
324325
325326 switch (native_os) {
326327 .wasi, .linux, .solaris, .illumos => {},
327328 else => return error.SkipZigTest,
328329 }
329 if (true) {
330 // https://github.com/ziglang/zig/issues/14968
331 return error.SkipZigTest;
332 }
333 var cwd = fs.cwd();
330
334331 var tmp = tmpDir(.{});
332 defer tmp.cleanup();
333
334 const target_name = "link-target";
335 const link_name = "newlink";
335336
336 cwd.deleteFile("example.txt") catch {};
337 tmp.dir.deleteFile("new.txt") catch {};
337 const subdir = try tmp.dir.makeOpenPath("subdir", .{});
338338
339 try cwd.writeFile(.{ .sub_path = "example.txt", .data = "example" });
340 try posix.linkat(cwd.fd, "example.txt", tmp.dir.fd, "new.txt", 0);
339 defer tmp.dir.deleteFile(target_name) catch {};
340 try tmp.dir.writeFile(.{ .sub_path = target_name, .data = "example" });
341341
342 const efd = try cwd.openFile("example.txt", .{});
342 // Test 1: link from file in subdir back up to target in parent directory
343 try posix.linkat(tmp.dir.fd, target_name, subdir.fd, link_name, 0);
344
345 const efd = try tmp.dir.openFile(target_name, .{});
343346 defer efd.close();
344347
345 const nfd = try tmp.dir.openFile("new.txt", .{});
348 const nfd = try subdir.openFile(link_name, .{});
349 defer nfd.close();
346350
347351 {
348 defer nfd.close();
349352 const estat = try posix.fstat(efd.handle);
350353 const nstat = try posix.fstat(nfd.handle);
351
352354 try testing.expectEqual(estat.ino, nstat.ino);
353355 try testing.expectEqual(@as(@TypeOf(nstat.nlink), 2), nstat.nlink);
354356 }
355357
356 try posix.unlinkat(tmp.dir.fd, "new.txt", 0);
358 // Test 2: remove link
359 try posix.unlinkat(subdir.fd, link_name, 0);
357360
358361 {
359362 const estat = try posix.fstat(efd.handle);
360363 try testing.expectEqual(@as(@TypeOf(estat.nlink), 1), estat.nlink);
361364 }
362
363 try cwd.deleteFile("example.txt");
364365}
365366
366367test "fstatat" {
......@@ -979,7 +980,7 @@ test "POSIX file locking with fcntl" {
979980 return error.SkipZigTest;
980981 }
981982
982 var tmp = std.testing.tmpDir(.{});
983 var tmp = tmpDir(.{});
983984 defer tmp.cleanup();
984985
985986 // Create a temporary lock file