Commit 49128c86f8

LeRoyce Pearson <leroycepearson@geemili.xyz>
2020-03-14 22:31:54
Extract `run_lock_file_test`
1 parent 7ab7768
Changed files (1)
lib
std
lib/std/fs.zig
@@ -1723,50 +1723,70 @@ test "" {
 
 const FILE_LOCK_TEST_SLEEP_TIME = 1 * std.time.ns_per_s;
 
-//test "open file with lock twice, make sure it wasn't open at the same time" {
-//    const filename = "file_lock_test.txt";
-//
-//    if (builtin.os.tag == .windows) {
-//        var ctxs = [_]FileLockTestContext{
-//            .{ .filename = filename },
-//            .{ .filename = filename },
-//        };
-//
-//        const threads = [_]*std.Thread{
-//            try std.Thread.spawn(&ctxs[0], lock_file_for_test),
-//            try std.Thread.spawn(&ctxs[1], lock_file_for_test),
-//        };
-//
-//        for (threads[0..]) |thread| {
-//            thread.wait();
-//        }
-//
-//        std.debug.assert(!ctxs[0].overlaps(&ctxs[1]));
-//    } else {
-//        const shared_mem = try std.os.mmap(null, 2 * @sizeOf(FileLockTestContext), std.os.PROT_READ | std.os.PROT_WRITE, std.os.MAP_SHARED | std.os.MAP_ANONYMOUS, -1, 0);
-//        defer std.os.munmap(shared_mem);
-//        const ctxs = @ptrCast([*]FileLockTestContext, shared_mem.ptr);
-//
-//        const childpid = try std.os.fork();
-//        const ctx_idx: usize = if (childpid != 0) 0 else 1;
-//
-//        ctxs[ctx_idx].filename = filename;
-//        lock_file_for_test(&ctxs[ctx_idx]);
-//
-//        if (childpid != 0) {
-//            _ = std.os.waitpid(childpid, 0);
-//
-//            std.debug.assert(!ctxs[0].overlaps(&ctxs[1]));
-//        } else {
-//            std.os.exit(0);
-//        }
-//    }
-//
-//    cwd().deleteFile(filename) catch |err| switch (err) {
-//        error.FileNotFound => {},
-//        else => return err,
-//    };
-//}
+test "open file with lock twice, make sure it wasn't open at the same time" {
+    const filename = "file_lock_test.txt";
+
+    var contexts = [_]FileLockTestContext{
+        .{ .filename = filename, .create = true, .exclusive = true },
+        .{ .filename = filename, .create = true, .exclusive = true },
+    };
+    try run_lock_file_test(&contexts);
+
+    // Check for an error
+    var was_error = false;
+    for (contexts) |context, idx| {
+        if (context.err) |err| {
+            was_error = true;
+            std.debug.warn("\nError in context {}: {}\n", .{ idx, err });
+        }
+    }
+    if (was_error) builtin.panic("There was an error in contexts", null);
+
+    std.debug.assert(!contexts[0].overlaps(&contexts[1]));
+
+    cwd().deleteFile(filename) catch |err| switch (err) {
+        error.FileNotFound => {},
+        else => return err,
+    };
+}
+
+test "create file, lock and read from multiple process at once" {
+    const filename = "file_read_lock_test.txt";
+    const filedata = "Hello, world!\n";
+
+    try std.fs.cwd().writeFile(filename, filedata);
+
+    var contexts = [_]FileLockTestContext{
+        .{ .filename = filename, .create = false, .exclusive = false },
+        .{ .filename = filename, .create = false, .exclusive = false },
+        .{ .filename = filename, .create = false, .exclusive = true },
+    };
+
+    try run_lock_file_test(&contexts);
+
+    var was_error = false;
+    for (contexts) |context, idx| {
+        if (context.err) |err| {
+            was_error = true;
+            std.debug.warn("\nError in context {}: {}\n", .{ idx, err });
+        }
+    }
+    if (was_error) builtin.panic("There was an error in contexts", null);
+
+    std.debug.assert(contexts[0].overlaps(&contexts[1]));
+    std.debug.assert(!contexts[2].overlaps(&contexts[0]));
+    std.debug.assert(!contexts[2].overlaps(&contexts[1]));
+    if (contexts[0].bytes_read.? != filedata.len) {
+        std.debug.warn("\n bytes_read: {}, expected: {} \n", .{ contexts[0].bytes_read, filedata.len });
+    }
+    std.debug.assert(contexts[0].bytes_read.? == filedata.len);
+    std.debug.assert(contexts[1].bytes_read.? == filedata.len);
+
+    cwd().deleteFile(filename) catch |err| switch (err) {
+        error.FileNotFound => {},
+        else => return err,
+    };
+}
 
 const FileLockTestContext = struct {
     filename: []const u8,
@@ -1778,6 +1798,7 @@ const FileLockTestContext = struct {
     exclusive: bool,
 
     // Output variables
+    err: ?(File.OpenError || std.os.ReadError) = null,
     start_time: u64 = 0,
     end_time: u64 = 0,
     bytes_read: ?usize = null,
@@ -1789,69 +1810,65 @@ const FileLockTestContext = struct {
     fn run(ctx: *@This()) void {
         var file: File = undefined;
         if (ctx.create) {
-            file = cwd().createFile(ctx.filename, .{ .lock = true }) catch unreachable;
+            file = cwd().createFile(ctx.filename, .{ .lock = true }) catch |err| {
+                ctx.err = err;
+                return;
+            };
         } else {
-            file = cwd().openFile(ctx.filename, .{ .lock = true, .write = ctx.exclusive }) catch unreachable;
+            file = cwd().openFile(ctx.filename, .{ .lock = true, .write = ctx.exclusive }) catch |err| {
+                ctx.err = err;
+                return;
+            };
         }
+        defer file.close();
 
         ctx.start_time = std.time.milliTimestamp();
 
-        var buffer: [100]u8 = undefined;
-        ctx.bytes_read = 0;
-        while (true) {
-            const amt = file.read(buffer[0..]) catch unreachable;
-            if (amt == 0) break;
-            ctx.bytes_read.? += amt;
+        if (!ctx.create) {
+            var buffer: [100]u8 = undefined;
+            ctx.bytes_read = 0;
+            while (true) {
+                const amt = file.read(buffer[0..]) catch |err| {
+                    ctx.err = err;
+                    return;
+                };
+                if (amt == 0) break;
+                ctx.bytes_read.? += amt;
+            }
         }
+
         std.time.sleep(FILE_LOCK_TEST_SLEEP_TIME);
 
         ctx.end_time = std.time.milliTimestamp();
-        file.close();
     }
 };
 
-test "create file, lock and read from multiple process at once" {
-    const filename = "file_read_lock_test.txt";
-    const filedata = "Hello, world!\n";
-
-    try std.fs.cwd().writeFile(filename, filedata);
-
-    const NUM_PROCESSES = 3;
-    var shared_mem: if (builtin.os.tag == .windows) [NUM_PROCESSES]FileLockTestContext else []align(mem.page_size) u8 = undefined;
+fn run_lock_file_test(contexts: []FileLockTestContext) !void {
+    var shared_mem: if (builtin.os.tag == .windows) void else []align(mem.page_size) u8 = undefined;
 
     var ctxs: []FileLockTestContext = undefined;
     if (builtin.os.tag == .windows) {
-        ctxs = shared_mem[0..NUM_PROCESSES];
+        ctxs = contexts;
     } else {
-        shared_mem = try std.os.mmap(null, NUM_PROCESSES * @sizeOf(FileLockTestContext), std.os.PROT_READ | std.os.PROT_WRITE, std.os.MAP_SHARED | std.os.MAP_ANONYMOUS, -1, 0);
+        shared_mem = try std.os.mmap(null, contexts.len * @sizeOf(FileLockTestContext), std.os.PROT_READ | std.os.PROT_WRITE, std.os.MAP_SHARED | std.os.MAP_ANONYMOUS, -1, 0);
         const ctxs_ptr = @ptrCast([*]FileLockTestContext, shared_mem.ptr);
-        ctxs = ctxs_ptr[0..NUM_PROCESSES];
-    }
+        ctxs = ctxs_ptr[0..contexts.len];
 
-    ctxs[0] = .{
-        .filename = filename,
-        .create = false,
-        .exclusive = false,
-    };
-    ctxs[1] = .{
-        .filename = filename,
-        .create = false,
-        .exclusive = false,
-    };
-    ctxs[2] = .{
-        .filename = filename,
-        .create = false,
-        .exclusive = true,
-    };
+        for (contexts) |context, idx| {
+            ctxs[idx] = context;
+        }
+    }
 
     if (builtin.os.tag == .windows) {
-        const threads: [NUM_PROCESSES]*std.Thread = undefined;
-        for (ctxs) |*ctx, idx| {
-            threads[idx] = try std.Thread.spawn(ctx, Context.run);
+        const threads = std.ArrayList(*std.Thread).init(testing.allocator);
+        defer {
+            for (threads.toSlice()) |thread| {
+                thread.wait();
+            }
+            threads.deinit();
         }
-
-        for (threads[0..]) |thread| {
-            thread.wait();
+        for (ctxs) |*ctx, idx| {
+            threads.append(try std.Thread.spawn(ctx, Context.run));
         }
     } else {
         var ctx_opt: ?*FileLockTestContext = null;
@@ -1875,21 +1892,11 @@ test "create file, lock and read from multiple process at once" {
         }
     }
 
-    std.debug.assert(ctxs[0].overlaps(&ctxs[1]));
-    std.debug.assert(!ctxs[2].overlaps(&ctxs[0]));
-    std.debug.assert(!ctxs[2].overlaps(&ctxs[1]));
-    if (ctxs[0].bytes_read.? != filedata.len) {
-        std.debug.warn("\n bytes_read: {}, expected: {} \n", .{ ctxs[0].bytes_read, filedata.len });
-    }
-    std.debug.assert(ctxs[0].bytes_read.? == filedata.len);
-    std.debug.assert(ctxs[1].bytes_read.? == filedata.len);
-
     if (builtin.os.tag != .windows) {
+        // Copy contexts out of shared memory
+        for (ctxs) |ctx, idx| {
+            contexts[idx] = ctx;
+        }
         std.os.munmap(shared_mem);
     }
-
-    cwd().deleteFile(filename) catch |err| switch (err) {
-        error.FileNotFound => {},
-        else => return err,
-    };
 }