Repository: youtube/cobalt
Pull request #5354: Add tests for epoll
Author: login: madhurajayaraman
Created: 2025-04-09T22:29:17Z | Merged: 2025-05-27T15:23:21Z

b/406058855

Adding tests for epoll based on pre-existing SbSocketWaiter tests


Diff:
diff --git a/starboard/elf_loader/exported_symbols.cc b/starboard/elf_loader/exported_symbols.cc
index 68bed71769c1..89559bb45406 100644
--- a/starboard/elf_loader/exported_symbols.cc
+++ b/starboard/elf_loader/exported_symbols.cc
@@ -22,6 +22,7 @@
 #include <netdb.h>
 #include <sched.h>
 #include <stdlib.h>
+#include <sys/epoll.h>
 #include <sys/mman.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
@@ -216,6 +217,10 @@ ExportedSymbols::ExportedSymbols() {
   REGISTER_SYMBOL(closedir);
   REGISTER_SYMBOL(dup);
   REGISTER_SYMBOL(dup2);
+  REGISTER_SYMBOL(epoll_create);
+  REGISTER_SYMBOL(epoll_create1);
+  REGISTER_SYMBOL(epoll_ctl);
+  REGISTER_SYMBOL(epoll_wait);
   REGISTER_SYMBOL(fcntl);
   REGISTER_SYMBOL(free);
   REGISTER_SYMBOL(freeifaddrs);
diff --git a/starboard/nplb/BUILD.gn b/starboard/nplb/BUILD.gn
index a647726f846c..657d10e1c5c5 100644
--- a/starboard/nplb/BUILD.gn
+++ b/starboard/nplb/BUILD.gn
@@ -118,6 +118,10 @@ test("nplb") {
     "posix_compliance/posix_directory_create_test.cc",
     "posix_compliance/posix_directory_get_next_test.cc",
     "posix_compliance/posix_directory_open_test.cc",
+    "posix_compliance/posix_epoll_create_test.cc",
+    "posix_compliance/posix_epoll_ctl_test.cc",
+    "posix_compliance/posix_epoll_test_helper.cc",
+    "posix_compliance/posix_epoll_wait_test.cc",
     "posix_compliance/posix_file_can_open_test.cc",
     "posix_compliance/posix_file_close_test.cc",
     "posix_compliance/posix_file_delete_test.cc",
diff --git a/starboard/nplb/posix_compliance/posix_epoll_create_test.cc b/starboard/nplb/posix_compliance/posix_epoll_create_test.cc
new file mode 100644
index 000000000000..66e3f9ddf91d
--- /dev/null
+++ b/starboard/nplb/posix_compliance/posix_epoll_create_test.cc
@@ -0,0 +1,92 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*
+This contains tests for epoll_create() and epoll_create1(). epoll_create takes
+a size argument, which is disregarded as long as it is greater than zero.
+epoll_create1() takes a flags argument. When flags are 0, epoll_create1() is
+the same as epoll_create().
+The following error scenarios are untested for epoll_create1():
+1. EMFILE (per-process limit of open FDs) is difficult to test reliably in a
+unit test framework without affecting the environment or other tests. It would
+require opening FDs until the limit is reached.
+2. ENFILE (system-wide limit of open FDs) is even harder to test than EMFILE -
+it would require opening FDs till the system wide limit is reached.
+3. ENOMEM (out of memory) is not reliably testable in a unit test as it's hard
+to deterministically exhaust kernel memory.
+These are also untested for epoll_create() for the same reasons.
+*/
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+TEST(PosixEpollCreateTests, CreatesValidFileDescriptorOnSuccess) {
+  int epoll_fd = epoll_create(1);
+
+  ASSERT_GE(epoll_fd, 0) << "epoll_create(1) failed: " << strerror(errno);
+  ASSERT_EQ(close(epoll_fd), 0) << "close failed: " << strerror(errno);
+}
+
+TEST(PosixEpollCreateTests, FailsWithEINVALWhenSizeIsZero) {
+  int epoll_fd = epoll_create(0);
+
+  ASSERT_EQ(epoll_fd, -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST(PosixEpollCreateTests, FailsWithEINVALWhenSizeIsNegative) {
+  int epoll_fd = epoll_create(-1);
+
+  ASSERT_EQ(epoll_fd, -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST(PosixEpollCreate1Tests, CreateSuccessfully) {
+  int epfd = epoll_create1(0);
+  ASSERT_NE(epfd, -1) << "epoll_create1(0) failed: " << strerror(errno);
+  ASSERT_EQ(close(epfd), 0) << "close failed: " << strerror(errno);
+}
+
+TEST(PosixEpollCreate1Tests, CreateSuccessfullyWithCloExec) {
+  int epfd = epoll_create1(EPOLL_CLOEXEC);
+  ASSERT_NE(epfd, -1) << "epoll_create1(EPOLL_CLOEXEC) failed: "
+                      << strerror(errno);
+
+  int flags = fcntl(epfd, F_GETFD);
+  ASSERT_NE(flags, -1) << "fcntl(F_GETFD) failed: " << strerror(errno);
+  ASSERT_TRUE(flags & FD_CLOEXEC) << "FD_CLOEXEC was not set.";
+  ASSERT_EQ(close(epfd), 0) << "close failed: " << strerror(errno);
+}
+
+TEST(PosixEpollCreate1Tests, ErrorInvalidFlags) {
+  // An arbitrary invalid flag value.
+  // EPOLL_CLOEXEC is 0x80000. We pick another bit not used by epoll_create1.
+  const int kInvalidFlag = 0x1;
+  int epfd = epoll_create1(kInvalidFlag);
+  ASSERT_EQ(epfd, -1);
+  ASSERT_EQ(errno, EINVAL);
+  // No fd to close as creation failed.
+}
+
+}  // namespace
+}  // namespace nplb
+}  // namespace starboard
diff --git a/starboard/nplb/posix_compliance/posix_epoll_ctl_test.cc b/starboard/nplb/posix_compliance/posix_epoll_ctl_test.cc
new file mode 100644
index 000000000000..7d4d18b142ad
--- /dev/null
+++ b/starboard/nplb/posix_compliance/posix_epoll_ctl_test.cc
@@ -0,0 +1,218 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/* The following error scenarios are untested for epoll_ctl():
+1. ENOMEM (out of memory for control operation) is not reliably testable.
+2. ENOSPC (max_user_watches limit) is not reliably testable in a unit test.
+*/
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollCtlTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+
+  void SetUp() override {
+    epfd_ = epoll_create1(0);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+};
+
+TEST_F(PosixEpollCtlTests, AddFdSuccessfully) {
+  struct epoll_event event = {};
+  event.events = EPOLLIN | EPOLLOUT;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_ADD failed: " << strerror(errno);
+}
+
+TEST_F(PosixEpollCtlTests, ModifyFdSuccessfully) {
+  struct epoll_event event = {};
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_ADD for MOD test failed: " << strerror(errno);
+
+  event.events = EPOLLOUT;  // Modify to only EPOLLOUT
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_MOD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_MOD failed: " << strerror(errno);
+}
+
+TEST_F(PosixEpollCtlTests, DeleteFdSuccessfully) {
+  struct epoll_event event = {};
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_ADD for DEL test failed: " << strerror(errno);
+
+  // The 'event' parameter is ignored for EPOLL_CTL_DEL but must be non-NULL on
+  // older kernels. Modern kernels (>= 2.6.9) allow NULL. For compliance, pass a
+  // valid pointer.
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_DEL, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_DEL failed: " << strerror(errno);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorBadEpfd) {
+  struct epoll_event event = {};
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(kInvalidFd, EPOLL_CTL_ADD, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, EBADF);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorBadFdOnAdd) {
+  struct epoll_event event = {};
+  event.events = EPOLLIN;
+  event.data.fd = kInvalidFd;
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, kInvalidFd, &event), -1);
+  ASSERT_EQ(errno, EBADF);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorBadFdOnMod) {
+  struct epoll_event event = {};
+  event.events = EPOLLIN;
+  event.data.fd = kInvalidFd;  // This is the FD we are trying to MOD.
+
+  // First, add a valid fd to have something in the epoll set.
+  struct epoll_event valid_event = {};
+  valid_event.events = EPOLLIN;
+  valid_event.data.fd = pipe_fds_[0];
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &valid_event), 0);
+
+  // Try to MOD using an fd that is itself invalid.
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_MOD, kInvalidFd, &event), -1);
+  ASSERT_EQ(errno, EBADF);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorAlreadyExistsOnAdd) {
+  struct epoll_event event = {};
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "First EPOLL_CTL_ADD failed: " << strerror(errno);
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, EEXIST);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorEpfdIsNotEpollFd) {
+  struct epoll_event event = {};
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+
+  // Use one end of the pipe as a non-epoll fd for epfd argument
+  ASSERT_EQ(epoll_ctl(pipe_fds_[1], EPOLL_CTL_ADD, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorFdIsSameAsEpfd) {
+  struct epoll_event event = {};
+  event.events = EPOLLIN;
+  event.data.fd = epfd_;  // Trying to add epfd to itself
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, epfd_, &event), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorInvalidOperation) {
+  struct epoll_event event = {};
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+  // An arbitrary integer that isn't a valid EPOLL_CTL operation.
+  const int kInvalidOp = 99;
+
+  ASSERT_EQ(epoll_ctl(epfd_, kInvalidOp, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorLoopBetweenTwoEpollInstances) {
+  int epfd2 = epoll_create1(0);
+  ASSERT_NE(epfd2, -1)
+      << "Failed to create second epoll instance for ELOOP test: "
+      << strerror(errno);
+
+  // Try A watches B, B watches A
+  struct epoll_event ev_a_watches_b = {};
+  ev_a_watches_b.events = EPOLLIN;
+  ev_a_watches_b.data.fd = epfd2;  // epfd_ will watch epfd2
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, epfd2, &ev_a_watches_b), 0)
+      << "epoll_ctl add epfd2 to epfd_ failed: " << strerror(errno);
+
+  struct epoll_event ev_b_watches_a = {};
+  ev_b_watches_a.events = EPOLLIN;
+  ev_b_watches_a.data.fd = epfd_;  // epfd2 tries to watch epfd_
+  ASSERT_EQ(epoll_ctl(epfd2, EPOLL_CTL_ADD, epfd_, &ev_b_watches_a), -1);
+  ASSERT_EQ(errno, ELOOP);
+
+  // Clean up: remove epfd2 from epfd_
+  epoll_ctl(epfd_, EPOLL_CTL_DEL, epfd2, &ev_a_watches_b);
+  if (epfd2 >= 0) {
+    close(epfd2);
+  }
+}
+
+TEST_F(PosixEpollCtlTests, ErrorFdNotRegisteredOnMod) {
+  struct epoll_event event = {};
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];  // This fd is valid but not yet added
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_MOD, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, ENOENT);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorFdNotRegisteredOnDel) {
+  struct epoll_event event = {};  // Dummy event for DEL
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];  // This fd is valid but not yet added
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_DEL, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, ENOENT);
+}
+
+}  // namespace
+}  // namespace nplb
+}  // namespace starboard
diff --git a/starboard/nplb/posix_compliance/posix_epoll_test_helper.cc b/starboard/nplb/posix_compliance/posix_epoll_test_helper.cc
new file mode 100644
index 000000000000..6255fd15e796
--- /dev/null
+++ b/starboard/nplb/posix_compliance/posix_epoll_test_helper.cc
@@ -0,0 +1,46 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// A helper function to create a pipe.
+// Returns true on success, false on failure.
+// pipe_fds[0] is the read end, pipe_fds[1] is the write end.
+bool CreatePipe(int pipe_fds[2], int flags = 0) {
+  if (flags == 0) {
+    return pipe(pipe_fds) == 0;
+  }
+  return pipe2(pipe_fds, flags) == 0;
+}
+
+// Test fixture for epoll tests
+class PosixEpollTest : public ::testing::Test {
+ protected:
+  static const int kInvalidFd = -1;  // An fd value that is likely invalid.
+  static const int kMaxEvents = 10;  // Maximum number of events for epoll_wait.
+  static const int kShortTimeoutMs = 50;
+  static const int kModerateTimeoutMs = 100;
+};
+
+}  // namespace
+}  // namespace nplb
+}  // namespace starboard
diff --git a/starboard/nplb/posix_compliance/posix_epoll_wait_test.cc b/starboard/nplb/posix_compliance/posix_epoll_wait_test.cc
new file mode 100644
index 000000000000..6ef89cdea304
--- /dev/null
+++ b/starboard/nplb/posix_compliance/posix_epoll_wait_test.cc
@@ -0,0 +1,287 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/* The following error scenarios are untested for epoll_wait():
+1. EFAULT (events pointer is bad) is difficult to safely and reliably test.
+2. EINTR (interrupted by signal) is difficult to test.
+3. Negative timeout is an infinite timeout, which is difficult to test.
+*/
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollWaitTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+  struct epoll_event events_[kMaxEvents];
+
+  void SetUp() override {
+    epfd_ = epoll_create(1);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    // Use non-blocking pipes to prevent writes from blocking indefinitely if
+    // pipe is full
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+
+  // Helper to add to epoll
+  void AddToEpoll(int fd_to_add, uint32_t ev_mask) {
+    struct epoll_event event = {};
+    event.events = ev_mask;
+    event.data.fd = fd_to_add;
+    ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, fd_to_add, &event), 0)
+        << "Failed to add fd " << fd_to_add << " to epoll with events "
+        << ev_mask << ": " << strerror(errno);
+  }
+
+  // Helper to remove from epoll
+  void RemoveFromEpoll(int fd_to_remove) {
+    struct epoll_event event {};  // Dummy event, required for older kernels
+    if (epfd_ >= 0 && fd_to_remove >= 0) {
+      epoll_ctl(epfd_, EPOLL_CTL_DEL, fd_to_remove, &event);
+    }
+  }
+};
+
+TEST_F(PosixEpollWaitTests, EventReportedSuccessfully) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch read end for input
+
+  char buffer = 'x';
+  const size_t buffer_length = sizeof(buffer);
+  ASSERT_EQ(write(pipe_fds_[1], &buffer, buffer_length), buffer_length)
+      << "Write to pipe failed: " << strerror(errno);
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kModerateTimeoutMs);
+  ASSERT_EQ(nfds, 1) << "epoll_wait did not return 1 event: " << strerror(errno)
+                     << " (nfds=" << nfds << ")";
+  ASSERT_EQ(events_[0].data.fd, pipe_fds_[0]);
+  ASSERT_TRUE(events_[0].events & EPOLLIN);
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, TimeoutZeroReturnsImmediately) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);
+
+  // Ensure no events are pending initially by draining the pipe
+  char buffer[10];
+  while (read(pipe_fds_[0], buffer, sizeof(buffer)) > 0)
+    ;  // Drain
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, 0);  // 0ms timeout
+  ASSERT_EQ(nfds, 0) << "epoll_wait with 0 timeout did not return 0: "
+                     << strerror(errno);
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, TimeoutPositiveReturnsAfterTimeout) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);
+
+  // Ensure no events are pending initially
+  char buffer[10];
+  while (read(pipe_fds_[0], buffer, sizeof(buffer)) > 0) {
+  }  // Drain
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kShortTimeoutMs);
+  ASSERT_EQ(nfds, 0)
+      << "epoll_wait with positive timeout did not return 0 (event occurred?): "
+      << strerror(errno);
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, MaxEventsLimitsReturnedEvents) {
+  int p2[2] = {-1, -1};
+  ASSERT_TRUE(CreatePipe(p2, O_NONBLOCK));
+  int pipe2_read_fd = p2[0];
+  int pipe2_write_fd = p2[1];
+
+  AddToEpoll(pipe_fds_[0], EPOLLIN);
+  AddToEpoll(pipe2_read_fd, EPOLLIN);
+
+  char buffer = 'z';
+  ASSERT_EQ(write(pipe_fds_[1], &buffer, 1), 1);
+  ASSERT_EQ(write(pipe2_write_fd, &buffer, 1), 1);
+
+  const int kMaxEventsForThisTest = 1;
+  struct epoll_event single_event[kMaxEventsForThisTest];
+  int nfds = epoll_wait(epfd_, single_event, kMaxEventsForThisTest,
+                        kModerateTimeoutMs);
+  ASSERT_EQ(nfds, kMaxEventsForThisTest)
+      << "epoll_wait did not return max_events: " << strerror(errno);
+
+  RemoveFromEpoll(pipe_fds_[0]);
+  RemoveFromEpoll(pipe2_read_fd);
+
+  if (pipe2_read_fd >= 0) {
+    close(pipe2_read_fd);
+  }
+  if (pipe2_write_fd >= 0) {
+    close(pipe2_write_fd);
+  }
+}
+
+TEST_F(PosixEpollWaitTests, ErrorBadEpfd) {
+  ASSERT_EQ(epoll_wait(kInvalidFd, events_, kMaxEvents, 0), -1);
+  ASSERT_EQ(errno, EBADF);
+}
+
+TEST_F(PosixEpollWaitTests, ErrorInvalidMaxEventsZero) {
+  ASSERT_EQ(epoll_wait(epfd_, events_, 0, 0), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollWaitTests, ErrorInvalidMaxEventsNegative) {
+  ASSERT_EQ(epoll_wait(epfd_, events_, -1, 0), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollWaitTests, ErrorEpfdIsNotEpollFd) {
+  // Use one end of the pipe as a non-epoll fd for epfd argument
+  // (pipe_fds_[1] is valid from SetUp)
+  ASSERT_EQ(epoll_wait(pipe_fds_[1], events_, kMaxEvents, 0), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollWaitTests, WaitForWriteOnReadOnlyPipeEndNeverSignalsWritable) {
+  // pipe_fds_[0] is the read end, inherently not writable.
+  // We expect a timeout, not EPOLLOUT.
+  AddToEpoll(pipe_fds_[0], EPOLLOUT);
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kShortTimeoutMs);
+
+  ASSERT_EQ(nfds, 0)
+      << "epoll_wait should timeout for EPOLLOUT on read-only pipe end. "
+      << "nfds=" << nfds << ", errno=" << (errno ? strerror(errno) : "none")
+      << (nfds > 0 ? ", event=" + std::to_string(events_[0].events) : "");
+  if (nfds > 0) {
+    ASSERT_FALSE(events_[0].events & EPOLLOUT)
+        << "EPOLLOUT incorrectly signalled for read-only pipe end.";
+  }
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, WaitForReadOnWriteOnlyPipeEndNeverSignalsReadable) {
+  // pipe_fds_[1] is the write end, inherently not readable.
+  // We expect a timeout, not EPOLLIN.
+  AddToEpoll(pipe_fds_[1], EPOLLIN);
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kShortTimeoutMs);
+
+  ASSERT_EQ(nfds, 0)
+      << "epoll_wait should timeout for EPOLLIN on write-only pipe end. "
+      << "nfds=" << nfds << ", errno=" << (errno ? strerror(errno) : "none")
+      << (nfds > 0 ? ", event=" + std::to_string(events_[0].events) : "");
+  if (nfds > 0) {
+    ASSERT_FALSE(events_[0].events & EPOLLIN)
+        << "EPOLLIN incorrectly signalled for write-only pipe end.";
+  }
+  RemoveFromEpoll(pipe_fds_[1]);
+}
+
+TEST_F(PosixEpollWaitTests, WaitForWriteOnReadOnlyPipeEndWhenWriteEndClosed) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN | EPOLLOUT | EPOLLHUP);
+
+  ASSERT_NE(pipe_fds_[1], -1);  // Ensure write end is initially valid
+  close(pipe_fds_[1]);
+  pipe_fds_[1] = -1;  // Mark as closed for TearDown logic
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kModerateTimeoutMs);
+  ASSERT_GE(nfds, 0) << "epoll_wait failed: " << strerror(errno);
+
+  bool hup_received = false;
+  bool out_received = false;
+  bool in_received_for_eof = false;
+
+  if (nfds > 0) {
+    ASSERT_EQ(events_[0].data.fd, pipe_fds_[0]);
+    if (events_[0].events & EPOLLIN) {
+      in_received_for_eof = true;
+    }
+    if (events_[0].events & EPOLLHUP) {
+      hup_received = true;
+    }
+    if (events_[0].events & EPOLLOUT) {
+      out_received = true;
+    }
+
+    ASSERT_TRUE(in_received_for_eof || hup_received)
+        << "Expected EPOLLIN (EOF) or EPOLLHUP on read end when write end "
+           "closed. Events: "
+        << events_[0].events;
+    ASSERT_FALSE(out_received)
+        << "EPOLLOUT incorrectly signalled for read-only pipe end when write "
+           "end closed. Events: "
+        << events_[0].events;
+  } else {
+    char c_buf;
+    // Attempt a read to ensure EOF is processed by the kernel for pipe_fds_[0]
+    read(pipe_fds_[0], &c_buf, 1);  // This should see EOF (return 0) or error.
+
+    nfds = epoll_wait(epfd_, events_, kMaxEvents, kModerateTimeoutMs);
+    ASSERT_GT(nfds, 0) << "No event reported on read-end after write-end "
+                          "closed and explicit read attempt. Errno: "
+                       << (errno ? strerror(errno) : "none");
+    if (nfds > 0) {
+      ASSERT_EQ(events_[0].data.fd, pipe_fds_[0]);
+      if (events_[0].events & EPOLLIN) {
+        in_received_for_eof = true;
+      }
+      if (events_[0].events & EPOLLHUP) {
+        hup_received = true;
+      }
+      if (events_[0].events & EPOLLOUT) {
+        out_received = true;
+      }
+
+      // After a read attempt on a pipe with a closed write end,
+      // EPOLLIN (due to EOF) and EPOLLHUP are expected.
+      ASSERT_TRUE(in_received_for_eof && hup_received)
+          << "Expected EPOLLIN (EOF) and EPOLLHUP after read attempt. Events: "
+          << events_[0].events;
+      ASSERT_FALSE(out_received)
+          << "EPOLLOUT incorrectly signalled for read-only pipe end when write "
+             "end closed. Events: "
+          << events_[0].events;
+    }
+  }
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+}  // namespace
+}  // namespace nplb
+}  // namespace starboard
diff --git a/starboard/tools/api_leak_detector/api_leak_detector.py b/starboard/tools/api_leak_detector/api_leak_detector.py
index 7a02a3639c9b..e90f94006242 100755
--- a/starboard/tools/api_leak_detector/api_leak_detector.py
+++ b/starboard/tools/api_leak_detector/api_leak_detector.py
@@ -97,6 +97,10 @@
     'connect',
     'dup',
     'dup2',
