// vtest flaky: true // vtest retry: 3 import os import os.notify // make a pipe and return the (read, write) file descriptors fn make_pipe() !(int, int) { $if linux { pipefd := [2]int{} if C.pipe(&pipefd[0]) != 0 { return error('error ${C.errno}: ' + os.posix_get_error_msg(C.errno)) } return pipefd[0], pipefd[1] } return -1, -1 } fn test_level_trigger() { // currently only linux is supported $if linux { mut notifier := notify.new()! reader, writer := make_pipe()! defer { os.fd_close(reader) os.fd_close(writer) notifier.close() or {} } notifier.add(reader, .read)! os.fd_write(writer, 'foobar') mut n := ¬ifier check_read_event(mut n, reader, 'foo') check_read_event(mut n, reader, 'bar') assert notifier.wait(0).len == 0 } } fn test_edge_trigger() { // currently only linux is supported $if linux { mut notifier := notify.new()! reader, writer := make_pipe()! defer { os.fd_close(reader) os.fd_close(writer) notifier.close() or {} } notifier.add(reader, .read, .edge_trigger)! mut n := ¬ifier os.fd_write(writer, 'foobar') check_read_event(mut n, reader, 'foo') assert notifier.wait(0).len == 0 os.fd_write(writer, 'baz') // we do not get an event because there is still data // to be read // assert notifier.wait(0).len == 0 // TODO: investigage why the above assert suddenly started failing on the latest Ubuntu kernel update: // 5.11.0-37-generic #41~20.04.2-Ubuntu SMP Fri Sep 24 09:06:38 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux } } fn test_one_shot() { $if linux { mut notifier := notify.new()! reader, writer := make_pipe()! defer { os.fd_close(reader) os.fd_close(writer) notifier.close() or {} } notifier.add(reader, .read, .one_shot)! mut n := ¬ifier os.fd_write(writer, 'foobar') check_read_event(mut n, reader, 'foo') os.fd_write(writer, 'baz') assert notifier.wait(0).len == 0 // rearm notifier.modify(reader, .read)! check_read_event(mut n, reader, 'barbaz') } } fn test_hangup() { $if linux { mut notifier := notify.new()! reader, writer := make_pipe()! defer { os.fd_close(reader) notifier.close() or {} } notifier.add(reader, .hangup)! assert notifier.wait(0).len == 0 // closing on the writer end of the pipe will // cause a hangup on the reader end os.fd_close(writer) events := notifier.wait(0) assert events.len == 1 assert events[0].fd == reader assert events[0].kind.has(.hangup) } } fn test_write() { $if linux { mut notifier := notify.new()! reader, writer := make_pipe()! defer { os.fd_close(reader) os.fd_close(writer) notifier.close() or {} } notifier.add(reader, .write)! assert notifier.wait(0).len == 0 notifier.add(writer, .write)! events := notifier.wait(0) assert events.len == 1 assert events[0].fd == writer assert events[0].kind.has(.write) } } fn test_remove() { $if linux { mut notifier := notify.new()! reader, writer := make_pipe()! defer { os.fd_close(reader) os.fd_close(writer) notifier.close() or {} } // level triggered - will keep getting events while // there is data to read notifier.add(reader, .read)! os.fd_write(writer, 'foobar') assert notifier.wait(0).len == 1 assert notifier.wait(0).len == 1 notifier.remove(reader)! assert notifier.wait(0).len == 0 } } fn check_read_event(mut notifier notify.FdNotifier, reader_fd int, expected string) { events := notifier.wait(0) assert events.len == 1 assert events[0].fd == reader_fd assert events[0].kind.has(.read) s, _ := os.fd_read(events[0].fd, expected.len) assert s == expected }