| ... | ... | @@ -1584,13 +1584,6 @@ pub fn openSelfExe() OpenSelfExeError!File { |
| 1584 | 1584 | return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, .{}); |
| 1585 | 1585 | } |
| 1586 | 1586 | |
| 1587 | | test "openSelfExe" { |
| 1588 | | switch (builtin.os.tag) { |
| 1589 | | .linux, .macosx, .ios, .windows, .freebsd, .dragonfly => (try openSelfExe()).close(), |
| 1590 | | else => return error.SkipZigTest, // Unsupported OS. |
| 1591 | | } |
| 1592 | | } |
| 1593 | | |
| 1594 | 1587 | pub const SelfExePathError = os.ReadLinkError || os.SysCtlError; |
| 1595 | 1588 | |
| 1596 | 1589 | /// `selfExePath` except allocates the result on the heap. |
| ... | ... | @@ -1678,163 +1671,9 @@ test "" { |
| 1678 | 1671 | _ = copyFileAbsolute; |
| 1679 | 1672 | _ = updateFileAbsolute; |
| 1680 | 1673 | _ = Dir.copyFile; |
| 1674 | _ = @import("fs/test.zig"); |
| 1681 | 1675 | _ = @import("fs/path.zig"); |
| 1682 | 1676 | _ = @import("fs/file.zig"); |
| 1683 | 1677 | _ = @import("fs/get_app_data_dir.zig"); |
| 1684 | 1678 | _ = @import("fs/watch.zig"); |
| 1685 | 1679 | } |
| 1686 | | |
| 1687 | | const FILE_LOCK_TEST_SLEEP_TIME = 5 * std.time.millisecond; |
| 1688 | | |
| 1689 | | test "open file with exclusive nonblocking lock twice" { |
| 1690 | | const dir = cwd(); |
| 1691 | | const filename = "file_nonblocking_lock_test.txt"; |
| 1692 | | |
| 1693 | | const file1 = try dir.createFile(filename, .{ .lock = .Exclusive, .lock_nonblocking = true }); |
| 1694 | | defer file1.close(); |
| 1695 | | |
| 1696 | | const file2 = dir.createFile(filename, .{ .lock = .Exclusive, .lock_nonblocking = true }); |
| 1697 | | std.debug.assert(std.meta.eql(file2, error.WouldBlock)); |
| 1698 | | |
| 1699 | | dir.deleteFile(filename) catch |err| switch (err) { |
| 1700 | | error.FileNotFound => {}, |
| 1701 | | else => return err, |
| 1702 | | }; |
| 1703 | | } |
| 1704 | | |
| 1705 | | test "open file with lock twice, make sure it wasn't open at the same time" { |
| 1706 | | if (builtin.single_threaded) return; |
| 1707 | | |
| 1708 | | const filename = "file_lock_test.txt"; |
| 1709 | | |
| 1710 | | var contexts = [_]FileLockTestContext{ |
| 1711 | | .{ .filename = filename, .create = true, .lock = .Exclusive }, |
| 1712 | | .{ .filename = filename, .create = true, .lock = .Exclusive }, |
| 1713 | | }; |
| 1714 | | try run_lock_file_test(&contexts); |
| 1715 | | |
| 1716 | | // Check for an error |
| 1717 | | var was_error = false; |
| 1718 | | for (contexts) |context, idx| { |
| 1719 | | if (context.err) |err| { |
| 1720 | | was_error = true; |
| 1721 | | std.debug.warn("\nError in context {}: {}\n", .{ idx, err }); |
| 1722 | | } |
| 1723 | | } |
| 1724 | | if (was_error) builtin.panic("There was an error in contexts", null); |
| 1725 | | |
| 1726 | | std.debug.assert(!contexts[0].overlaps(&contexts[1])); |
| 1727 | | |
| 1728 | | cwd().deleteFile(filename) catch |err| switch (err) { |
| 1729 | | error.FileNotFound => {}, |
| 1730 | | else => return err, |
| 1731 | | }; |
| 1732 | | } |
| 1733 | | |
| 1734 | | test "create file, lock and read from multiple process at once" { |
| 1735 | | if (builtin.single_threaded) return; |
| 1736 | | |
| 1737 | | const filename = "file_read_lock_test.txt"; |
| 1738 | | const filedata = "Hello, world!\n"; |
| 1739 | | |
| 1740 | | try std.fs.cwd().writeFile(filename, filedata); |
| 1741 | | |
| 1742 | | var contexts = [_]FileLockTestContext{ |
| 1743 | | .{ .filename = filename, .create = false, .lock = .Shared }, |
| 1744 | | .{ .filename = filename, .create = false, .lock = .Shared }, |
| 1745 | | .{ .filename = filename, .create = false, .lock = .Exclusive }, |
| 1746 | | }; |
| 1747 | | |
| 1748 | | try run_lock_file_test(&contexts); |
| 1749 | | |
| 1750 | | var was_error = false; |
| 1751 | | for (contexts) |context, idx| { |
| 1752 | | if (context.err) |err| { |
| 1753 | | was_error = true; |
| 1754 | | std.debug.warn("\nError in context {}: {}\n", .{ idx, err }); |
| 1755 | | } |
| 1756 | | } |
| 1757 | | if (was_error) builtin.panic("There was an error in contexts", null); |
| 1758 | | |
| 1759 | | std.debug.assert(contexts[0].overlaps(&contexts[1])); |
| 1760 | | std.debug.assert(!contexts[2].overlaps(&contexts[0])); |
| 1761 | | std.debug.assert(!contexts[2].overlaps(&contexts[1])); |
| 1762 | | if (contexts[0].bytes_read.? != filedata.len) { |
| 1763 | | std.debug.warn("\n bytes_read: {}, expected: {} \n", .{ contexts[0].bytes_read, filedata.len }); |
| 1764 | | } |
| 1765 | | std.debug.assert(contexts[0].bytes_read.? == filedata.len); |
| 1766 | | std.debug.assert(contexts[1].bytes_read.? == filedata.len); |
| 1767 | | |
| 1768 | | cwd().deleteFile(filename) catch |err| switch (err) { |
| 1769 | | error.FileNotFound => {}, |
| 1770 | | else => return err, |
| 1771 | | }; |
| 1772 | | } |
| 1773 | | |
| 1774 | | const FileLockTestContext = struct { |
| 1775 | | filename: []const u8, |
| 1776 | | pid: if (builtin.os.tag == .windows) ?void else ?std.os.pid_t = null, |
| 1777 | | |
| 1778 | | // use file.createFile |
| 1779 | | create: bool, |
| 1780 | | // the type of lock to use |
| 1781 | | lock: File.Lock, |
| 1782 | | |
| 1783 | | // Output variables |
| 1784 | | err: ?(File.OpenError || std.os.ReadError) = null, |
| 1785 | | start_time: u64 = 0, |
| 1786 | | end_time: u64 = 0, |
| 1787 | | bytes_read: ?usize = null, |
| 1788 | | |
| 1789 | | fn overlaps(self: *const @This(), other: *const @This()) bool { |
| 1790 | | return (self.start_time < other.end_time) and (self.end_time > other.start_time); |
| 1791 | | } |
| 1792 | | |
| 1793 | | fn run(ctx: *@This()) void { |
| 1794 | | var file: File = undefined; |
| 1795 | | if (ctx.create) { |
| 1796 | | file = cwd().createFile(ctx.filename, .{ .lock = ctx.lock }) catch |err| { |
| 1797 | | ctx.err = err; |
| 1798 | | return; |
| 1799 | | }; |
| 1800 | | } else { |
| 1801 | | file = cwd().openFile(ctx.filename, .{ .lock = ctx.lock }) catch |err| { |
| 1802 | | ctx.err = err; |
| 1803 | | return; |
| 1804 | | }; |
| 1805 | | } |
| 1806 | | defer file.close(); |
| 1807 | | |
| 1808 | | ctx.start_time = std.time.milliTimestamp(); |
| 1809 | | |
| 1810 | | if (!ctx.create) { |
| 1811 | | var buffer: [100]u8 = undefined; |
| 1812 | | ctx.bytes_read = 0; |
| 1813 | | while (true) { |
| 1814 | | const amt = file.read(buffer[0..]) catch |err| { |
| 1815 | | ctx.err = err; |
| 1816 | | return; |
| 1817 | | }; |
| 1818 | | if (amt == 0) break; |
| 1819 | | ctx.bytes_read.? += amt; |
| 1820 | | } |
| 1821 | | } |
| 1822 | | |
| 1823 | | std.time.sleep(FILE_LOCK_TEST_SLEEP_TIME); |
| 1824 | | |
| 1825 | | ctx.end_time = std.time.milliTimestamp(); |
| 1826 | | } |
| 1827 | | }; |
| 1828 | | |
| 1829 | | fn run_lock_file_test(contexts: []FileLockTestContext) !void { |
| 1830 | | var threads = std.ArrayList(*std.Thread).init(std.testing.allocator); |
| 1831 | | defer { |
| 1832 | | for (threads.toSlice()) |thread| { |
| 1833 | | thread.wait(); |
| 1834 | | } |
| 1835 | | threads.deinit(); |
| 1836 | | } |
| 1837 | | for (contexts) |*ctx, idx| { |
| 1838 | | try threads.append(try std.Thread.spawn(ctx, FileLockTestContext.run)); |
| 1839 | | } |
| 1840 | | } |