+    'epoll_create',
+    'epoll_create1',
+    'epoll_ctl',
+    'epoll_wait'
     'fcntl',
     'free',
     'freeaddrinfo',


Reviews:
user: login: andrewsavage1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T18:18:53Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T18:26:45Z
user: login: andrewsavage1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-12T06:25:35Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T16:09:37Z
user: login: yell0wd0g
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T21:21:38Z
user: login: yell0wd0g
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T21:30:04Z
user: login: yell0wd0g
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T21:32:24Z
user: login: yell0wd0g
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T21:34:00Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T16:10:54Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T16:41:41Z
user: login: andrewsavage1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T03:43:37Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T16:57:39Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T17:43:43Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T17:43:59Z
user: login: andrewsavage1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T01:19:17Z
user: login: yell0wd0g
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T02:38:23Z
user: login: yell0wd0g
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T02:39:08Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T17:42:31Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T16:17:23Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T18:39:28Z
user: login: y4vor
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T00:35:29Z
user: login: yell0wd0g
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T17:06:12Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T17:13:42Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T17:15:07Z
user: login: yell0wd0g
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T17:17:24Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T17:33:20Z
user: login: yell0wd0g
body: Many changes needed still.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T16:17:08Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T16:53:43Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T16:55:16Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T17:09:31Z
user: login: yell0wd0g
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T17:15:08Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T18:49:26Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T18:50:12Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T20:18:04Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T20:18:22Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T20:19:18Z
user: login: yell0wd0g
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T00:01:21Z
user: login: yell0wd0g
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T00:07:01Z
user: login: yell0wd0g
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T00:07:16Z
user: login: yell0wd0g
body: Another round of comments.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-01T16:46:29Z
user: login: yell0wd0g
body: A few comments to iterate on.
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T21:42:14Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T15:47:22Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T16:44:03Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T17:02:29Z
user: login: andrewsavage1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T17:09:46Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T17:20:23Z
user: login: yell0wd0g
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T18:01:56Z
user: login: andrewsavage1
body: Just style nits, otherwise lgtm
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T18:23:45Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T18:36:12Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T20:32:25Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T20:32:32Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T20:32:41Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T20:32:50Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T20:32:56Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T20:33:22Z
user: login: madhurajayaraman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T20:33:36Z
user: login: yell0wd0g
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T20:58:01Z
user: login: yell0wd0g
body: LGTM
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T21:03:47Z
user: login: jellefoks
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-23T22:23:17Z

Review comments:
diff_hunk: @@ -0,0 +1,160 @@
+// Copyright 2015 The Cobalt Authors. All Rights Reserved.
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: andrewsavage1
body: I think this year is a little off!
created_at: 2025-04-10T18:18:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+// Copyright 2015 The Cobalt Authors. All Rights Reserved.
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: ooh maybe just a bit
created_at: 2025-04-10T18:26:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class SbPosixEpollTest : public ::testing::TestWithParam<int> {
+ public:
+  int GetAddressType() { return GetParam(); }
+};
+
+TEST(PosixEpollAddRemoveTest, SunnyDay) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_TRUE(socket >= 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+  int add_val = epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev);
+  EXPECT_TRUE(add_val == 0);
+
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_DEL, socket, &epev) == 0);
+
+  EXPECT_TRUE(close(socket) == 0);
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, SunnyDayMany) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  const int kMany = kSbFileMaxOpen;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: andrewsavage1
body: Do we expect opening sockets up to the limit to have some flakiness?
created_at: 2025-04-12T03:20:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class SbPosixEpollTest : public ::testing::TestWithParam<int> {
+ public:
+  int GetAddressType() { return GetParam(); }
+};
+
+TEST(PosixEpollAddRemoveTest, SunnyDay) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: andrewsavage1
body: nit: I'd prefer having the variable name be different from the function name (here and other cases of naming the variable "socket" below)
created_at: 2025-04-12T03:21:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class SbPosixEpollTest : public ::testing::TestWithParam<int> {
+ public:
+  int GetAddressType() { return GetParam(); }
+};
+
+TEST(PosixEpollAddRemoveTest, SunnyDay) {
+  int epfd = epoll_create(1);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: andrewsavage1
body: It looks like we're creating an epfd and closing it in every unit test here—if we're fine using the same epfd instance every time, we could create it in a constructor, otherwise we should probably create it in the SetUp override
created_at: 2025-04-12T03:25:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class SbPosixEpollTest : public ::testing::TestWithParam<int> {
+ public:
+  int GetAddressType() { return GetParam(); }
+};
+
+TEST(PosixEpollAddRemoveTest, SunnyDay) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_TRUE(socket >= 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+  int add_val = epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev);
+  EXPECT_TRUE(add_val == 0);
+
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_DEL, socket, &epev) == 0);
+
+  EXPECT_TRUE(close(socket) == 0);
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, SunnyDayMany) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_TRUE(sockets[i] >= 0);
+    EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev) == 0);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_TRUE(close(sockets[i]) == 0);
+  }
+
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, RainyDayAddToSameWaiter) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_TRUE(socket >= 0);
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+
+  // First add should succeed.
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev) == 0);
+
+  // Second add should fail.
+  EXPECT_FALSE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev) == 0);
+
+  // Remove should succeed.
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_DEL, socket, &epev) == 0);
+
+  // Add after remove should succeed.
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev) == 0);
+
+  // Second add after remove should fail.
+  EXPECT_FALSE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev) == 0);
+
+  EXPECT_TRUE(close(socket) == 0);
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, RainyDayInvalidSocket) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+
+  EXPECT_FALSE(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev) == 0);
+
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, RainyDayNoInterest) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_TRUE(socket >= 0);
+
+  EXPECT_FALSE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, nullptr) == 0);
+
+  EXPECT_TRUE(close(socket) == 0);
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, RainyDayRemoveSocket) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_TRUE(socket >= 0);
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+
+  // First remove should fail.
+  EXPECT_FALSE(epoll_ctl(epfd, EPOLL_CTL_DEL, socket, &epev) == 0);
+
+  // First add should succeed.
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev) == 0);
+
+  // Remove after add should succeed.
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_DEL, socket, &epev) == 0);
+
+  // Remove after remove should succeed.
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: andrewsavage1
body: The comment doens't match the EXPECT call here—I assume the comment is wrong and the remove after remove should fail
created_at: 2025-04-12T03:28:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class SbPosixEpollTest : public ::testing::TestWithParam<int> {
+ public:
+  int GetAddressType() { return GetParam(); }
+};
+
+TEST(PosixEpollAddRemoveTest, SunnyDay) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: andrewsavage1
body: Throughout this suite, use EXPECT_* macros for number comparison like EXPECT_GT here
created_at: 2025-04-12T03:32:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class SbPosixEpollTest : public ::testing::TestWithParam<int> {
+ public:
+  int GetAddressType() { return GetParam(); }
+};
+
+TEST(PosixEpollAddRemoveTest, SunnyDay) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_TRUE(socket >= 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+  int add_val = epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev);
+  EXPECT_TRUE(add_val == 0);
+
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_DEL, socket, &epev) == 0);
+
+  EXPECT_TRUE(close(socket) == 0);
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, SunnyDayMany) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_TRUE(sockets[i] >= 0);
+    EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev) == 0);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_TRUE(close(sockets[i]) == 0);
+  }
+
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, RainyDayAddToSameWaiter) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_TRUE(socket >= 0);
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+
+  // First add should succeed.
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev) == 0);
+
+  // Second add should fail.
+  EXPECT_FALSE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev) == 0);
+
+  // Remove should succeed.
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_DEL, socket, &epev) == 0);
+
+  // Add after remove should succeed.
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev) == 0);
+
+  // Second add after remove should fail.
+  EXPECT_FALSE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev) == 0);
+
+  EXPECT_TRUE(close(socket) == 0);
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, RainyDayInvalidSocket) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+
+  EXPECT_FALSE(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev) == 0);
+
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, RainyDayNoInterest) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_TRUE(socket >= 0);
+
+  EXPECT_FALSE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, nullptr) == 0);
+
+  EXPECT_TRUE(close(socket) == 0);
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, RainyDayRemoveSocket) {
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: andrewsavage1
body: I feel this test and RainyDayAddToSameWaiter are testing too much and are doing so because there's so much setup/teardown work in the functions—I suggest putting them in a new suite, and have SetUp/TearDown functions that do everything but the actual EXPECT_ calls we care about, that way the tests can just look like

```
TEST(MySuite, FirstRemoveFails) {
  EXPECT_NE(epoll_ctl(epfd, EPOLL_CTL_DEL, socket, &epev), 0);
}

TEST(MySuite, SecondAddFails) {
  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev), 0);
  EXPECT_NE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev), 0);
}
```
etc.

I think it'd be pretty simple to implement and simpler to read but if there's pushback I'm fine with doing it this way, it's already implemented 
created_at: 2025-04-12T03:42:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class SbPosixEpollTest : public ::testing::TestWithParam<int> {
+ public:
+  int GetAddressType() { return GetParam(); }
+};
+
+TEST(PosixEpollAddRemoveTest, SunnyDay) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_TRUE(socket >= 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+  int add_val = epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev);
+  EXPECT_TRUE(add_val == 0);
+
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_DEL, socket, &epev) == 0);
+
+  EXPECT_TRUE(close(socket) == 0);
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, SunnyDayMany) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  const int kMany = kSbFileMaxOpen;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: This is from our previous socket waiter test which wasn't flaky, so I assume not -- in the event that this does have flakiness we can drop the number a little.
created_at: 2025-04-14T16:09:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class SbPosixEpollTest : public ::testing::TestWithParam<int> {
+ public:
+  int GetAddressType() { return GetParam(); }
+};
+
+TEST(PosixEpollAddRemoveTest, SunnyDay) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: +1 and also same applies to ASSERT_* (l.38). This is for better semantics, but also for better outputs when/if the assertion fail.
created_at: 2025-04-14T21:21:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class SbPosixEpollTest : public ::testing::TestWithParam<int> {
+ public:
+  int GetAddressType() { return GetParam(); }
+};
+
+TEST(PosixEpollAddRemoveTest, SunnyDay) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_TRUE(socket >= 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+  int add_val = epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev);
+  EXPECT_TRUE(add_val == 0);
+
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_DEL, socket, &epev) == 0);
+
+  EXPECT_TRUE(close(socket) == 0);
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, SunnyDayMany) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_TRUE(sockets[i] >= 0);
+    EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev) == 0);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_TRUE(close(sockets[i]) == 0);
+  }
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: nit: Always prefer range-based loops if the index |i| is not needed, i.e.:
```
for (auto& socket_descriptor : sockets) {
  socket_descriptor = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  ASSERT_TRUE(sockets[i]);
  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev));
}

for (const auto& socket_descriptor : sockets) {
  EXPECT_TRUE(close(socket_descriptor));
}
```

Arguably, comparing an integer with a EXPECT/ASSERT_TRUE is not semantically, correct; if you prefer to compare as integers (e.g. `ASSERT_GT(bla, 0);` then you need to give a name to that 0, e.g. `constexpr int kSuccess = 0;`) or similar.

