Chromium Code Reviews| Index: native_client_sdk/src/tests/nacl_io_test/mount_node_tty_test.cc |
| diff --git a/native_client_sdk/src/tests/nacl_io_test/mount_node_tty_test.cc b/native_client_sdk/src/tests/nacl_io_test/mount_node_tty_test.cc |
| index c9a67cd54fa825cad21223cef5e668a531246cf5..0df8a0bc4a822387fbea36530038297e4d0eb9fe 100644 |
| --- a/native_client_sdk/src/tests/nacl_io_test/mount_node_tty_test.cc |
| +++ b/native_client_sdk/src/tests/nacl_io_test/mount_node_tty_test.cc |
| @@ -126,6 +126,14 @@ TEST_F(TtyTest, TtyOutput) { |
| EXPECT_EQ(0, strncmp(user_data.output_buf, message, message_len)); |
| } |
| +static int TtyWrite(int fd, const char* string) { |
| + struct tioc_nacl_input_string input; |
| + input.buffer =string; |
| + input.length = strlen(input.buffer); |
| + char* ioctl_arg = reinterpret_cast<char*>(&input); |
| + return ki_ioctl(fd, TIOCNACLINPUT, ioctl_arg); |
| +} |
| + |
| // Returns: |
| // 0 -> Not readable |
| // 1 -> Readable |
| @@ -144,9 +152,9 @@ static int IsReadable(int fd) { |
| if (rtn != 1) |
| return -1; // error |
| if (FD_ISSET(fd, &errorfds)) |
| - return -1; // error |
| + return -2; // error |
| if (!FD_ISSET(fd, &readfds)) |
| - return -1; // error |
| + return -3; // error |
| return 1; // readable |
| } |
| @@ -186,18 +194,11 @@ TEST_F(TtyTest, TtySelect) { |
| ASSERT_FALSE(FD_ISSET(tty_fd, &errorfds)); |
| // Send 4 bytes to TTY input |
| - struct tioc_nacl_input_string input; |
| - input.buffer = "input:test"; |
| - input.length = strlen(input.buffer); |
| - char* ioctl_arg = reinterpret_cast<char*>(&input); |
| - ASSERT_EQ(0, ki_ioctl(tty_fd, TIOCNACLINPUT, ioctl_arg)); |
| + ASSERT_EQ(0, TtyWrite(tty_fd, "input:test")); |
| // TTY should not be readable until newline in written |
| ASSERT_EQ(IsReadable(tty_fd), 0); |
| - |
| - input.buffer = "input:\n"; |
| - input.length = strlen(input.buffer); |
| - ASSERT_EQ(0, ki_ioctl(tty_fd, TIOCNACLINPUT, ioctl_arg)); |
| + ASSERT_EQ(0, TtyWrite(tty_fd, "input:\n")); |
| // TTY should now be readable |
| ASSERT_EQ(IsReadable(tty_fd), 1); |
| @@ -205,6 +206,33 @@ TEST_F(TtyTest, TtySelect) { |
| ki_close(tty_fd); |
| } |
| +TEST_F(TtyTest, TtyICANON) { |
| + int tty_fd = ki_open("/dev/tty", O_RDONLY); |
| + |
| + ASSERT_EQ(IsReadable(tty_fd), 0); |
| + |
| + struct termios tattr; |
| + tcgetattr(tty_fd, &tattr); |
| + tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */ |
| + tcsetattr(tty_fd, TCSAFLUSH, &tattr); |
| + |
| + ASSERT_EQ(IsReadable(tty_fd), 0); |
| + |
| + // Set some bytes to the TTY, not including newline |
| + ASSERT_EQ(0, TtyWrite(tty_fd, "a")); |
| + |
| + // Since we are not in canonical mode the bytes should be |
| + // immediately readable. |
| + ASSERT_EQ(IsReadable(tty_fd), 1); |
| + |
| + // Read byte form tty. |
|
binji
2013/09/19 00:48:55
sp: from
noelallen1
2013/09/19 21:29:27
Done.
|
| + char c; |
| + ASSERT_EQ(1, read(tty_fd, &c, 1)); |
| + ASSERT_EQ('a', c); |
| + |
| + ASSERT_EQ(IsReadable(tty_fd), 0); |
| +} |
| + |
| int g_recieved_signal = 0; |
| void sighandler(int sig) { |
| @@ -246,4 +274,86 @@ TEST_F(TtyTest, WindowSize) { |
| reinterpret_cast<char*>(&old_winsize))); |
| } |
| +/* |
| + * Sleep for 50ms then send a resize event to /dev/tty. |
| + */ |
| +static void* resize_thread_main(void* arg) { |
| + usleep(50 * 1000); |
| + |
| + int* tty_fd = static_cast<int*>(arg); |
| + struct winsize winsize; |
| + winsize.ws_col = 100; |
| + winsize.ws_row = 200; |
| + ki_ioctl(*tty_fd, TIOCSWINSZ, reinterpret_cast<char*>(&winsize)); |
| + return NULL; |
| +} |
| + |
| +TEST_F(TtyTest, ResizeDuringSelect) { |
| + // Test that a window resize during a call |
| + // to select(3) will cause it to fail with EINTR. |
| + int tty_fd = ki_open("/dev/tty", O_RDONLY); |
| + |
| + fd_set readfds; |
| + fd_set errorfds; |
| + FD_ZERO(&readfds); |
| + FD_ZERO(&errorfds); |
| + FD_SET(tty_fd, &readfds); |
| + FD_SET(tty_fd, &errorfds); |
| + |
| + pthread_t resize_thread; |
| + pthread_create(&resize_thread, NULL, resize_thread_main, |
| + &tty_fd); |
| + |
| + struct timeval timeout; |
| + timeout.tv_sec = 20; |
| + timeout.tv_usec = 0; |
| + |
| + // TTY should not be readable either before or after the |
| + // call to select(3). |
| + ASSERT_EQ(IsReadable(tty_fd), 0); |
| + |
| + int rtn = ki_select(tty_fd + 1, &readfds, NULL, &errorfds, &timeout); |
| + pthread_join(resize_thread, NULL); |
| + ASSERT_EQ(-1, rtn); |
| + ASSERT_EQ(EINTR, errno); |
| + ASSERT_EQ(IsReadable(tty_fd), 0); |
| +} |
| + |
| +/* |
| + * Sleep for 50ms then send some input to the /dev/tty. |
| + */ |
| +static void* input_thread_main(void* arg) { |
| + usleep(50 * 1000); |
| + |
| + int fd = ki_open("/dev/tty", O_RDONLY); |
| + TtyWrite(fd, "test\n"); |
| + return NULL; |
| +} |
| + |
| +TEST_F(TtyTest, InputDuringSelect) { |
| + // Test that input which occurs while in select causes |
| + // select to return. |
| + int tty_fd = ki_open("/dev/tty", O_RDONLY); |
| + |
| + fd_set readfds; |
| + fd_set errorfds; |
| + FD_ZERO(&readfds); |
| + FD_ZERO(&errorfds); |
| + FD_SET(tty_fd, &readfds); |
| + FD_SET(tty_fd, &errorfds); |
| + |
| + pthread_t resize_thread; |
| + pthread_create(&resize_thread, NULL, input_thread_main, |
| + &dev_tty_); |
| + |
| + struct timeval timeout; |
| + timeout.tv_sec = 20; |
| + timeout.tv_usec = 0; |
| + |
| + int rtn = ki_select(tty_fd + 1, &readfds, NULL, &errorfds, &timeout); |
| + pthread_join(resize_thread, NULL); |
| + |
| + ASSERT_EQ(1, rtn); |
| +} |
| + |
| } |