Skip to content

Commit d0e288a

Browse files
rootbeeralexrp
authored andcommitted
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.
1 parent 8d824df commit d0e288a

File tree

2 files changed

+109
-108
lines changed

2 files changed

+109
-108
lines changed

lib/std/posix.zig

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
22752275
pub 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`.
24122412
pub 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.
26062606
pub 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.
30013001
pub 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.
30903090
pub 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.
32793279
pub 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

Lines changed: 101 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,12 @@ test "check WASI CWD" {
4444
}
4545
}
4646

47-
test "chdir smoke test" {
47+
test "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-
}
75+
test "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

111109
test "open smoke test" {
@@ -222,44 +220,42 @@ test "openat smoke test" {
222220
}
223221

224222
test "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

265261
test "readlink on Windows" {
@@ -277,90 +273,95 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
277273
}
278274

279275
test "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

322323
test "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

366367
test "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

0 commit comments

Comments
 (0)