created_at: 2025-04-14T21:30:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class SbPosixEpollTest : public ::testing::TestWithParam<int> {
+ public:
+  int GetAddressType() { return GetParam(); }
+};
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: Is this class needed? None of the test cases below use it.
created_at: 2025-04-14T21:32:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class SbPosixEpollTest : public ::testing::TestWithParam<int> {
+ public:
+  int GetAddressType() { return GetParam(); }
+};
+
+TEST(PosixEpollAddRemoveTest, SunnyDay) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_TRUE(socket >= 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+  int add_val = epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev);
+  EXPECT_TRUE(add_val == 0);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: In cases like this where you call a function and then leave an assertion or check on the return value, consider adding ` << strerror(errno);` to give more information on what went wrong.
created_at: 2025-04-14T21:33:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class SbPosixEpollTest : public ::testing::TestWithParam<int> {
+ public:
+  int GetAddressType() { return GetParam(); }
+};
+
+TEST(PosixEpollAddRemoveTest, SunnyDay) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_TRUE(socket >= 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+  int add_val = epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev);
+  EXPECT_TRUE(add_val == 0);
+
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_DEL, socket, &epev) == 0);
+
+  EXPECT_TRUE(close(socket) == 0);
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, SunnyDayMany) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_TRUE(sockets[i] >= 0);
+    EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev) == 0);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_TRUE(close(sockets[i]) == 0);
+  }
+
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, RainyDayAddToSameWaiter) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_TRUE(socket >= 0);
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+
+  // First add should succeed.
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev) == 0);
+
+  // Second add should fail.
+  EXPECT_FALSE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev) == 0);
+
+  // Remove should succeed.
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_DEL, socket, &epev) == 0);
+
+  // Add after remove should succeed.
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev) == 0);
+
+  // Second add after remove should fail.
+  EXPECT_FALSE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev) == 0);
+
+  EXPECT_TRUE(close(socket) == 0);
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, RainyDayInvalidSocket) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+
+  EXPECT_FALSE(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev) == 0);
+
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, RainyDayNoInterest) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_TRUE(socket >= 0);
+
+  EXPECT_FALSE(epoll_ctl(epfd, EPOLL_CTL_ADD, socket, nullptr) == 0);
+
+  EXPECT_TRUE(close(socket) == 0);
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, RainyDayRemoveSocket) {
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: Changed
created_at: 2025-04-15T16:10:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,160 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class SbPosixEpollTest : public ::testing::TestWithParam<int> {
+ public:
+  int GetAddressType() { return GetParam(); }
+};
+
+TEST(PosixEpollAddRemoveTest, SunnyDay) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_TRUE(socket >= 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+  int add_val = epoll_ctl(epfd, EPOLL_CTL_ADD, socket, &epev);
+  EXPECT_TRUE(add_val == 0);
+
+  EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_DEL, socket, &epev) == 0);
+
+  EXPECT_TRUE(close(socket) == 0);
+  EXPECT_TRUE(close(epfd) == 0);
+}
+
+TEST(PosixEpollAddRemoveTest, SunnyDayMany) {
+  int epfd = epoll_create(1);
+  EXPECT_TRUE(epfd > 0);
+
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  epoll_event epev;
+  epev.events = EPOLLIN | EPOLLOUT;
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_TRUE(sockets[i] >= 0);
+    EXPECT_TRUE(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev) == 0);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_TRUE(close(sockets[i]) == 0);
+  }
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: I'd tried to change the loops earlier from a regular for loop to a for each loop and got weird behaviour, so I'm keeping the `for i` structure for now.
Given that most posix functions exit successfully with return code 0, the `ASSERT_TRUE(exp, 0)` structure exists all over our tests (and code).  IMO, tests should reflect production code as closely as possible. I can modify across the board so we have consistency, but I don't think it necessarily makes sense to return `kSuccess` in one set of tests without consistency.
created_at: 2025-04-15T16:41:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,108 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    EXPECT_GT(epfd, 0);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(socket_fd, 0);
+
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0);
+    EXPECT_EQ(close(epfd), 0);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  ASSERT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  ASSERT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayAddToSameWaiter) {
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: andrewsavage1
body: What do you think about breaking this into many small tests? It seems like it could be broken into 
1. Test that just a remove fails
2. Test that first add succeeds, second fails
3. Test that add succeeds, remove succeeds, second remove fails
(we could add more if you think more are important)

It seems like those 3 cover the basic cases here, but this test does slightly more in that it does them all in tandem (which will test a separate case, but also potentially hide failures from the more basic cases)
created_at: 2025-04-16T03:40:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,108 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    EXPECT_GT(epfd, 0);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(socket_fd, 0);
+
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0);
+    EXPECT_EQ(close(epfd), 0);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  ASSERT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  ASSERT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0);
+  }
+
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: andrewsavage1
body: Outside of the response from calling `::socket` is there a way to test that the sockets actually exist?
created_at: 2025-04-16T03:41:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,108 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    EXPECT_GT(epfd, 0);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: andrewsavage1
body: I'm confused about when you're using EXPECT vs ASSERT in these tests—I would've expected ASSERT to be used in the SetUp calls, as the actual test case couldn't run without that setup, and the test cases to mostly use EXPECT calls
created_at: 2025-04-16T03:43:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,108 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    EXPECT_GT(epfd, 0);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: No you're totally right I did the wrong find + replace earlier, will fix.
created_at: 2025-04-16T16:57:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,108 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    EXPECT_GT(epfd, 0);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(socket_fd, 0);
+
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0);
+    EXPECT_EQ(close(epfd), 0);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  ASSERT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  ASSERT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0);
+  }
+
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: No, we have sockets tests that verify the functionality of the socket API. The return value should be enough to indicate that the socket exists or not.
There are also more involved tests with epoll in base_unittests added here that I'm bringing in from upstream: https://github.com/youtube/cobalt/pull/5420


created_at: 2025-04-16T17:43:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,108 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    EXPECT_GT(epfd, 0);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(socket_fd, 0);
+
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0);
+    EXPECT_EQ(close(epfd), 0);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  ASSERT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  ASSERT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayAddToSameWaiter) {
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: yep adding more.
created_at: 2025-04-16T17:43:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,108 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    EXPECT_GT(epfd, 0);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(socket_fd, 0);
+
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0);
+    EXPECT_EQ(close(epfd), 0);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  ASSERT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  ASSERT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0);
+  }
+
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: andrewsavage1
body: Makes sense!
created_at: 2025-04-17T01:19:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,220 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: In Chromium member variables have an underscore at the end of the name, e.g. `epfd_;`.
created_at: 2025-04-17T02:38:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,220 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: Why is there a SunnyDay/RainyDay prefix on the test cases?
created_at: 2025-04-17T02:39:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,220 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+#define MAX_EVENTS 10
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: nit: `#define` is C90, C++ uses `constexpr`, this should be `constexpr size_t kMaxEvents = 10;`. 
created_at: 2025-04-17T02:41:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,220 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+#define MAX_EVENTS 10
+  struct epoll_event ev, events[MAX_EVENTS];
+  int listen_sock, conn_sock, nfds;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0);
+
+  // bind socket with local address
+  sockaddr_in6 address = {};
+  EXPECT_TRUE(
+      PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+      PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+  address.sin6_port = htons(PosixGetPortNumberForTests());
+
+  socklen_t add_len = sizeof(struct sockaddr_in);
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  if (epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
+    perror("epoll_ctl: listen_sock");
+    exit(EXIT_FAILURE);
+  }
+
+  // placeholder value in for loop to avoid infinite loop
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: nit: Capitalize `// Placeholder...`
created_at: 2025-04-17T02:41:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,220 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+#define MAX_EVENTS 10
+  struct epoll_event ev, events[MAX_EVENTS];
+  int listen_sock, conn_sock, nfds;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0);
+
+  // bind socket with local address
+  sockaddr_in6 address = {};
+  EXPECT_TRUE(
+      PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+      PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+  address.sin6_port = htons(PosixGetPortNumberForTests());
+
+  socklen_t add_len = sizeof(struct sockaddr_in);
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  if (epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
+    perror("epoll_ctl: listen_sock");
+    exit(EXIT_FAILURE);
+  }
+
+  // placeholder value in for loop to avoid infinite loop
+  for (int i = 0; i < 5; i++) {
+    nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
+    if (nfds == -1) {
+      perror("epoll_wait");
+      exit(EXIT_FAILURE);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: 1. Don't use `perror`, use `LOG(ERROR)` or similar.
2. Don't use exit, since that'll terminate the binary, preventing other tests from running/finishing. Instead use ASSERT or `FAIL()` (https://google.github.io/googletest/reference/assertions.html#success-failure)
created_at: 2025-04-17T02:43:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,220 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+#define MAX_EVENTS 10
+  struct epoll_event ev, events[MAX_EVENTS];
+  int listen_sock, conn_sock, nfds;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0);
+
+  // bind socket with local address
+  sockaddr_in6 address = {};
+  EXPECT_TRUE(
+      PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+      PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+  address.sin6_port = htons(PosixGetPortNumberForTests());
+
+  socklen_t add_len = sizeof(struct sockaddr_in);
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  if (epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
+    perror("epoll_ctl: listen_sock");
+    exit(EXIT_FAILURE);
+  }
+
+  // placeholder value in for loop to avoid infinite loop
+  for (int i = 0; i < 5; i++) {
+    nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
+    if (nfds == -1) {
+      perror("epoll_wait");
+      exit(EXIT_FAILURE);
+    }
+
+    for (int n = 0; n < nfds; ++n) {
+      if (events[n].data.fd == listen_sock) {
+        conn_sock =
+            accept(listen_sock, reinterpret_cast<struct sockaddr*>(&address),
+                   &add_len);
+        if (conn_sock == -1) {
+          perror("accept");
+          exit(EXIT_FAILURE);
+        }
+        // set non-blocking
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: nit: Capitalize `set`
created_at: 2025-04-17T02:43:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,220 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+#define MAX_EVENTS 10
+  struct epoll_event ev, events[MAX_EVENTS];
+  int listen_sock, conn_sock, nfds;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0);
+
+  // bind socket with local address
+  sockaddr_in6 address = {};
+  EXPECT_TRUE(
+      PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+      PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+  address.sin6_port = htons(PosixGetPortNumberForTests());
+
+  socklen_t add_len = sizeof(struct sockaddr_in);
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  if (epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
+    perror("epoll_ctl: listen_sock");
+    exit(EXIT_FAILURE);
+  }
+
+  // placeholder value in for loop to avoid infinite loop
+  for (int i = 0; i < 5; i++) {
+    nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
+    if (nfds == -1) {
+      perror("epoll_wait");
+      exit(EXIT_FAILURE);
+    }
+
+    for (int n = 0; n < nfds; ++n) {
+      if (events[n].data.fd == listen_sock) {
+        conn_sock =
+            accept(listen_sock, reinterpret_cast<struct sockaddr*>(&address),
+                   &add_len);
+        if (conn_sock == -1) {
+          perror("accept");
+          exit(EXIT_FAILURE);
+        }
+        // set non-blocking
+        fcntl(conn_sock, F_SETFL, O_NONBLOCK);
+        ev.events = EPOLLIN | EPOLLET;
+        ev.data.fd = conn_sock;
+        if (epoll_ctl(epfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) {
+          perror("epoll_ctl: conn_sock");
+          exit(EXIT_FAILURE);
+        }
+      } else {
+        // do something
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: nit: Capitalize comment. Should we do something here?
created_at: 2025-04-17T02:44:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,220 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: If you look at the other tests in nplb as well, that's the standard for do we expect this to test successful behaviour or edge cases that we expect to fail. rainy day would be invalid inputs, empty objects, etc, sunny day would be the happy path execution.
created_at: 2025-04-21T17:42:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,220 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: Gotcha thanks. If this is not legacy code I'd argue for abandoning that practice. The test name say "Fails" so sunny/rainy day is superfluous and not a common idiom.
created_at: 2025-04-21T17:49:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,220 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: I don't think that's a convention we follow in our tests yet - I can follow up w a change to follow chromium conventions across the board but I'd rather have consistency across cobalt that we then change to be like chromium instead of a single file that follows chromium.
created_at: 2025-04-22T16:17:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,220 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: Doing the change all at once makes sense to me. Can we leave a TODO()+bug ?
created_at: 2025-04-22T16:32:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,220 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: b/412696447
created_at: 2025-04-22T18:39:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,235 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+#define MAX_EVENTS 10
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: y4vor
body: It is a little bit strange to hide those defines here in the middle of the class.
Maybe use `constexpr int kMaxEvents = 10` and move it above the class. Same for `kMaxBuf`.
created_at: 2025-04-24T00:29:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,235 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+#define MAX_EVENTS 10
+#define MAXBUF 1024
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[MAX_EVENTS];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // bind socket with local address
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 5 second timeout for wait
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 5000);
+  // expect nothing to be ready since we're not doing anything
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+  struct sockaddr_in dest;
+
+  char buffer[MAXBUF];
+  struct epoll_event events[MAX_EVENTS];
+  int i, num_ready;
+
+  // Add socket to epoll
+  epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev);
+
+  if (connect(socket_fd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+    EXPECT_EQ(errno, EINPROGRESS) << "Connection failed, not in progress";
+  }
+
+  // Wait for socket to connect
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 1000);
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      printf("Socket %d connected\n", events[i].data.fd);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: y4vor
body: use SB_LOG(INFO) instead of printf. At least for now as we still rely on the low level `SbLog`.
created_at: 2025-04-24T00:32:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,245 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+#define MAX_EVENTS 10
+#define MAXBUF 1024
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[MAX_EVENTS];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // bind socket with local address
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 5 second timeout for wait
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 5000);
+  // expect nothing to be ready since we're not doing anything
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+  struct sockaddr_in dest;
+
+  char buffer[MAXBUF];
+  struct epoll_event events[MAX_EVENTS];
+  int i, num_ready;
+
+  // Add socket to epoll
+  epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev);
+
+  if (connect(socket_fd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+    EXPECT_EQ(errno, EINPROGRESS) << "Connection failed, not in progress";
+  }
+
+  // Wait for socket to connect
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 1000);
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      printf("Socket %d connected\n", events[i].data.fd);
+    }
+  }
+
+  EXPECT_GT(num_ready, 0) << "No sockets connected after wait";
+  int bytes_received = 0;
+
+  char* send_buf = new char[MAXBUF];
+  char* receive_buf = new char[MAXBUF];
+  for (int i = 0; i < MAXBUF; ++i) {
+    send_buf[i] = static_cast<char>(i);
+  }
+  memset(receive_buf, 0, MAXBUF);
+  int bytes_sent = sendto(socket_fd, send_buf, MAXBUF, kSendFlags, NULL, 0);
+
+  // Wait to receive data from connected socket
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 1000);
+  bool data_recieved = false;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: nit: s/data_recieved/data_received/
created_at: 2025-04-24T23:47:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,245 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+#define MAX_EVENTS 10
+#define MAXBUF 1024
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[MAX_EVENTS];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // bind socket with local address
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 5 second timeout for wait
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 5000);
+  // expect nothing to be ready since we're not doing anything
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+  struct sockaddr_in dest;
+
+  char buffer[MAXBUF];
+  struct epoll_event events[MAX_EVENTS];
+  int i, num_ready;
+
+  // Add socket to epoll
+  epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev);
+
+  if (connect(socket_fd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+    EXPECT_EQ(errno, EINPROGRESS) << "Connection failed, not in progress";
+  }
+
+  // Wait for socket to connect
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 1000);
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      printf("Socket %d connected\n", events[i].data.fd);
+    }
+  }
+
+  EXPECT_GT(num_ready, 0) << "No sockets connected after wait";
+  int bytes_received = 0;
+
+  char* send_buf = new char[MAXBUF];
+  char* receive_buf = new char[MAXBUF];
+  for (int i = 0; i < MAXBUF; ++i) {
+    send_buf[i] = static_cast<char>(i);
+  }
+  memset(receive_buf, 0, MAXBUF);
+  int bytes_sent = sendto(socket_fd, send_buf, MAXBUF, kSendFlags, NULL, 0);
+
+  // Wait to receive data from connected socket
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 1000);
+  bool data_recieved = false;
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      SB_LOG(INFO) << "Socket " << events[i].data.fd << " receiving data";
+      memset(buffer, 0, MAXBUF);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: Is this used?
created_at: 2025-04-28T17:05:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,220 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+#define MAX_EVENTS 10
+  struct epoll_event ev, events[MAX_EVENTS];
+  int listen_sock, conn_sock, nfds;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0);
+
+  // bind socket with local address
+  sockaddr_in6 address = {};
+  EXPECT_TRUE(
+      PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+      PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+  address.sin6_port = htons(PosixGetPortNumberForTests());
+
+  socklen_t add_len = sizeof(struct sockaddr_in);
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  if (epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
+    perror("epoll_ctl: listen_sock");
+    exit(EXIT_FAILURE);
+  }
+
+  // placeholder value in for loop to avoid infinite loop
+  for (int i = 0; i < 5; i++) {
+    nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
+    if (nfds == -1) {
+      perror("epoll_wait");
+      exit(EXIT_FAILURE);
+    }
+
+    for (int n = 0; n < nfds; ++n) {
+      if (events[n].data.fd == listen_sock) {
+        conn_sock =
+            accept(listen_sock, reinterpret_cast<struct sockaddr*>(&address),
+                   &add_len);
+        if (conn_sock == -1) {
+          perror("accept");
+          exit(EXIT_FAILURE);
+        }
+        // set non-blocking
+        fcntl(conn_sock, F_SETFL, O_NONBLOCK);
+        ev.events = EPOLLIN | EPOLLET;
+        ev.data.fd = conn_sock;
+        if (epoll_ctl(epfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) {
+          perror("epoll_ctl: conn_sock");
+          exit(EXIT_FAILURE);
+        }
+      } else {
+        // do something
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: leftover from when i was getting help on the tests and needed to show jelle what i was doing!
created_at: 2025-04-28T17:13:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,245 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+#define MAX_EVENTS 10
+#define MAXBUF 1024
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[MAX_EVENTS];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // bind socket with local address
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 5 second timeout for wait
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 5000);
+  // expect nothing to be ready since we're not doing anything
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+  struct sockaddr_in dest;
+
+  char buffer[MAXBUF];
+  struct epoll_event events[MAX_EVENTS];
+  int i, num_ready;
+
+  // Add socket to epoll
+  epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev);
+
+  if (connect(socket_fd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+    EXPECT_EQ(errno, EINPROGRESS) << "Connection failed, not in progress";
+  }
+
+  // Wait for socket to connect
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 1000);
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      printf("Socket %d connected\n", events[i].data.fd);
+    }
+  }
+
+  EXPECT_GT(num_ready, 0) << "No sockets connected after wait";
+  int bytes_received = 0;
+
+  char* send_buf = new char[MAXBUF];
+  char* receive_buf = new char[MAXBUF];
+  for (int i = 0; i < MAXBUF; ++i) {
+    send_buf[i] = static_cast<char>(i);
+  }
+  memset(receive_buf, 0, MAXBUF);
+  int bytes_sent = sendto(socket_fd, send_buf, MAXBUF, kSendFlags, NULL, 0);
+
+  // Wait to receive data from connected socket
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 1000);
+  bool data_recieved = false;
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      SB_LOG(INFO) << "Socket " << events[i].data.fd << " receiving data";
+      memset(buffer, 0, MAXBUF);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: What do you mean?

created_at: 2025-04-28T17:15:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,245 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+#define MAX_EVENTS 10
+#define MAXBUF 1024
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[MAX_EVENTS];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // bind socket with local address
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 5 second timeout for wait
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 5000);
+  // expect nothing to be ready since we're not doing anything
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+  struct sockaddr_in dest;
+
+  char buffer[MAXBUF];
+  struct epoll_event events[MAX_EVENTS];
+  int i, num_ready;
+
+  // Add socket to epoll
+  epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev);
+
+  if (connect(socket_fd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+    EXPECT_EQ(errno, EINPROGRESS) << "Connection failed, not in progress";
+  }
+
+  // Wait for socket to connect
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 1000);
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      printf("Socket %d connected\n", events[i].data.fd);
+    }
+  }
+
+  EXPECT_GT(num_ready, 0) << "No sockets connected after wait";
+  int bytes_received = 0;
+
+  char* send_buf = new char[MAXBUF];
+  char* receive_buf = new char[MAXBUF];
+  for (int i = 0; i < MAXBUF; ++i) {
+    send_buf[i] = static_cast<char>(i);
+  }
+  memset(receive_buf, 0, MAXBUF);
+  int bytes_sent = sendto(socket_fd, send_buf, MAXBUF, kSendFlags, NULL, 0);
+
+  // Wait to receive data from connected socket
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 1000);
+  bool data_recieved = false;
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      SB_LOG(INFO) << "Socket " << events[i].data.fd << " receiving data";
+      memset(buffer, 0, MAXBUF);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: I see a definition of `char buffer[kMaxBuf];` (in l.199 in my view), and here I see it being cleared, but I don't see this `buffer` being used in any meaningful way?
created_at: 2025-04-28T17:17:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,245 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+#define MAX_EVENTS 10
+#define MAXBUF 1024
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[MAX_EVENTS];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // bind socket with local address
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 5 second timeout for wait
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 5000);
+  // expect nothing to be ready since we're not doing anything
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+  struct sockaddr_in dest;
+
+  char buffer[MAXBUF];
+  struct epoll_event events[MAX_EVENTS];
+  int i, num_ready;
+
+  // Add socket to epoll
+  epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev);
+
+  if (connect(socket_fd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+    EXPECT_EQ(errno, EINPROGRESS) << "Connection failed, not in progress";
+  }
+
+  // Wait for socket to connect
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 1000);
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      printf("Socket %d connected\n", events[i].data.fd);
+    }
+  }
+
+  EXPECT_GT(num_ready, 0) << "No sockets connected after wait";
+  int bytes_received = 0;
+
+  char* send_buf = new char[MAXBUF];
+  char* receive_buf = new char[MAXBUF];
+  for (int i = 0; i < MAXBUF; ++i) {
+    send_buf[i] = static_cast<char>(i);
+  }
+  memset(receive_buf, 0, MAXBUF);
+  int bytes_sent = sendto(socket_fd, send_buf, MAXBUF, kSendFlags, NULL, 0);
+
+  // Wait to receive data from connected socket
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 1000);
+  bool data_recieved = false;
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      SB_LOG(INFO) << "Socket " << events[i].data.fd << " receiving data";
+      memset(buffer, 0, MAXBUF);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: You are completely right I changed the variable names in the middle for clarity and missed one
created_at: 2025-04-28T17:33:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,220 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    socket_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: I cannot see the `//TODO(b/412696447): Correct member variable style.` I was expecting.
created_at: 2025-04-29T16:05:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: nit: `constexpr`.
created_at: 2025-04-29T16:05:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: If `sockets` doesn't grow/shrink, consider `std::array<>`.
created_at: 2025-04-29T16:06:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: From the documentation of `socket()`: `On success, a file descriptor for the new socket is returned.  On error, -1 is returned, and [errno](https://man7.org/linux/man-pages/man3/errno.3.html) is set to indicate the error.`. So what about adding here ` << strerror(errno);`?
created_at: 2025-04-29T16:07:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[kMaxEvents];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: nit/question: I'm surprised the compiler didn't complain that `on` is a const int and yet it was used to leave the result of an operation in l.172.
created_at: 2025-04-29T16:08:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[kMaxEvents];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: nit: Capitalize and add period add the end throughout. (Here, l.169, l.175...)
created_at: 2025-04-29T16:09:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[kMaxEvents];
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: In C90, you had to define variables at the top of the scope. Since this is C++, move them as close as possible to their use site, e.g. for `ev`, to l.183. Please do this throughout.


And use designated initializers if possible (https://en.cppreference.com/w/cpp/language/aggregate_initialization#Designated_initializers).
created_at: 2025-04-29T16:10:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,235 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+#define MAX_EVENTS 10
+#define MAXBUF 1024
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[MAX_EVENTS];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // bind socket with local address
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 5 second timeout for wait
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 5000);
+  // expect nothing to be ready since we're not doing anything
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+  struct sockaddr_in dest;
+
+  char buffer[MAXBUF];
+  struct epoll_event events[MAX_EVENTS];
+  int i, num_ready;
+
+  // Add socket to epoll
+  epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev);
+
+  if (connect(socket_fd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+    EXPECT_EQ(errno, EINPROGRESS) << "Connection failed, not in progress";
+  }
+
+  // Wait for socket to connect
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 1000);
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      printf("Socket %d connected\n", events[i].data.fd);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: I'm still seeing `printf()`, am I in the wrong patchset?
created_at: 2025-04-29T16:11:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[kMaxEvents];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // bind socket with local address
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 5 second timeout for wait
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 5000);
+  // expect nothing to be ready since we're not doing anything
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+  struct sockaddr_in dest;
+  struct epoll_event events[kMaxEvents];
+  int i, num_ready;
+
+  // Add socket to epoll
+  epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev);
+
+  if (connect(socket_fd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+    EXPECT_EQ(errno, EINPROGRESS) << "Connection failed, not in progress";
+  }
+
+  // Wait for socket to connect
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 1000);
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      printf("Socket %d connected\n", events[i].data.fd);
+    }
+  }
+
+  EXPECT_GT(num_ready, 0) << "No sockets connected after wait";
+  int bytes_received = 0;
+
+  char* send_buf = new char[kMaxBuf];
+  char* receive_buf = new char[kMaxBuf];
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: Seeing that this PR is not ready and you'll have to fix a number of things, please use here `std::array<>`, and also don't use a for loop to fill it up, instead use   `std::iota(send_buf.begin(), send_buf.end(), 1); // Fill with 1, 2, 3, 4, 5...`. 

created_at: 2025-04-29T16:13:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[kMaxEvents];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // bind socket with local address
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 5 second timeout for wait
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 5000);
+  // expect nothing to be ready since we're not doing anything
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+  struct sockaddr_in dest;
+  struct epoll_event events[kMaxEvents];
+  int i, num_ready;
+
+  // Add socket to epoll
+  epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev);
+
+  if (connect(socket_fd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+    EXPECT_EQ(errno, EINPROGRESS) << "Connection failed, not in progress";
+  }
+
+  // Wait for socket to connect
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 1000);
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      printf("Socket %d connected\n", events[i].data.fd);
+    }
+  }
+
+  EXPECT_GT(num_ready, 0) << "No sockets connected after wait";
+  int bytes_received = 0;
+
+  char* send_buf = new char[kMaxBuf];
+  char* receive_buf = new char[kMaxBuf];
+  for (int i = 0; i < kMaxBuf; ++i) {
+    send_buf[i] = static_cast<char>(i);
+  }
+  memset(receive_buf, 0, kMaxBuf);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: After you move to using `std::array<>`, here becomes `receive_buf.fill(0);` .
created_at: 2025-04-29T16:14:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[kMaxEvents];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // bind socket with local address
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 5 second timeout for wait
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 5000);
+  // expect nothing to be ready since we're not doing anything
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+  struct sockaddr_in dest;
+  struct epoll_event events[kMaxEvents];
+  int i, num_ready;
+
+  // Add socket to epoll
+  epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev);
+
+  if (connect(socket_fd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+    EXPECT_EQ(errno, EINPROGRESS) << "Connection failed, not in progress";
+  }
+
+  // Wait for socket to connect
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 1000);
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      printf("Socket %d connected\n", events[i].data.fd);
+    }
+  }
+
+  EXPECT_GT(num_ready, 0) << "No sockets connected after wait";
+  int bytes_received = 0;
+
+  char* send_buf = new char[kMaxBuf];
+  char* receive_buf = new char[kMaxBuf];
+  for (int i = 0; i < kMaxBuf; ++i) {
+    send_buf[i] = static_cast<char>(i);
+  }
+  memset(receive_buf, 0, kMaxBuf);
+  int bytes_sent = sendto(socket_fd, send_buf, kMaxBuf, kSendFlags, NULL, 0);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: nit: s/NULL/nullptr/ here and anywhere else.
created_at: 2025-04-29T16:15:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[kMaxEvents];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // bind socket with local address
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 5 second timeout for wait
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 5000);
+  // expect nothing to be ready since we're not doing anything
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+  struct sockaddr_in dest;
+  struct epoll_event events[kMaxEvents];
+  int i, num_ready;
+
+  // Add socket to epoll
+  epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev);
+
+  if (connect(socket_fd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+    EXPECT_EQ(errno, EINPROGRESS) << "Connection failed, not in progress";
+  }
+
+  // Wait for socket to connect
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 1000);
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      printf("Socket %d connected\n", events[i].data.fd);
+    }
+  }
+
+  EXPECT_GT(num_ready, 0) << "No sockets connected after wait";
+  int bytes_received = 0;
+
+  char* send_buf = new char[kMaxBuf];
+  char* receive_buf = new char[kMaxBuf];
+  for (int i = 0; i < kMaxBuf; ++i) {
+    send_buf[i] = static_cast<char>(i);
+  }
+  memset(receive_buf, 0, kMaxBuf);
+  int bytes_sent = sendto(socket_fd, send_buf, kMaxBuf, kSendFlags, NULL, 0);
+
+  // Wait to receive data from connected socket
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 1000);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: nit: Make `1000` a `constexpr size_t`.
created_at: 2025-04-29T16:15:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[kMaxEvents];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // bind socket with local address
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 5 second timeout for wait
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 5000);
+  // expect nothing to be ready since we're not doing anything
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+  struct sockaddr_in dest;
+  struct epoll_event events[kMaxEvents];
+  int i, num_ready;
+
+  // Add socket to epoll
+  epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev);
+
+  if (connect(socket_fd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+    EXPECT_EQ(errno, EINPROGRESS) << "Connection failed, not in progress";
+  }
+
+  // Wait for socket to connect
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 1000);
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      printf("Socket %d connected\n", events[i].data.fd);
+    }
+  }
+
+  EXPECT_GT(num_ready, 0) << "No sockets connected after wait";
+  int bytes_received = 0;
+
+  char* send_buf = new char[kMaxBuf];
+  char* receive_buf = new char[kMaxBuf];
+  for (int i = 0; i < kMaxBuf; ++i) {
+    send_buf[i] = static_cast<char>(i);
+  }
+  memset(receive_buf, 0, kMaxBuf);
+  int bytes_sent = sendto(socket_fd, send_buf, kMaxBuf, kSendFlags, NULL, 0);
+
+  // Wait to receive data from connected socket
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 1000);
+  bool data_received = false;
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      SB_LOG(INFO) << "Socket " << events[i].data.fd << " receiving data";
+      recvfrom(socket_fd, receive_buf, kMaxBuf, 0, 0, 0);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: nit:
```
recvfrom(socket_fd, receive_buf, kMaxBuf, /*flags=*/0, /*restrict_address=*/0, /*address_len=*/0);
```

Shouldn't we check the return value? `Upon successful completion, recvfrom() shall return the length of the message in bytes. If no messages are available to be received and the peer has performed an orderly shutdown, recvfrom() shall return 0. Otherwise, the function shall return -1 and set errno to indicate the error.`
created_at: 2025-04-29T16:16:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: It doesn't compile with `constexpr` :  `../../starboard/nplb/posix_compliance/posix_epoll_test.cc:78:17: error: constexpr variable 'kMany' must be initialized by a constant expression`
created_at: 2025-04-29T16:53:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: the `constexpr` error cascades into why we can't use an array here : 
```
../../starboard/nplb/posix_compliance/posix_epoll_test.cc:79:15: error: variable-sized object may not be initialized
  int sockets[kMany] = {};
  ```
created_at: 2025-04-29T16:55:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[kMaxEvents];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // bind socket with local address
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 5 second timeout for wait
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 5000);
+  // expect nothing to be ready since we're not doing anything
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+  struct sockaddr_in dest;
+  struct epoll_event events[kMaxEvents];
+  int i, num_ready;
+
+  // Add socket to epoll
+  epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev);
+
+  if (connect(socket_fd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+    EXPECT_EQ(errno, EINPROGRESS) << "Connection failed, not in progress";
+  }
+
+  // Wait for socket to connect
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 1000);
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      printf("Socket %d connected\n", events[i].data.fd);
+    }
+  }
+
+  EXPECT_GT(num_ready, 0) << "No sockets connected after wait";
+  int bytes_received = 0;
+
+  char* send_buf = new char[kMaxBuf];
+  char* receive_buf = new char[kMaxBuf];
+  for (int i = 0; i < kMaxBuf; ++i) {
+    send_buf[i] = static_cast<char>(i);
+  }
+  memset(receive_buf, 0, kMaxBuf);
+  int bytes_sent = sendto(socket_fd, send_buf, kMaxBuf, kSendFlags, NULL, 0);
+
+  // Wait to receive data from connected socket
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 1000);
+  bool data_received = false;
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      SB_LOG(INFO) << "Socket " << events[i].data.fd << " receiving data";
+      recvfrom(socket_fd, receive_buf, kMaxBuf, 0, 0, 0);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: Added this in and it's failing, modifying a different socket recvfrm test rn to make it work.
created_at: 2025-04-29T17:09:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: OOh it's because `kSbFileMaxOpen` is a const as well. Meh, never mind this.
created_at: 2025-04-29T17:15:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[kMaxEvents];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: This is used in some of the other socket tests, but if it's unconventional we can take a second look at its implementation later.
created_at: 2025-04-29T18:49:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,272 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as it is > 0.
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests.
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data.
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc.
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  // TODO(b/412696447): Correct member variable style.
+  int timeout = 1000;
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0) << strerror(errno);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0) << strerror(errno);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  // Create listen socket, bind and listen on <port>.
+  int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // Set socket to be reusable.
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // Bind socket with local address.
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  struct epoll_event ev, events[kMaxEvents];
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 1 second timeout for wait.
+  int num_ready = epoll_wait(epfd, events, kMaxEvents, timeout);
+  // Expect nothing to be ready since we're not doing anything.
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, ReceiveWithWait) {
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: This test is copied almost verbatim from posix_socket_receive_test.cc but has epoll calls added in.
created_at: 2025-04-29T18:50:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,235 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+#define MAX_EVENTS 10
+#define MAXBUF 1024
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[MAX_EVENTS];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // bind socket with local address
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 5 second timeout for wait
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 5000);
+  // expect nothing to be ready since we're not doing anything
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+  struct sockaddr_in dest;
+
+  char buffer[MAXBUF];
+  struct epoll_event events[MAX_EVENTS];
+  int i, num_ready;
+
+  // Add socket to epoll
+  epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev);
+
+  if (connect(socket_fd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+    EXPECT_EQ(errno, EINPROGRESS) << "Connection failed, not in progress";
+  }
+
+  // Wait for socket to connect
+  num_ready = epoll_wait(epfd, events, MAX_EVENTS, 1000);
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      printf("Socket %d connected\n", events[i].data.fd);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: Missed one instance of it, fixed in latest patchset.
created_at: 2025-04-29T20:18:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: Added in latest patchset.
created_at: 2025-04-29T20:18:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,243 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as its  > 0
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  struct epoll_event ev, events[kMaxEvents];
+  int listen_sock, num_ready;
+
+  // create listen socket, bind and listen on <port>
+  listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // set socket reusable
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // bind socket with local address
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 5 second timeout for wait
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 5000);
+  // expect nothing to be ready since we're not doing anything
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWait) {
+  struct sockaddr_in dest;
+  struct epoll_event events[kMaxEvents];
+  int i, num_ready;
+
+  // Add socket to epoll
+  epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev);
+
+  if (connect(socket_fd, (struct sockaddr*)&address, sizeof(address)) != 0) {
+    EXPECT_EQ(errno, EINPROGRESS) << "Connection failed, not in progress";
+  }
+
+  // Wait for socket to connect
+  num_ready = epoll_wait(epfd, events, kMaxEvents, 1000);
+  for (i = 0; i < num_ready; i++) {
+    if (events[i].events & EPOLLIN) {
+      printf("Socket %d connected\n", events[i].data.fd);
+    }
+  }
+
+  EXPECT_GT(num_ready, 0) << "No sockets connected after wait";
+  int bytes_received = 0;
+
+  char* send_buf = new char[kMaxBuf];
+  char* receive_buf = new char[kMaxBuf];
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: madhurajayaraman
body: Rewrote this test to replicate one of the socket_recieve tests - it does still use the char[] but looking at it with jelle later.
created_at: 2025-04-29T20:19:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,272 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as it is > 0.
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests.
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data.
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc.
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  // TODO(b/412696447): Correct member variable style.
+  int timeout = 1000;
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: nit: I think here you could just do
```
  for (auto& socket : sockets) {
    socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    //...
  }

  for (const auto& socket: sockets) {
    EXPECT_EQ(close(socket), 0) << strerror(errno);
  }
```

Note the first one is an `auto&`, so it can be modified by the `::socket()` call.
created_at: 2025-04-30T00:01:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,272 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as it is > 0.
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests.
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data.
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc.
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  // TODO(b/412696447): Correct member variable style.
+  int timeout = 1000;
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0) << strerror(errno);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0) << strerror(errno);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  // Create listen socket, bind and listen on <port>.
+  int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // Set socket to be reusable.
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // Bind socket with local address.
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  struct epoll_event ev, events[kMaxEvents];
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: Prefer designated initializers when there's no unions:
```
  struct epoll_event event = {
      .events = EPOLLIN,
      .data = {
        .fd = listen_sock,
      }
  };
```
which has the added value of initializing to their default values (i.e. 0) 
all the other unspecified variables (whereas the present code leaves them
random).

Also consider `std::array<struct epoll_event, kMaxEvents> events` or
`std::vector<struct epoll_event> events(kMaxEvents);` if `std::array<>` 
complains. In l.189, use `events.data()` either way.
created_at: 2025-04-30T00:07:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,272 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as it is > 0.
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests.
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data.
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc.
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  // TODO(b/412696447): Correct member variable style.
+  int timeout = 1000;
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0) << strerror(errno);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0) << strerror(errno);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  // Create listen socket, bind and listen on <port>.
+  int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // Set socket to be reusable.
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // Bind socket with local address.
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  struct epoll_event ev, events[kMaxEvents];
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 1 second timeout for wait.
+  int num_ready = epoll_wait(epfd, events, kMaxEvents, timeout);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: `const int`.
created_at: 2025-04-30T00:07:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,279 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as it is > 0.
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests.
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data.
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc.
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  // TODO(b/412696447): Correct member variable style.
+
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: Inline in l.176? In either case, also `const`.
created_at: 2025-05-01T16:37:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,279 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as it is > 0.
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests.
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data.
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc.
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  // TODO(b/412696447): Correct member variable style.
+
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: Since `epev` is used everywhere, could we give it a better name, like `polling_event`, or just `event`? As it is, is a shortening but doesnt' even respect the word order (should be `ep_ev` in any case). But since it's pervasive and it's meant to be readable, please correct.
created_at: 2025-05-01T16:39:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,279 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as it is > 0.
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests.
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data.
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc.
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  // TODO(b/412696447): Correct member variable style.
+
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0) << strerror(errno);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0) << strerror(errno);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  // Create listen socket, bind and listen on <port>.
+  int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // Set socket to be reusable.
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // Bind socket with local address.
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  struct epoll_event ev, events[kMaxEvents];
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 2 second timeout for wait.
+  int num_ready = epoll_wait(epfd, events, kMaxEvents, kSocketTimeout / 100);
+  // Expect nothing to be ready since we're not doing anything.
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, ReceiveWithWait) {
+  const int kBufSize = 256 * 1024;
+  const int kSockBufSize = kBufSize / 8;
+  int listen_socket_fd = -1, client_socket_fd = -1, server_socket_fd = -1;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: Separate each in one line.
created_at: 2025-05-01T16:40:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,279 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as it is > 0.
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests.
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data.
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc.
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  // TODO(b/412696447): Correct member variable style.
+
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0) << strerror(errno);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0) << strerror(errno);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  // Create listen socket, bind and listen on <port>.
+  int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // Set socket to be reusable.
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // Bind socket with local address.
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  struct epoll_event ev, events[kMaxEvents];
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 2 second timeout for wait.
+  int num_ready = epoll_wait(epfd, events, kMaxEvents, kSocketTimeout / 100);
+  // Expect nothing to be ready since we're not doing anything.
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, ReceiveWithWait) {
+  const int kBufSize = 256 * 1024;
+  const int kSockBufSize = kBufSize / 8;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: `constexpr` these two?
created_at: 2025-05-01T16:40:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,279 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as it is > 0.
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests.
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data.
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc.
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  // TODO(b/412696447): Correct member variable style.
+
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0) << strerror(errno);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0) << strerror(errno);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  // Create listen socket, bind and listen on <port>.
+  int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // Set socket to be reusable.
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // Bind socket with local address.
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  struct epoll_event ev, events[kMaxEvents];
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 2 second timeout for wait.
+  int num_ready = epoll_wait(epfd, events, kMaxEvents, kSocketTimeout / 100);
+  // Expect nothing to be ready since we're not doing anything.
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, ReceiveWithWait) {
+  const int kBufSize = 256 * 1024;
+  const int kSockBufSize = kBufSize / 8;
+  int listen_socket_fd = -1, client_socket_fd = -1, server_socket_fd = -1;
+  int result = PosixSocketCreateAndConnect(
+      AF_INET, AF_INET, htons(PosixGetPortNumberForTests()), kSocketTimeout,
+      &listen_socket_fd, &client_socket_fd, &server_socket_fd);
+
+  // Let's set the buffers small to create partial reads and writes.
+  PosixSocketSetReceiveBufferSize(client_socket_fd, kSockBufSize);
+  PosixSocketSetReceiveBufferSize(server_socket_fd, kSockBufSize);
+  PosixSocketSetSendBufferSize(client_socket_fd, kSockBufSize);
+  PosixSocketSetSendBufferSize(server_socket_fd, kSockBufSize);
+
+  // Create the buffers and fill the send buffer with a pattern, the receive
+  // buffer with zeros.
+  char* send_buf = new char[kBufSize];
+  char* receive_buf = new char[kBufSize];
+  for (int i = 0; i < kBufSize; ++i) {
+    send_buf[i] = static_cast<char>(i);
+    receive_buf[i] = 0;
+  }
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: I feel a strong sense of having commented before about using std::array<> and STL functions, and either you forget those comments or are actively ignoring them.

_If_ the idea is not to use C++ traits (big IF), then at least make that plain
by filing a bug and leaving here and in other parts where these C90 (or C11) 
idioms are used (e.g. l.82, l.90) a `// TODO(b/...): Migrate to C++.`.
created_at: 2025-05-01T16:42:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,279 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as it is > 0.
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests.
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data.
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc.
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  // TODO(b/412696447): Correct member variable style.
+
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0) << strerror(errno);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0) << strerror(errno);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  // Create listen socket, bind and listen on <port>.
+  int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // Set socket to be reusable.
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // Bind socket with local address.
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  struct epoll_event ev, events[kMaxEvents];
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 2 second timeout for wait.
+  int num_ready = epoll_wait(epfd, events, kMaxEvents, kSocketTimeout / 100);
+  // Expect nothing to be ready since we're not doing anything.
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, ReceiveWithWait) {
+  const int kBufSize = 256 * 1024;
+  const int kSockBufSize = kBufSize / 8;
+  int listen_socket_fd = -1, client_socket_fd = -1, server_socket_fd = -1;
+  int result = PosixSocketCreateAndConnect(
+      AF_INET, AF_INET, htons(PosixGetPortNumberForTests()), kSocketTimeout,
+      &listen_socket_fd, &client_socket_fd, &server_socket_fd);
+
+  // Let's set the buffers small to create partial reads and writes.
+  PosixSocketSetReceiveBufferSize(client_socket_fd, kSockBufSize);
+  PosixSocketSetReceiveBufferSize(server_socket_fd, kSockBufSize);
+  PosixSocketSetSendBufferSize(client_socket_fd, kSockBufSize);
+  PosixSocketSetSendBufferSize(server_socket_fd, kSockBufSize);
+
+  // Create the buffers and fill the send buffer with a pattern, the receive
+  // buffer with zeros.
+  char* send_buf = new char[kBufSize];
+  char* receive_buf = new char[kBufSize];
+  for (int i = 0; i < kBufSize; ++i) {
+    send_buf[i] = static_cast<char>(i);
+    receive_buf[i] = 0;
+  }
+
+  // Send from server to client.
+  int send_total = 0;
+  int receive_total = 0;
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: Move these guys closer to where they are used please.
created_at: 2025-05-01T16:43:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,279 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as it is > 0.
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests.
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data.
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc.
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  // TODO(b/412696447): Correct member variable style.
+
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0) << strerror(errno);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0) << strerror(errno);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  // Create listen socket, bind and listen on <port>.
+  int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // Set socket to be reusable.
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // Bind socket with local address.
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  struct epoll_event ev, events[kMaxEvents];
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 2 second timeout for wait.
+  int num_ready = epoll_wait(epfd, events, kMaxEvents, kSocketTimeout / 100);
+  // Expect nothing to be ready since we're not doing anything.
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, ReceiveWithWait) {
+  const int kBufSize = 256 * 1024;
+  const int kSockBufSize = kBufSize / 8;
+  int listen_socket_fd = -1, client_socket_fd = -1, server_socket_fd = -1;
+  int result = PosixSocketCreateAndConnect(
+      AF_INET, AF_INET, htons(PosixGetPortNumberForTests()), kSocketTimeout,
+      &listen_socket_fd, &client_socket_fd, &server_socket_fd);
+
+  // Let's set the buffers small to create partial reads and writes.
+  PosixSocketSetReceiveBufferSize(client_socket_fd, kSockBufSize);
+  PosixSocketSetReceiveBufferSize(server_socket_fd, kSockBufSize);
+  PosixSocketSetSendBufferSize(client_socket_fd, kSockBufSize);
+  PosixSocketSetSendBufferSize(server_socket_fd, kSockBufSize);
+
+  // Create the buffers and fill the send buffer with a pattern, the receive
+  // buffer with zeros.
+  char* send_buf = new char[kBufSize];
+  char* receive_buf = new char[kBufSize];
+  for (int i = 0; i < kBufSize; ++i) {
+    send_buf[i] = static_cast<char>(i);
+    receive_buf[i] = 0;
+  }
+
+  // Send from server to client.
+  int send_total = 0;
+  int receive_total = 0;
+  epoll_ctl(epfd, EPOLL_CTL_ADD, server_socket_fd, &epev);
+  epoll_ctl(epfd, EPOLL_CTL_ADD, client_socket_fd, &epev);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: `epoll_ctl` returns a value (`When successful, epoll_ctl() returns zero.  When an error occurs, epoll_ctl() returns -1 and [errno](https://man7.org/linux/man-pages/man3/errno.3.html) is set to indicate the error.`). Is it OK to ignore it?
created_at: 2025-05-01T16:44:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,279 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "starboard/common/socket.h"
+#include "starboard/configuration_constants.h"
+#include "starboard/nplb/posix_compliance/posix_socket_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+constexpr int kMaxEvents = 10;
+constexpr int kMaxBuf = 1024;
+
+class PosixEpollTest : public testing::Test {
+ public:
+  void SetUp() override {
+    // Create epoll object, arg doesn't matter as long as it is > 0.
+    epfd = epoll_create(1);
+    ASSERT_GT(epfd, 0) << strerror(errno);
+
+    // Create non-blocking socket for use in all tests.
+    socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    ASSERT_GE(socket_fd, 0) << strerror(errno);
+
+    // Set epoll_event data.
+    epev.data.fd = socket_fd;
+    epev.events = EPOLLIN | EPOLLOUT;
+
+    // Get socket for use in tests similar to socket_helper.cc.
+    ASSERT_TRUE(
+        PosixGetLocalAddressIPv4(reinterpret_cast<sockaddr*>(&address)) == 0 ||
+        PosixGetLocalAddressIPv6(reinterpret_cast<sockaddr*>(&address)) == 0);
+    address.sin6_port = htons(PosixGetPortNumberForTests());
+  }
+
+  void TearDown() override {
+    EXPECT_EQ(close(socket_fd), 0) << strerror(errno);
+    EXPECT_EQ(close(epfd), 0) << strerror(errno);
+  }
+
+ protected:
+  // TODO(b/412696447): Correct member variable style.
+
+  int epfd;
+  int socket_fd;
+  epoll_event epev;
+  sockaddr_in6 address = {};
+  socklen_t add_len = sizeof(struct sockaddr_in);
+};
+
+TEST_F(PosixEpollTest, SunnyDayAddRemove) {
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, SunnyDayMany) {
+  const int kMany = kSbFileMaxOpen;
+  std::vector<int> sockets(kMany, 0);
+
+  for (int i = 0; i < kMany; ++i) {
+    sockets[i] = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    EXPECT_GE(sockets[i], 0) << strerror(errno);
+    EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, sockets[i], &epev), 0)
+        << strerror(errno);
+  }
+
+  for (int i = 0; i < kMany; ++i) {
+    EXPECT_EQ(close(sockets[i]), 0) << strerror(errno);
+  }
+}
+
+TEST_F(PosixEpollTest, RainyDayRemoveFromEmptyFails) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleAddFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayDoubleRemoveFails) {
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayAddRemoveRepeated) {
+  // First remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // First add should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Remove after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0);
+
+  // Add after remove should succeed.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0)
+      << strerror(errno);
+
+  // Second add after remove should fail.
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &epev), 0);
+
+  // Remove should succeed, to clear epoll queue for next test.
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_DEL, socket_fd, &epev), 0)
+      << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, RainyDayInvalidSocket) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &epev), 0);
+}
+
+TEST_F(PosixEpollTest, RainyDayNoInterest) {
+  EXPECT_LT(epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, nullptr), 0);
+}
+
+TEST_F(PosixEpollTest, SunnyDayWaitTimeout) {
+  // Create listen socket, bind and listen on <port>.
+  int listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  ASSERT_GE(listen_sock, 0);
+
+  // Set socket to be reusable.
+  const int on = 1;
+  int result =
+      setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  // Bind socket with local address.
+  result =
+      bind(listen_sock, reinterpret_cast<struct sockaddr*>(&address), add_len);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  result = listen(listen_sock, kMaxConn);
+  EXPECT_EQ(result, 0) << strerror(errno);
+
+  struct epoll_event ev, events[kMaxEvents];
+  ev.events = EPOLLIN;
+  ev.data.fd = listen_sock;
+  EXPECT_EQ(epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev), 0)
+      << strerror(errno);
+
+  // 2 second timeout for wait.
+  int num_ready = epoll_wait(epfd, events, kMaxEvents, kSocketTimeout / 100);
+  // Expect nothing to be ready since we're not doing anything.
+  EXPECT_EQ(num_ready, 0);
+
+  EXPECT_EQ(close(listen_sock), 0) << strerror(errno);
+}
+
+TEST_F(PosixEpollTest, ReceiveWithWait) {
+  const int kBufSize = 256 * 1024;
+  const int kSockBufSize = kBufSize / 8;
+  int listen_socket_fd = -1, client_socket_fd = -1, server_socket_fd = -1;
+  int result = PosixSocketCreateAndConnect(
+      AF_INET, AF_INET, htons(PosixGetPortNumberForTests()), kSocketTimeout,
+      &listen_socket_fd, &client_socket_fd, &server_socket_fd);
+
+  // Let's set the buffers small to create partial reads and writes.
+  PosixSocketSetReceiveBufferSize(client_socket_fd, kSockBufSize);
+  PosixSocketSetReceiveBufferSize(server_socket_fd, kSockBufSize);
+  PosixSocketSetSendBufferSize(client_socket_fd, kSockBufSize);
+  PosixSocketSetSendBufferSize(server_socket_fd, kSockBufSize);
+
+  // Create the buffers and fill the send buffer with a pattern, the receive
+  // buffer with zeros.
+  char* send_buf = new char[kBufSize];
+  char* receive_buf = new char[kBufSize];
+  for (int i = 0; i < kBufSize; ++i) {
+    send_buf[i] = static_cast<char>(i);
+    receive_buf[i] = 0;
+  }
+
+  // Send from server to client.
+  int send_total = 0;
+  int receive_total = 0;
+  epoll_ctl(epfd, EPOLL_CTL_ADD, server_socket_fd, &epev);
+  epoll_ctl(epfd, EPOLL_CTL_ADD, client_socket_fd, &epev);
+  int num_ready = 0;
+  struct epoll_event events[kMaxEvents];
+  num_ready = epoll_wait(epfd, events, kMaxEvents, kSocketTimeout);
path: starboard/nplb/posix_compliance/posix_epoll_test.cc
user: login: yell0wd0g
body: nit:
```   
  struct epoll_event events[kMaxEvents];  
  int num_ready = epoll_wait(epfd, events, kMaxEvents, kSocketTimeout);
```

I.e. don't separate declaration and initialization.
created_at: 2025-05-01T16:45:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,73 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_create1 ---
+// epoll_create1 is epoll_create without the obsolete size argument.
+class PosixEpollCreate1Tests : public PosixEpollTest {};
path: starboard/nplb/posix_compliance/posix_epoll_create_test.cc
user: login: yell0wd0g
body: When the test class is empty, it's not needed and can be removed
by simply s/TEST_F/TEST/ the test cases below. 

https://google.github.io/googletest/reference/testing.html#TEST
created_at: 2025-05-20T21:34:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,73 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_create1 ---
+// epoll_create1 is epoll_create without the obsolete size argument.
+class PosixEpollCreate1Tests : public PosixEpollTest {};
+
+TEST_F(PosixEpollCreate1Tests, CreateSuccessfully) {
+  int epfd = epoll_create1(0);
+  ASSERT_NE(epfd, -1) << "epoll_create1(0) failed: " << strerror(errno);
+  if (epfd != -1) {
path: starboard/nplb/posix_compliance/posix_epoll_create_test.cc
user: login: yell0wd0g
body: ASSERT(bla) implicitly has a return if the condition doesn't hold,
so we don't need to test the value again, i.e.
```
  ASSERT_NE(epfd, -1) << "epoll_create1(0) failed: " << strerror(errno);
￼ ASSERT_EQ(close(epfd), 0);  // |epfd| cannot be -1 if we get here.
```
￼
This applies throughout and would simplify the code.
created_at: 2025-05-20T21:36:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,73 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_create1 ---
+// epoll_create1 is epoll_create without the obsolete size argument.
+class PosixEpollCreate1Tests : public PosixEpollTest {};
+
+TEST_F(PosixEpollCreate1Tests, CreateSuccessfully) {
+  int epfd = epoll_create1(0);
+  ASSERT_NE(epfd, -1) << "epoll_create1(0) failed: " << strerror(errno);
+  if (epfd != -1) {
+    ASSERT_EQ(close(epfd), 0);
path: starboard/nplb/posix_compliance/posix_epoll_create_test.cc
user: login: yell0wd0g
body: `close()` also sets errno when failing (`close() returns zero 
on success. On error, -1 is returned, and errno is set 
appropriately.`). So this should be
```
    ASSERT_EQ(close(epfd), 0) << "close: " << strerror(errno);
```

created_at: 2025-05-20T21:40:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,219 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_ctl ---
+class PosixEpollCtlTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+
+  void SetUp() override {
+    epfd_ = epoll_create1(0);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+};
+
+TEST_F(PosixEpollCtlTests, AddFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN | EPOLLOUT;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_ADD failed: " << strerror(errno);
+}
+
+TEST_F(PosixEpollCtlTests, ModifyFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
path: starboard/nplb/posix_compliance/posix_epoll_ctl_test.cc
user: login: yell0wd0g
body: nit: Try to use "designated initializers"?
created_at: 2025-05-20T21:41:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,73 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_create1 ---
+// epoll_create1 is epoll_create without the obsolete size argument.
+class PosixEpollCreate1Tests : public PosixEpollTest {};
+
+TEST_F(PosixEpollCreate1Tests, CreateSuccessfully) {
+  int epfd = epoll_create1(0);
+  ASSERT_NE(epfd, -1) << "epoll_create1(0) failed: " << strerror(errno);
+  if (epfd != -1) {
path: starboard/nplb/posix_compliance/posix_epoll_create_test.cc
user: login: madhurajayaraman
body: Oh good catch, TY! I'll update the gem to include a lot of these things (in addition to fixing this)...this is a pretty obvious one, I'm not sure how it escaped my notice. I guess that's why we have reviews!
created_at: 2025-05-21T15:47:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,73 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_create1 ---
+// epoll_create1 is epoll_create without the obsolete size argument.
+class PosixEpollCreate1Tests : public PosixEpollTest {};
+
+TEST_F(PosixEpollCreate1Tests, CreateSuccessfully) {
+  int epfd = epoll_create1(0);
+  ASSERT_NE(epfd, -1) << "epoll_create1(0) failed: " << strerror(errno);
+  if (epfd != -1) {
+    ASSERT_EQ(close(epfd), 0);
path: starboard/nplb/posix_compliance/posix_epoll_create_test.cc
user: login: madhurajayaraman
body: Good note, will add this in - Any ASSERT or EXPECT statement that tests a function's success should print the error with the format "<function_name> failed: " << strerror(errno)
created_at: 2025-05-21T16:44:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,219 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_ctl ---
+class PosixEpollCtlTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+
+  void SetUp() override {
+    epfd_ = epoll_create1(0);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+};
+
+TEST_F(PosixEpollCtlTests, AddFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN | EPOLLOUT;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_ADD failed: " << strerror(errno);
+}
+
+TEST_F(PosixEpollCtlTests, ModifyFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
path: starboard/nplb/posix_compliance/posix_epoll_ctl_test.cc
user: login: madhurajayaraman
body: Tried to use them, got :
```
../../starboard/nplb/posix_compliance/posix_epoll_ctl_test.cc:57:62: error: nested designators are a C99 extension [-Werror,-Wc99-designator]
  struct epoll_event event = { .events = EPOLLIN | EPOLLOUT, .data.fd = pipe_fds_[0]};
```

So could use it for just `.events`, and set `.data.fd` explicitly but at that point I'd prefer consistency and just setting both fields the way I already do.
created_at: 2025-05-21T17:02:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,219 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_ctl ---
+class PosixEpollCtlTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+
+  void SetUp() override {
+    epfd_ = epoll_create1(0);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+};
+
+TEST_F(PosixEpollCtlTests, AddFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN | EPOLLOUT;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_ADD failed: " << strerror(errno);
+}
+
+TEST_F(PosixEpollCtlTests, ModifyFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
path: starboard/nplb/posix_compliance/posix_epoll_ctl_test.cc
user: login: andrewsavage1
body: You can do `{..., .data={.fd = pipe_fds_[0]}` as a c++ nested designated initializer. I don't think it looks better when there are just two fields like this though, so I'd rather keep it as is
created_at: 2025-05-21T17:09:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,219 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_ctl ---
+class PosixEpollCtlTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+
+  void SetUp() override {
+    epfd_ = epoll_create1(0);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+};
+
+TEST_F(PosixEpollCtlTests, AddFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN | EPOLLOUT;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_ADD failed: " << strerror(errno);
+}
+
+TEST_F(PosixEpollCtlTests, ModifyFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
path: starboard/nplb/posix_compliance/posix_epoll_ctl_test.cc
user: login: madhurajayaraman
body: Ok, will leave as is.
created_at: 2025-05-21T17:20:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,219 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_ctl ---
+class PosixEpollCtlTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+
+  void SetUp() override {
+    epfd_ = epoll_create1(0);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+};
+
+TEST_F(PosixEpollCtlTests, AddFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN | EPOLLOUT;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_ADD failed: " << strerror(errno);
+}
+
+TEST_F(PosixEpollCtlTests, ModifyFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
path: starboard/nplb/posix_compliance/posix_epoll_ctl_test.cc
user: login: yell0wd0g
body: Then we should instruct to initialize structs, like this: 
`  struct epoll_event event = {};`

which sets all fields to their default value (which is well
defined) as opposed to leaving them uninitialized. WDYT?
created_at: 2025-05-21T18:01:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+TEST(PosixEpollCreate1Tests, CreateSuccessfully) {
+  int epfd = epoll_create1(0);
+  ASSERT_NE(epfd, -1) << "epoll_create1(0) failed: " << strerror(errno);
+  ASSERT_EQ(close(epfd), 0) << "close failed: " << strerror(errno);
+}
+
+TEST(PosixEpollCreate1Tests, CreateSuccessfullyWithCloExec) {
+  int epfd = epoll_create1(EPOLL_CLOEXEC);
+  ASSERT_NE(epfd, -1) << "epoll_create1(EPOLL_CLOEXEC) failed: "
+                      << strerror(errno);
+
+  int flags = fcntl(epfd, F_GETFD);
+  ASSERT_NE(flags, -1) << "fcntl(F_GETFD) failed: " << strerror(errno);
+  ASSERT_TRUE(flags & FD_CLOEXEC) << "FD_CLOEXEC was not set.";
+  ASSERT_EQ(close(epfd), 0) << "close failed: " << strerror(errno);
+}
+
+TEST(PosixEpollCreate1Tests, ErrorInvalidFlags) {
+  // An arbitrary invalid flag value.
+  // EPOLL_CLOEXEC is 0x80000. We pick another bit not used by epoll_create1.
+  const int kInvalidFlag = 0x1;
+  int epfd = epoll_create1(kInvalidFlag);
+  ASSERT_EQ(epfd, -1);
+  ASSERT_EQ(errno, EINVAL);
+  // No fd to close as creation failed.
+}
+
+/* The following error scenarios are untested for epoll_create1():
path: starboard/nplb/posix_compliance/posix_epoll_create_test.cc
user: login: andrewsavage1
body: Do you prefer leaving these comments in? I think they're fine if you like them, but I think they belong as a file comment at the top
created_at: 2025-05-21T18:10:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,219 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_ctl ---
+class PosixEpollCtlTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+
+  void SetUp() override {
+    epfd_ = epoll_create1(0);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+};
+
+TEST_F(PosixEpollCtlTests, AddFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN | EPOLLOUT;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_ADD failed: " << strerror(errno);
+}
+
+TEST_F(PosixEpollCtlTests, ModifyFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_ADD for MOD test failed: " << strerror(errno);
+
+  event.events = EPOLLOUT;  // Modify to only EPOLLOUT
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_MOD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_MOD failed: " << strerror(errno);
+}
+
+TEST_F(PosixEpollCtlTests, DeleteFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_ADD for DEL test failed: " << strerror(errno);
+
+  // The 'event' parameter is ignored for EPOLL_CTL_DEL but must be non-NULL on
+  // older kernels. Modern kernels (>= 2.6.9) allow NULL. For compliance, pass a
+  // valid pointer.
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_DEL, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_DEL failed: " << strerror(errno);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorBadEpfd) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(kInvalidFd, EPOLL_CTL_ADD, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, EBADF);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorBadFdOnAdd) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = kInvalidFd;
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, kInvalidFd, &event), -1);
+  ASSERT_EQ(errno, EBADF);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorBadFdOnMod) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = kInvalidFd;  // This is the FD we are trying to MOD.
+
+  // First, add a valid fd to have something in the epoll set.
+  struct epoll_event valid_event;
+  valid_event.events = EPOLLIN;
+  valid_event.data.fd = pipe_fds_[0];
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &valid_event), 0);
+
+  // Try to MOD using an fd that is itself invalid.
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_MOD, kInvalidFd, &event), -1);
+  ASSERT_EQ(errno, EBADF);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorAlreadyExistsOnAdd) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "First EPOLL_CTL_ADD failed: " << strerror(errno);
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, EEXIST);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorEpfdIsNotEpollFd) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+
+  // Use one end of the pipe as a non-epoll fd for epfd argument
+  ASSERT_EQ(epoll_ctl(pipe_fds_[1], EPOLL_CTL_ADD, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorFdIsSameAsEpfd) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = epfd_;  // Trying to add epfd to itself
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, epfd_, &event), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorInvalidOperation) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+  // An arbitrary integer that isn't a valid EPOLL_CTL operation.
+  const int kInvalidOp = 99;
+
+  ASSERT_EQ(epoll_ctl(epfd_, kInvalidOp, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorLoopBetweenTwoEpollInstances) {
+  int epfd2 = epoll_create1(0);
+  ASSERT_NE(epfd2, -1)
+      << "Failed to create second epoll instance for ELOOP test: "
+      << strerror(errno);
+
+  // Try A watches B, B watches A
+  struct epoll_event ev_a_watches_b;
+  ev_a_watches_b.events = EPOLLIN;
+  ev_a_watches_b.data.fd = epfd2;  // epfd_ will watch epfd2
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, epfd2, &ev_a_watches_b), 0)
+      << "epoll_ctl add epfd2 to epfd_ failed: " << strerror(errno);
+
+  struct epoll_event ev_b_watches_a;
+  ev_b_watches_a.events = EPOLLIN;
+  ev_b_watches_a.data.fd = epfd_;  // epfd2 tries to watch epfd_
+  ASSERT_EQ(epoll_ctl(epfd2, EPOLL_CTL_ADD, epfd_, &ev_b_watches_a), -1);
+  ASSERT_EQ(errno, ELOOP);
+
+  // Clean up: remove epfd2 from epfd_
+  epoll_ctl(epfd_, EPOLL_CTL_DEL, epfd2, &ev_a_watches_b);
+  if (epfd2 >= 0) {
+    close(epfd2);
+  }
+}
+
+TEST_F(PosixEpollCtlTests, ErrorFdNotRegisteredOnMod) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];  // This fd is valid but not yet added
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_MOD, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, ENOENT);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorFdNotRegisteredOnDel) {
+  struct epoll_event event;  // Dummy event for DEL
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];  // This fd is valid but not yet added
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_DEL, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, ENOENT);
+}
+
+/* The following error scenarios are untested for epoll_ctl():
path: starboard/nplb/posix_compliance/posix_epoll_ctl_test.cc
user: login: andrewsavage1
body: Rec moving to top
created_at: 2025-05-21T18:15:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,46 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// A helper function to create a pipe.
+// Returns true on success, false on failure.
+// pipe_fds[0] is the read end, pipe_fds[1] is the write end.
+bool CreatePipe(int pipe_fds[2], int flags = 0) {
+  if (flags == 0) {
+    return pipe(pipe_fds) == 0;
+  }
+  return pipe2(pipe_fds, flags) == 0;
+}
+
+// Test fixture for epoll tests
+class PosixEpollTest : public ::testing::Test {
+ protected:
+  static const int kInvalidFd = -123;  // An fd value that is likely invalid.
path: starboard/nplb/posix_compliance/posix_epoll_test_helper.cc
user: login: andrewsavage1
body: Is `-123` better than just `-1`? Do we use `-1` for something else? I don't really like choosing an arbitrary number for an invalid Fd
created_at: 2025-05-21T18:15:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,219 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_ctl ---
path: starboard/nplb/posix_compliance/posix_epoll_ctl_test.cc
user: login: andrewsavage1
body: These lead comments are unnecessary—can you remove this one and the other test suite comments that are added?
created_at: 2025-05-21T18:17:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,327 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_wait ---
+class PosixEpollWaitTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+  struct epoll_event events_[kMaxEvents];
+
+  void SetUp() override {
+    epfd_ = epoll_create1(0);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    // Use non-blocking pipes to prevent writes from blocking indefinitely if
+    // pipe is full
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+    // NOTE: No FDs are added to epoll instance by default in SetUp.
+    // Tests are responsible for adding/removing FDs they monitor.
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+
+  // Helper to add to epoll
+  void AddToEpoll(int fd_to_add, uint32_t ev_mask) {
+    struct epoll_event event;
+    event.events = ev_mask;
+    event.data.fd = fd_to_add;
+    ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, fd_to_add, &event), 0)
+        << "Failed to add fd " << fd_to_add << " to epoll with events "
+        << ev_mask << ": " << strerror(errno);
+  }
+
+  // Helper to remove from epoll
+  void RemoveFromEpoll(int fd_to_remove) {
+    struct epoll_event event {};  // Dummy event, required for older kernels
+    if (epfd_ >= 0 && fd_to_remove >= 0) {
+      epoll_ctl(epfd_, EPOLL_CTL_DEL, fd_to_remove, &event);
+    }
+  }
+};
+
+TEST_F(PosixEpollWaitTests, EventReportedSuccessfully) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch read end for input
+
+  char buffer = 'x';
+  ASSERT_EQ(write(pipe_fds_[1], &buffer, 1), 1)
+      << "Write to pipe failed: " << strerror(errno);
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kModerateTimeoutMs);
+  ASSERT_EQ(nfds, 1) << "epoll_wait did not return 1 event: " << strerror(errno)
+                     << " (nfds=" << nfds << ")";
+  ASSERT_EQ(events_[0].data.fd, pipe_fds_[0]);
+  ASSERT_TRUE(events_[0].events & EPOLLIN);
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, TimeoutZeroReturnsImmediately) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch something
path: starboard/nplb/posix_compliance/posix_epoll_wait_test.cc
user: login: andrewsavage1
body: This comment isn't helpful imo, it should either be removed or replaced with something more meaningful
created_at: 2025-05-21T18:19:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,327 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_wait ---
+class PosixEpollWaitTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+  struct epoll_event events_[kMaxEvents];
+
+  void SetUp() override {
+    epfd_ = epoll_create1(0);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    // Use non-blocking pipes to prevent writes from blocking indefinitely if
+    // pipe is full
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+    // NOTE: No FDs are added to epoll instance by default in SetUp.
+    // Tests are responsible for adding/removing FDs they monitor.
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+
+  // Helper to add to epoll
+  void AddToEpoll(int fd_to_add, uint32_t ev_mask) {
+    struct epoll_event event;
+    event.events = ev_mask;
+    event.data.fd = fd_to_add;
+    ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, fd_to_add, &event), 0)
+        << "Failed to add fd " << fd_to_add << " to epoll with events "
+        << ev_mask << ": " << strerror(errno);
+  }
+
+  // Helper to remove from epoll
+  void RemoveFromEpoll(int fd_to_remove) {
+    struct epoll_event event {};  // Dummy event, required for older kernels
+    if (epfd_ >= 0 && fd_to_remove >= 0) {
+      epoll_ctl(epfd_, EPOLL_CTL_DEL, fd_to_remove, &event);
+    }
+  }
+};
+
+TEST_F(PosixEpollWaitTests, EventReportedSuccessfully) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch read end for input
+
+  char buffer = 'x';
+  ASSERT_EQ(write(pipe_fds_[1], &buffer, 1), 1)
+      << "Write to pipe failed: " << strerror(errno);
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kModerateTimeoutMs);
+  ASSERT_EQ(nfds, 1) << "epoll_wait did not return 1 event: " << strerror(errno)
+                     << " (nfds=" << nfds << ")";
+  ASSERT_EQ(events_[0].data.fd, pipe_fds_[0]);
+  ASSERT_TRUE(events_[0].events & EPOLLIN);
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, TimeoutZeroReturnsImmediately) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch something
+
+  // Ensure no events are pending initially by draining the pipe
+  char buffer[10];
+  while (read(pipe_fds_[0], buffer, sizeof(buffer)) > 0)
path: starboard/nplb/posix_compliance/posix_epoll_wait_test.cc
user: login: andrewsavage1
body: Empty while loops should use empty braces instead of a single semicolon: go/cstyle#Formatting_Looping_Branching (fix here and below)
created_at: 2025-05-21T18:21:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,327 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_wait ---
+class PosixEpollWaitTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+  struct epoll_event events_[kMaxEvents];
+
+  void SetUp() override {
+    epfd_ = epoll_create1(0);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    // Use non-blocking pipes to prevent writes from blocking indefinitely if
+    // pipe is full
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+    // NOTE: No FDs are added to epoll instance by default in SetUp.
+    // Tests are responsible for adding/removing FDs they monitor.
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+
+  // Helper to add to epoll
+  void AddToEpoll(int fd_to_add, uint32_t ev_mask) {
+    struct epoll_event event;
+    event.events = ev_mask;
+    event.data.fd = fd_to_add;
+    ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, fd_to_add, &event), 0)
+        << "Failed to add fd " << fd_to_add << " to epoll with events "
+        << ev_mask << ": " << strerror(errno);
+  }
+
+  // Helper to remove from epoll
+  void RemoveFromEpoll(int fd_to_remove) {
+    struct epoll_event event {};  // Dummy event, required for older kernels
+    if (epfd_ >= 0 && fd_to_remove >= 0) {
+      epoll_ctl(epfd_, EPOLL_CTL_DEL, fd_to_remove, &event);
+    }
+  }
+};
+
+TEST_F(PosixEpollWaitTests, EventReportedSuccessfully) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch read end for input
+
+  char buffer = 'x';
+  ASSERT_EQ(write(pipe_fds_[1], &buffer, 1), 1)
+      << "Write to pipe failed: " << strerror(errno);
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kModerateTimeoutMs);
+  ASSERT_EQ(nfds, 1) << "epoll_wait did not return 1 event: " << strerror(errno)
+                     << " (nfds=" << nfds << ")";
+  ASSERT_EQ(events_[0].data.fd, pipe_fds_[0]);
+  ASSERT_TRUE(events_[0].events & EPOLLIN);
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, TimeoutZeroReturnsImmediately) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch something
+
+  // Ensure no events are pending initially by draining the pipe
+  char buffer[10];
+  while (read(pipe_fds_[0], buffer, sizeof(buffer)) > 0)
+    ;  // Drain
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, 0);  // 0ms timeout
+  ASSERT_EQ(nfds, 0) << "epoll_wait with 0 timeout did not return 0: "
+                     << strerror(errno);
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, TimeoutPositiveReturnsAfterTimeout) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch something
+
+  // Ensure no events are pending initially
+  char buffer[10];
+  while (read(pipe_fds_[0], buffer, sizeof(buffer)) > 0)
+    ;  // Drain
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kShortTimeoutMs);
+  ASSERT_EQ(nfds, 0)
+      << "epoll_wait with positive timeout did not return 0 (event occurred?): "
+      << strerror(errno);
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, MaxEventsLimitsReturnedEvents) {
+  int p2[2] = {-1, -1};
+  ASSERT_TRUE(CreatePipe(p2, O_NONBLOCK));
+  int pipe2_read_fd = p2[0];
+  int pipe2_write_fd = p2[1];
+
+  AddToEpoll(pipe_fds_[0], EPOLLIN);
+  AddToEpoll(pipe2_read_fd, EPOLLIN);
+
+  char buffer = 'z';
+  ASSERT_EQ(write(pipe_fds_[1], &buffer, 1), 1);
+  ASSERT_EQ(write(pipe2_write_fd, &buffer, 1), 1);
+
+  const int kMaxEventsForThisTest = 1;
+  struct epoll_event single_event[kMaxEventsForThisTest];
+  int nfds = epoll_wait(epfd_, single_event, kMaxEventsForThisTest,
+                        kModerateTimeoutMs);
+  ASSERT_EQ(nfds, kMaxEventsForThisTest)
+      << "epoll_wait did not return max_events: " << strerror(errno);
+
+  RemoveFromEpoll(pipe_fds_[0]);
+  RemoveFromEpoll(pipe2_read_fd);
+
+  if (pipe2_read_fd >= 0) {
+    close(pipe2_read_fd);
+  }
+  if (pipe2_write_fd >= 0) {
+    close(pipe2_write_fd);
+  }
+}
+
+TEST_F(PosixEpollWaitTests, ErrorBadEpfd) {
+  ASSERT_EQ(epoll_wait(kInvalidFd, events_, kMaxEvents, 0), -1);
+  ASSERT_EQ(errno, EBADF);
+}
+
+TEST_F(PosixEpollWaitTests, ErrorInvalidMaxEventsZero) {
+  ASSERT_EQ(epoll_wait(epfd_, events_, 0, 0), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollWaitTests, ErrorInvalidMaxEventsNegative) {
+  ASSERT_EQ(epoll_wait(epfd_, events_, -1, 0), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollWaitTests, ErrorEpfdIsNotEpollFd) {
+  // Use one end of the pipe as a non-epoll fd for epfd argument
+  // (pipe_fds_[1] is valid from SetUp)
+  ASSERT_EQ(epoll_wait(pipe_fds_[1], events_, kMaxEvents, 0), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollWaitTests, WaitForWriteOnReadOnlyPipeEndNeverSignalsWritable) {
+  // pipe_fds_[0] is the read end, inherently not writable.
+  // We expect a timeout, not EPOLLOUT.
+  AddToEpoll(pipe_fds_[0], EPOLLOUT);
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kShortTimeoutMs);
+
+  ASSERT_EQ(nfds, 0)
+      << "epoll_wait should timeout for EPOLLOUT on read-only pipe end. "
+      << "nfds=" << nfds << ", errno=" << (errno ? strerror(errno) : "none")
+      << (nfds > 0 ? ", event=" + std::to_string(events_[0].events) : "");
+  if (nfds > 0) {
+    ASSERT_FALSE(events_[0].events & EPOLLOUT)
+        << "EPOLLOUT incorrectly signalled for read-only pipe end.";
+  }
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, WaitForReadOnWriteOnlyPipeEndNeverSignalsReadable) {
+  // pipe_fds_[1] is the write end, inherently not readable.
+  // We expect a timeout, not EPOLLIN.
+  AddToEpoll(pipe_fds_[1], EPOLLIN);
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kShortTimeoutMs);
+
+  ASSERT_EQ(nfds, 0)
+      << "epoll_wait should timeout for EPOLLIN on write-only pipe end. "
+      << "nfds=" << nfds << ", errno=" << (errno ? strerror(errno) : "none")
+      << (nfds > 0 ? ", event=" + std::to_string(events_[0].events) : "");
+  if (nfds > 0) {
+    ASSERT_FALSE(events_[0].events & EPOLLIN)
+        << "EPOLLIN incorrectly signalled for write-only pipe end.";
+  }
+  RemoveFromEpoll(pipe_fds_[1]);
+}
+
+TEST_F(PosixEpollWaitTests, WaitForWriteOnReadOnlyPipeEndWhenWriteEndClosed) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN | EPOLLOUT | EPOLLHUP);
+
+  ASSERT_NE(pipe_fds_[1], -1);  // Ensure write end is initially valid
+  close(pipe_fds_[1]);
+  pipe_fds_[1] = -1;  // Mark as closed for TearDown logic
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kModerateTimeoutMs);
+  ASSERT_GE(nfds, 0) << "epoll_wait failed: " << strerror(errno);
+
+  bool hup_received = false;
+  bool out_received = false;
+  bool in_received_for_eof = false;
+
+  if (nfds > 0) {
+    ASSERT_EQ(events_[0].data.fd, pipe_fds_[0]);
+    if (events_[0].events & EPOLLIN) {
+      in_received_for_eof = true;
+    }
+    if (events_[0].events & EPOLLHUP) {
+      hup_received = true;
+    }
+    if (events_[0].events & EPOLLOUT) {
+      out_received = true;
+    }
+
+    ASSERT_TRUE(in_received_for_eof || hup_received)
+        << "Expected EPOLLIN (EOF) or EPOLLHUP on read end when write end "
+           "closed. Events: "
+        << events_[0].events;
+    ASSERT_FALSE(out_received)
+        << "EPOLLOUT incorrectly signalled for read-only pipe end when write "
+           "end closed. Events: "
+        << events_[0].events;
+  } else {
+    char c_buf;
+    // Attempt a read to ensure EOF is processed by the kernel for pipe_fds_[0]
+    read(pipe_fds_[0], &c_buf, 1);  // This should see EOF (return 0) or error.
+
+    nfds = epoll_wait(epfd_, events_, kMaxEvents, kModerateTimeoutMs);
+    ASSERT_GT(nfds, 0) << "No event reported on read-end after write-end "
+                          "closed and explicit read attempt. Errno: "
+                       << (errno ? strerror(errno) : "none");
+    if (nfds > 0) {
+      ASSERT_EQ(events_[0].data.fd, pipe_fds_[0]);
+      if (events_[0].events & EPOLLIN) {
+        in_received_for_eof = true;
+      }
+      if (events_[0].events & EPOLLHUP) {
+        hup_received = true;
+      }
+      if (events_[0].events & EPOLLOUT) {
+        out_received = true;
+      }
+
+      // After a read attempt on a pipe with a closed write end,
+      // EPOLLIN (due to EOF) and EPOLLHUP are expected.
+      ASSERT_TRUE(in_received_for_eof && hup_received)
+          << "Expected EPOLLIN (EOF) and EPOLLHUP after read attempt. Events: "
+          << events_[0].events;
+      ASSERT_FALSE(out_received)
+          << "EPOLLOUT incorrectly signalled for read-only pipe end when write "
+             "end closed. Events: "
+          << events_[0].events;
+    }
+  }
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, WaitForReadOnWriteOnlyPipeEndWhenReadEndClosed) {
+  AddToEpoll(pipe_fds_[1], EPOLLIN | EPOLLERR | EPOLLHUP);
+
+  ASSERT_NE(pipe_fds_[0], -1);  // Ensure read end is initially valid
+  close(pipe_fds_[0]);
+  pipe_fds_[0] = -1;  // Mark as closed for TearDown logic
+
+  char c = 'x';
+  // Attempting to write to a pipe whose read end is closed should eventually
+  // cause an error. This write helps ensure the kernel flags the FD with an
+  // error state (EPIPE). It might succeed if the pipe buffer isn't full yet,
+  // but subsequent epoll_wait should catch the error. Non-blocking write is
+  // fine, we care about the state epoll reports.
+  write(pipe_fds_[1], &c,
+        1);  // The result doesn't strictly matter for this write call itself.
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kModerateTimeoutMs);
+
+  ASSERT_GT(nfds, 0) << "epoll_wait should report an event on write end when "
+                        "read end is closed. nfds="
+                     << nfds
+                     << ", errno=" << (errno ? strerror(errno) : "none");
+
+  if (nfds > 0) {
+    ASSERT_EQ(events_[0].data.fd, pipe_fds_[1]);
+    bool err_received = (events_[0].events & EPOLLERR);
+    // EPOLLHUP often accompanies EPOLLERR for pipes in this broken state.
+    // bool hup_received = (events_[0].events & EPOLLHUP);
+    ASSERT_TRUE(err_received) << "EPOLLERR not signalled for write-only pipe "
+                                 "end when read end closed. Events: "
+                              << events_[0].events;
+    ASSERT_FALSE(events_[0].events & EPOLLIN)
+        << "EPOLLIN incorrectly signalled for write-only pipe end. Events: "
+        << events_[0].events;
+  }
+  RemoveFromEpoll(pipe_fds_[1]);
+}
+
+/* The following error scenarios are untested for epoll_wait():
path: starboard/nplb/posix_compliance/posix_epoll_wait_test.cc
user: login: andrewsavage1
body: rec moving to top
created_at: 2025-05-21T18:23:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,219 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_ctl ---
+class PosixEpollCtlTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+
+  void SetUp() override {
+    epfd_ = epoll_create1(0);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+};
+
+TEST_F(PosixEpollCtlTests, AddFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN | EPOLLOUT;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_ADD failed: " << strerror(errno);
+}
+
+TEST_F(PosixEpollCtlTests, ModifyFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
path: starboard/nplb/posix_compliance/posix_epoll_ctl_test.cc
user: login: madhurajayaraman
body: Sounds good, I can update this.
created_at: 2025-05-21T18:36:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+TEST(PosixEpollCreate1Tests, CreateSuccessfully) {
+  int epfd = epoll_create1(0);
+  ASSERT_NE(epfd, -1) << "epoll_create1(0) failed: " << strerror(errno);
+  ASSERT_EQ(close(epfd), 0) << "close failed: " << strerror(errno);
+}
+
+TEST(PosixEpollCreate1Tests, CreateSuccessfullyWithCloExec) {
+  int epfd = epoll_create1(EPOLL_CLOEXEC);
+  ASSERT_NE(epfd, -1) << "epoll_create1(EPOLL_CLOEXEC) failed: "
+                      << strerror(errno);
+
+  int flags = fcntl(epfd, F_GETFD);
+  ASSERT_NE(flags, -1) << "fcntl(F_GETFD) failed: " << strerror(errno);
+  ASSERT_TRUE(flags & FD_CLOEXEC) << "FD_CLOEXEC was not set.";
+  ASSERT_EQ(close(epfd), 0) << "close failed: " << strerror(errno);
+}
+
+TEST(PosixEpollCreate1Tests, ErrorInvalidFlags) {
+  // An arbitrary invalid flag value.
+  // EPOLL_CLOEXEC is 0x80000. We pick another bit not used by epoll_create1.
+  const int kInvalidFlag = 0x1;
+  int epfd = epoll_create1(kInvalidFlag);
+  ASSERT_EQ(epfd, -1);
+  ASSERT_EQ(errno, EINVAL);
+  // No fd to close as creation failed.
+}
+
+/* The following error scenarios are untested for epoll_create1():
path: starboard/nplb/posix_compliance/posix_epoll_create_test.cc
user: login: madhurajayaraman
body: Moved to top
created_at: 2025-05-21T20:32:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,219 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_ctl ---
+class PosixEpollCtlTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+
+  void SetUp() override {
+    epfd_ = epoll_create1(0);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+};
+
+TEST_F(PosixEpollCtlTests, AddFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN | EPOLLOUT;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_ADD failed: " << strerror(errno);
+}
+
+TEST_F(PosixEpollCtlTests, ModifyFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_ADD for MOD test failed: " << strerror(errno);
+
+  event.events = EPOLLOUT;  // Modify to only EPOLLOUT
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_MOD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_MOD failed: " << strerror(errno);
+}
+
+TEST_F(PosixEpollCtlTests, DeleteFdSuccessfully) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_ADD for DEL test failed: " << strerror(errno);
+
+  // The 'event' parameter is ignored for EPOLL_CTL_DEL but must be non-NULL on
+  // older kernels. Modern kernels (>= 2.6.9) allow NULL. For compliance, pass a
+  // valid pointer.
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_DEL, pipe_fds_[0], &event), 0)
+      << "EPOLL_CTL_DEL failed: " << strerror(errno);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorBadEpfd) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(kInvalidFd, EPOLL_CTL_ADD, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, EBADF);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorBadFdOnAdd) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = kInvalidFd;
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, kInvalidFd, &event), -1);
+  ASSERT_EQ(errno, EBADF);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorBadFdOnMod) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = kInvalidFd;  // This is the FD we are trying to MOD.
+
+  // First, add a valid fd to have something in the epoll set.
+  struct epoll_event valid_event;
+  valid_event.events = EPOLLIN;
+  valid_event.data.fd = pipe_fds_[0];
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &valid_event), 0);
+
+  // Try to MOD using an fd that is itself invalid.
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_MOD, kInvalidFd, &event), -1);
+  ASSERT_EQ(errno, EBADF);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorAlreadyExistsOnAdd) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), 0)
+      << "First EPOLL_CTL_ADD failed: " << strerror(errno);
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, EEXIST);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorEpfdIsNotEpollFd) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+
+  // Use one end of the pipe as a non-epoll fd for epfd argument
+  ASSERT_EQ(epoll_ctl(pipe_fds_[1], EPOLL_CTL_ADD, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorFdIsSameAsEpfd) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = epfd_;  // Trying to add epfd to itself
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, epfd_, &event), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorInvalidOperation) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];
+  // An arbitrary integer that isn't a valid EPOLL_CTL operation.
+  const int kInvalidOp = 99;
+
+  ASSERT_EQ(epoll_ctl(epfd_, kInvalidOp, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorLoopBetweenTwoEpollInstances) {
+  int epfd2 = epoll_create1(0);
+  ASSERT_NE(epfd2, -1)
+      << "Failed to create second epoll instance for ELOOP test: "
+      << strerror(errno);
+
+  // Try A watches B, B watches A
+  struct epoll_event ev_a_watches_b;
+  ev_a_watches_b.events = EPOLLIN;
+  ev_a_watches_b.data.fd = epfd2;  // epfd_ will watch epfd2
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, epfd2, &ev_a_watches_b), 0)
+      << "epoll_ctl add epfd2 to epfd_ failed: " << strerror(errno);
+
+  struct epoll_event ev_b_watches_a;
+  ev_b_watches_a.events = EPOLLIN;
+  ev_b_watches_a.data.fd = epfd_;  // epfd2 tries to watch epfd_
+  ASSERT_EQ(epoll_ctl(epfd2, EPOLL_CTL_ADD, epfd_, &ev_b_watches_a), -1);
+  ASSERT_EQ(errno, ELOOP);
+
+  // Clean up: remove epfd2 from epfd_
+  epoll_ctl(epfd_, EPOLL_CTL_DEL, epfd2, &ev_a_watches_b);
+  if (epfd2 >= 0) {
+    close(epfd2);
+  }
+}
+
+TEST_F(PosixEpollCtlTests, ErrorFdNotRegisteredOnMod) {
+  struct epoll_event event;
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];  // This fd is valid but not yet added
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_MOD, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, ENOENT);
+}
+
+TEST_F(PosixEpollCtlTests, ErrorFdNotRegisteredOnDel) {
+  struct epoll_event event;  // Dummy event for DEL
+  event.events = EPOLLIN;
+  event.data.fd = pipe_fds_[0];  // This fd is valid but not yet added
+
+  ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_DEL, pipe_fds_[0], &event), -1);
+  ASSERT_EQ(errno, ENOENT);
+}
+
+/* The following error scenarios are untested for epoll_ctl():
path: starboard/nplb/posix_compliance/posix_epoll_ctl_test.cc
user: login: madhurajayaraman
body: Moved to top.
created_at: 2025-05-21T20:32:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,46 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// A helper function to create a pipe.
+// Returns true on success, false on failure.
+// pipe_fds[0] is the read end, pipe_fds[1] is the write end.
+bool CreatePipe(int pipe_fds[2], int flags = 0) {
+  if (flags == 0) {
+    return pipe(pipe_fds) == 0;
+  }
+  return pipe2(pipe_fds, flags) == 0;
+}
+
+// Test fixture for epoll tests
+class PosixEpollTest : public ::testing::Test {
+ protected:
+  static const int kInvalidFd = -123;  // An fd value that is likely invalid.
path: starboard/nplb/posix_compliance/posix_epoll_test_helper.cc
user: login: madhurajayaraman
body: Using -1 isntead.
created_at: 2025-05-21T20:32:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,327 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_wait ---
+class PosixEpollWaitTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+  struct epoll_event events_[kMaxEvents];
+
+  void SetUp() override {
+    epfd_ = epoll_create1(0);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    // Use non-blocking pipes to prevent writes from blocking indefinitely if
+    // pipe is full
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+    // NOTE: No FDs are added to epoll instance by default in SetUp.
+    // Tests are responsible for adding/removing FDs they monitor.
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+
+  // Helper to add to epoll
+  void AddToEpoll(int fd_to_add, uint32_t ev_mask) {
+    struct epoll_event event;
+    event.events = ev_mask;
+    event.data.fd = fd_to_add;
+    ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, fd_to_add, &event), 0)
+        << "Failed to add fd " << fd_to_add << " to epoll with events "
+        << ev_mask << ": " << strerror(errno);
+  }
+
+  // Helper to remove from epoll
+  void RemoveFromEpoll(int fd_to_remove) {
+    struct epoll_event event {};  // Dummy event, required for older kernels
+    if (epfd_ >= 0 && fd_to_remove >= 0) {
+      epoll_ctl(epfd_, EPOLL_CTL_DEL, fd_to_remove, &event);
+    }
+  }
+};
+
+TEST_F(PosixEpollWaitTests, EventReportedSuccessfully) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch read end for input
+
+  char buffer = 'x';
+  ASSERT_EQ(write(pipe_fds_[1], &buffer, 1), 1)
+      << "Write to pipe failed: " << strerror(errno);
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kModerateTimeoutMs);
+  ASSERT_EQ(nfds, 1) << "epoll_wait did not return 1 event: " << strerror(errno)
+                     << " (nfds=" << nfds << ")";
+  ASSERT_EQ(events_[0].data.fd, pipe_fds_[0]);
+  ASSERT_TRUE(events_[0].events & EPOLLIN);
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, TimeoutZeroReturnsImmediately) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch something
path: starboard/nplb/posix_compliance/posix_epoll_wait_test.cc
user: login: madhurajayaraman
body: Remove.d
created_at: 2025-05-21T20:32:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,327 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_wait ---
+class PosixEpollWaitTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+  struct epoll_event events_[kMaxEvents];
+
+  void SetUp() override {
+    epfd_ = epoll_create1(0);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    // Use non-blocking pipes to prevent writes from blocking indefinitely if
+    // pipe is full
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+    // NOTE: No FDs are added to epoll instance by default in SetUp.
+    // Tests are responsible for adding/removing FDs they monitor.
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+
+  // Helper to add to epoll
+  void AddToEpoll(int fd_to_add, uint32_t ev_mask) {
+    struct epoll_event event;
+    event.events = ev_mask;
+    event.data.fd = fd_to_add;
+    ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, fd_to_add, &event), 0)
+        << "Failed to add fd " << fd_to_add << " to epoll with events "
+        << ev_mask << ": " << strerror(errno);
+  }
+
+  // Helper to remove from epoll
+  void RemoveFromEpoll(int fd_to_remove) {
+    struct epoll_event event {};  // Dummy event, required for older kernels
+    if (epfd_ >= 0 && fd_to_remove >= 0) {
+      epoll_ctl(epfd_, EPOLL_CTL_DEL, fd_to_remove, &event);
+    }
+  }
+};
+
+TEST_F(PosixEpollWaitTests, EventReportedSuccessfully) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch read end for input
+
+  char buffer = 'x';
+  ASSERT_EQ(write(pipe_fds_[1], &buffer, 1), 1)
+      << "Write to pipe failed: " << strerror(errno);
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kModerateTimeoutMs);
+  ASSERT_EQ(nfds, 1) << "epoll_wait did not return 1 event: " << strerror(errno)
+                     << " (nfds=" << nfds << ")";
+  ASSERT_EQ(events_[0].data.fd, pipe_fds_[0]);
+  ASSERT_TRUE(events_[0].events & EPOLLIN);
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, TimeoutZeroReturnsImmediately) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch something
+
+  // Ensure no events are pending initially by draining the pipe
+  char buffer[10];
+  while (read(pipe_fds_[0], buffer, sizeof(buffer)) > 0)
+    ;  // Drain
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, 0);  // 0ms timeout
+  ASSERT_EQ(nfds, 0) << "epoll_wait with 0 timeout did not return 0: "
+                     << strerror(errno);
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, TimeoutPositiveReturnsAfterTimeout) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch something
+
+  // Ensure no events are pending initially
+  char buffer[10];
+  while (read(pipe_fds_[0], buffer, sizeof(buffer)) > 0)
+    ;  // Drain
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kShortTimeoutMs);
+  ASSERT_EQ(nfds, 0)
+      << "epoll_wait with positive timeout did not return 0 (event occurred?): "
+      << strerror(errno);
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, MaxEventsLimitsReturnedEvents) {
+  int p2[2] = {-1, -1};
+  ASSERT_TRUE(CreatePipe(p2, O_NONBLOCK));
+  int pipe2_read_fd = p2[0];
+  int pipe2_write_fd = p2[1];
+
+  AddToEpoll(pipe_fds_[0], EPOLLIN);
+  AddToEpoll(pipe2_read_fd, EPOLLIN);
+
+  char buffer = 'z';
+  ASSERT_EQ(write(pipe_fds_[1], &buffer, 1), 1);
+  ASSERT_EQ(write(pipe2_write_fd, &buffer, 1), 1);
+
+  const int kMaxEventsForThisTest = 1;
+  struct epoll_event single_event[kMaxEventsForThisTest];
+  int nfds = epoll_wait(epfd_, single_event, kMaxEventsForThisTest,
+                        kModerateTimeoutMs);
+  ASSERT_EQ(nfds, kMaxEventsForThisTest)
+      << "epoll_wait did not return max_events: " << strerror(errno);
+
+  RemoveFromEpoll(pipe_fds_[0]);
+  RemoveFromEpoll(pipe2_read_fd);
+
+  if (pipe2_read_fd >= 0) {
+    close(pipe2_read_fd);
+  }
+  if (pipe2_write_fd >= 0) {
+    close(pipe2_write_fd);
+  }
+}
+
+TEST_F(PosixEpollWaitTests, ErrorBadEpfd) {
+  ASSERT_EQ(epoll_wait(kInvalidFd, events_, kMaxEvents, 0), -1);
+  ASSERT_EQ(errno, EBADF);
+}
+
+TEST_F(PosixEpollWaitTests, ErrorInvalidMaxEventsZero) {
+  ASSERT_EQ(epoll_wait(epfd_, events_, 0, 0), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollWaitTests, ErrorInvalidMaxEventsNegative) {
+  ASSERT_EQ(epoll_wait(epfd_, events_, -1, 0), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollWaitTests, ErrorEpfdIsNotEpollFd) {
+  // Use one end of the pipe as a non-epoll fd for epfd argument
+  // (pipe_fds_[1] is valid from SetUp)
+  ASSERT_EQ(epoll_wait(pipe_fds_[1], events_, kMaxEvents, 0), -1);
+  ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(PosixEpollWaitTests, WaitForWriteOnReadOnlyPipeEndNeverSignalsWritable) {
+  // pipe_fds_[0] is the read end, inherently not writable.
+  // We expect a timeout, not EPOLLOUT.
+  AddToEpoll(pipe_fds_[0], EPOLLOUT);
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kShortTimeoutMs);
+
+  ASSERT_EQ(nfds, 0)
+      << "epoll_wait should timeout for EPOLLOUT on read-only pipe end. "
+      << "nfds=" << nfds << ", errno=" << (errno ? strerror(errno) : "none")
+      << (nfds > 0 ? ", event=" + std::to_string(events_[0].events) : "");
+  if (nfds > 0) {
+    ASSERT_FALSE(events_[0].events & EPOLLOUT)
+        << "EPOLLOUT incorrectly signalled for read-only pipe end.";
+  }
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, WaitForReadOnWriteOnlyPipeEndNeverSignalsReadable) {
+  // pipe_fds_[1] is the write end, inherently not readable.
+  // We expect a timeout, not EPOLLIN.
+  AddToEpoll(pipe_fds_[1], EPOLLIN);
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kShortTimeoutMs);
+
+  ASSERT_EQ(nfds, 0)
+      << "epoll_wait should timeout for EPOLLIN on write-only pipe end. "
+      << "nfds=" << nfds << ", errno=" << (errno ? strerror(errno) : "none")
+      << (nfds > 0 ? ", event=" + std::to_string(events_[0].events) : "");
+  if (nfds > 0) {
+    ASSERT_FALSE(events_[0].events & EPOLLIN)
+        << "EPOLLIN incorrectly signalled for write-only pipe end.";
+  }
+  RemoveFromEpoll(pipe_fds_[1]);
+}
+
+TEST_F(PosixEpollWaitTests, WaitForWriteOnReadOnlyPipeEndWhenWriteEndClosed) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN | EPOLLOUT | EPOLLHUP);
+
+  ASSERT_NE(pipe_fds_[1], -1);  // Ensure write end is initially valid
+  close(pipe_fds_[1]);
+  pipe_fds_[1] = -1;  // Mark as closed for TearDown logic
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kModerateTimeoutMs);
+  ASSERT_GE(nfds, 0) << "epoll_wait failed: " << strerror(errno);
+
+  bool hup_received = false;
+  bool out_received = false;
+  bool in_received_for_eof = false;
+
+  if (nfds > 0) {
+    ASSERT_EQ(events_[0].data.fd, pipe_fds_[0]);
+    if (events_[0].events & EPOLLIN) {
+      in_received_for_eof = true;
+    }
+    if (events_[0].events & EPOLLHUP) {
+      hup_received = true;
+    }
+    if (events_[0].events & EPOLLOUT) {
+      out_received = true;
+    }
+
+    ASSERT_TRUE(in_received_for_eof || hup_received)
+        << "Expected EPOLLIN (EOF) or EPOLLHUP on read end when write end "
+           "closed. Events: "
+        << events_[0].events;
+    ASSERT_FALSE(out_received)
+        << "EPOLLOUT incorrectly signalled for read-only pipe end when write "
+           "end closed. Events: "
+        << events_[0].events;
+  } else {
+    char c_buf;
+    // Attempt a read to ensure EOF is processed by the kernel for pipe_fds_[0]
+    read(pipe_fds_[0], &c_buf, 1);  // This should see EOF (return 0) or error.
+
+    nfds = epoll_wait(epfd_, events_, kMaxEvents, kModerateTimeoutMs);
+    ASSERT_GT(nfds, 0) << "No event reported on read-end after write-end "
+                          "closed and explicit read attempt. Errno: "
+                       << (errno ? strerror(errno) : "none");
+    if (nfds > 0) {
+      ASSERT_EQ(events_[0].data.fd, pipe_fds_[0]);
+      if (events_[0].events & EPOLLIN) {
+        in_received_for_eof = true;
+      }
+      if (events_[0].events & EPOLLHUP) {
+        hup_received = true;
+      }
+      if (events_[0].events & EPOLLOUT) {
+        out_received = true;
+      }
+
+      // After a read attempt on a pipe with a closed write end,
+      // EPOLLIN (due to EOF) and EPOLLHUP are expected.
+      ASSERT_TRUE(in_received_for_eof && hup_received)
+          << "Expected EPOLLIN (EOF) and EPOLLHUP after read attempt. Events: "
+          << events_[0].events;
+      ASSERT_FALSE(out_received)
+          << "EPOLLOUT incorrectly signalled for read-only pipe end when write "
+             "end closed. Events: "
+          << events_[0].events;
+    }
+  }
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, WaitForReadOnWriteOnlyPipeEndWhenReadEndClosed) {
+  AddToEpoll(pipe_fds_[1], EPOLLIN | EPOLLERR | EPOLLHUP);
+
+  ASSERT_NE(pipe_fds_[0], -1);  // Ensure read end is initially valid
+  close(pipe_fds_[0]);
+  pipe_fds_[0] = -1;  // Mark as closed for TearDown logic
+
+  char c = 'x';
+  // Attempting to write to a pipe whose read end is closed should eventually
+  // cause an error. This write helps ensure the kernel flags the FD with an
+  // error state (EPIPE). It might succeed if the pipe buffer isn't full yet,
+  // but subsequent epoll_wait should catch the error. Non-blocking write is
+  // fine, we care about the state epoll reports.
+  write(pipe_fds_[1], &c,
+        1);  // The result doesn't strictly matter for this write call itself.
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kModerateTimeoutMs);
+
+  ASSERT_GT(nfds, 0) << "epoll_wait should report an event on write end when "
+                        "read end is closed. nfds="
+                     << nfds
+                     << ", errno=" << (errno ? strerror(errno) : "none");
+
+  if (nfds > 0) {
+    ASSERT_EQ(events_[0].data.fd, pipe_fds_[1]);
+    bool err_received = (events_[0].events & EPOLLERR);
+    // EPOLLHUP often accompanies EPOLLERR for pipes in this broken state.
+    // bool hup_received = (events_[0].events & EPOLLHUP);
+    ASSERT_TRUE(err_received) << "EPOLLERR not signalled for write-only pipe "
+                                 "end when read end closed. Events: "
+                              << events_[0].events;
+    ASSERT_FALSE(events_[0].events & EPOLLIN)
+        << "EPOLLIN incorrectly signalled for write-only pipe end. Events: "
+        << events_[0].events;
+  }
+  RemoveFromEpoll(pipe_fds_[1]);
+}
+
+/* The following error scenarios are untested for epoll_wait():
path: starboard/nplb/posix_compliance/posix_epoll_wait_test.cc
user: login: madhurajayaraman
body: moved.
created_at: 2025-05-21T20:32:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,219 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_ctl ---
path: starboard/nplb/posix_compliance/posix_epoll_ctl_test.cc
user: login: madhurajayaraman
body: remved.
created_at: 2025-05-21T20:33:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,327 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+// --- Tests for epoll_wait ---
+class PosixEpollWaitTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+  struct epoll_event events_[kMaxEvents];
+
+  void SetUp() override {
+    epfd_ = epoll_create1(0);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    // Use non-blocking pipes to prevent writes from blocking indefinitely if
+    // pipe is full
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+    // NOTE: No FDs are added to epoll instance by default in SetUp.
+    // Tests are responsible for adding/removing FDs they monitor.
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+
+  // Helper to add to epoll
+  void AddToEpoll(int fd_to_add, uint32_t ev_mask) {
+    struct epoll_event event;
+    event.events = ev_mask;
+    event.data.fd = fd_to_add;
+    ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, fd_to_add, &event), 0)
+        << "Failed to add fd " << fd_to_add << " to epoll with events "
+        << ev_mask << ": " << strerror(errno);
+  }
+
+  // Helper to remove from epoll
+  void RemoveFromEpoll(int fd_to_remove) {
+    struct epoll_event event {};  // Dummy event, required for older kernels
+    if (epfd_ >= 0 && fd_to_remove >= 0) {
+      epoll_ctl(epfd_, EPOLL_CTL_DEL, fd_to_remove, &event);
+    }
+  }
+};
+
+TEST_F(PosixEpollWaitTests, EventReportedSuccessfully) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch read end for input
+
+  char buffer = 'x';
+  ASSERT_EQ(write(pipe_fds_[1], &buffer, 1), 1)
+      << "Write to pipe failed: " << strerror(errno);
+
+  int nfds = epoll_wait(epfd_, events_, kMaxEvents, kModerateTimeoutMs);
+  ASSERT_EQ(nfds, 1) << "epoll_wait did not return 1 event: " << strerror(errno)
+                     << " (nfds=" << nfds << ")";
+  ASSERT_EQ(events_[0].data.fd, pipe_fds_[0]);
+  ASSERT_TRUE(events_[0].events & EPOLLIN);
+  RemoveFromEpoll(pipe_fds_[0]);
+}
+
+TEST_F(PosixEpollWaitTests, TimeoutZeroReturnsImmediately) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch something
+
+  // Ensure no events are pending initially by draining the pipe
+  char buffer[10];
+  while (read(pipe_fds_[0], buffer, sizeof(buffer)) > 0)
path: starboard/nplb/posix_compliance/posix_epoll_wait_test.cc
user: login: madhurajayaraman
body: Changed
created_at: 2025-05-21T20:33:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,286 @@
+// Copyright 2025 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/* The following error scenarios are untested for epoll_wait():
+1. EFAULT (events pointer is bad) is difficult to safely and reliably test.
+2. EINTR (interrupted by signal) is difficult to test.
+3. Negative timeout is an infinite timeout, which is difficult to test.
+*/
+
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#include "starboard/nplb/posix_compliance/posix_epoll_test_helper.cc"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+class PosixEpollWaitTests : public PosixEpollTest {
+ protected:
+  int epfd_ = -1;
+  int pipe_fds_[2] = {-1, -1};  // pipe_fds_[0] for read, pipe_fds_[1] for write
+  struct epoll_event events_[kMaxEvents];
+
+  void SetUp() override {
+    epfd_ = epoll_create(1);
+    ASSERT_NE(epfd_, -1) << "Failed to create epoll instance in SetUp: "
+                         << strerror(errno);
+    // Use non-blocking pipes to prevent writes from blocking indefinitely if
+    // pipe is full
+    ASSERT_TRUE(CreatePipe(pipe_fds_, O_NONBLOCK))
+        << "Failed to create pipe in SetUp: " << strerror(errno);
+  }
+
+  void TearDown() override {
+    if (epfd_ >= 0) {
+      close(epfd_);
+      epfd_ = -1;
+    }
+    if (pipe_fds_[0] >= 0) {
+      close(pipe_fds_[0]);
+      pipe_fds_[0] = -1;
+    }
+    if (pipe_fds_[1] >= 0) {
+      close(pipe_fds_[1]);
+      pipe_fds_[1] = -1;
+    }
+  }
+
+  // Helper to add to epoll
+  void AddToEpoll(int fd_to_add, uint32_t ev_mask) {
+    struct epoll_event event = {};
+    event.events = ev_mask;
+    event.data.fd = fd_to_add;
+    ASSERT_EQ(epoll_ctl(epfd_, EPOLL_CTL_ADD, fd_to_add, &event), 0)
+        << "Failed to add fd " << fd_to_add << " to epoll with events "
+        << ev_mask << ": " << strerror(errno);
+  }
+
+  // Helper to remove from epoll
+  void RemoveFromEpoll(int fd_to_remove) {
+    struct epoll_event event {};  // Dummy event, required for older kernels
+    if (epfd_ >= 0 && fd_to_remove >= 0) {
+      epoll_ctl(epfd_, EPOLL_CTL_DEL, fd_to_remove, &event);
+    }
+  }
+};
+
+TEST_F(PosixEpollWaitTests, EventReportedSuccessfully) {
+  AddToEpoll(pipe_fds_[0], EPOLLIN);  // Watch read end for input
+
+  char buffer = 'x';
+  ASSERT_EQ(write(pipe_fds_[1], &buffer, 1), 1)
path: starboard/nplb/posix_compliance/posix_epoll_wait_test.cc
user: login: yell0wd0g
body: micro-nit: Ideally this "1"s would be labelled, e.g.
```
  const size_t buffer_length = sizeof(buffer);
  ASSERT_EQ(write(pipe_fds_[1], &buffer, buffer_length), buffer_length)
      << ...
```
Otherwise is unclear whether they are the same (or e.g.
the second one is a different number).
created_at: 2025-05-22T20:58:01Z
author_association: CONTRIBUTOR

PR comments:
user: login: yell0wd0g
created_at: 2025-04-28T16:56:18Z
body: @madhurajayaraman what's the story with this PR/CL? It has had two rounds of reviews and has been alive for 
author_association: CONTRIBUTOR
user: login: yell0wd0g
created_at: 2025-05-06T03:20:33Z
body: Any news here?
author_association: CONTRIBUTOR
user: login: madhurajayaraman
created_at: 2025-05-20T15:40:40Z
body: Closed all previous comments since I rewrote the tests entirely.
If there are larger, structural comments about how the PR is set up, please ping me and I can update the Gem!
author_association: CONTRIBUTOR