<commit_before>/*
 *
 * Copyright 2018 Asylo authors
 *
 * 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 <sys/epoll.h>
#include <unistd.h>
#include <chrono>
#include <thread>

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/container/flat_hash_set.h"
#include "asylo/test/util/status_matchers.h"

namespace asylo {
namespace {

constexpr const char *kTestString = "Will this go through the pipe?";
constexpr size_t kBufferSize = 1024;
constexpr size_t kNumPipes = 8;
constexpr int kRead = 0;
constexpr int kWrite = 1;

class EpollTest : public ::testing::Test {
 protected:
  Status WriteData(int fd, const char *str) {
    ssize_t num_bytes_left = strlen(str);
    while (num_bytes_left > 0) {
      ssize_t num_bytes_written = write(fd, str, num_bytes_left);
      if (num_bytes_written < 0) {
        return Status(error::GoogleError::INTERNAL, "write() failed");
      }
      num_bytes_left -= num_bytes_written;
    }
    return Status::OkStatus();
  }

  Status ReadData(int fd, char *buf, size_t bytes_to_read) {
    while (bytes_to_read > 0) {
      int num_bytes_read = read(fd, buf, bytes_to_read);
      if (num_bytes_read < 0) {
        return Status(error::GoogleError::INTERNAL, "read() failed");
      }
      bytes_to_read -= num_bytes_read;
    }
    return Status::OkStatus();
  }

  void WriteToPipes(const std::vector<int> &write_fds, const char *str) {
    for (int fd : write_fds) {
      EXPECT_THAT(WriteData(fd, str), IsOk());
    }
  }

  void RegisterFds(int epfd, int pipe_idx, int additional_flags = 0) {
    for (size_t i = 0; i < kNumPipes; ++i) {
      // Create the epoll event we want to add.
      struct epoll_event ev;
      ev.events = pipe_idx == 0 ? EPOLLIN : EPOLLOUT;
      ev.events |= additional_flags;
      ev.data.fd = fd_pairs_[i][pipe_idx];
      ASSERT_NE(epoll_ctl(epfd, EPOLL_CTL_ADD, fd_pairs_[i][pipe_idx], &ev),
                -1);
    }
  }

  void InitializePipes() {
    for (int i = 0; i < kNumPipes; ++i) {
      ASSERT_EQ(pipe(fd_pairs_[i]), 0);
    }
  }

  void ClosePipes() {
    for (int i = 0; i < kNumPipes; ++i) {
      close(fd_pairs_[i][0]);
      close(fd_pairs_[i][1]);
    }
  }

  // Verify that only the first kNumPipes/2 fds have registered read events.
  void VerifyReadEvents(int epfd) {
    struct epoll_event events[kNumPipes];
    int num_events = epoll_wait(epfd, events, kNumPipes, -1);
    ASSERT_NE(num_events, -1);
    EXPECT_EQ(num_events, kNumPipes / 2);
    absl::flat_hash_set<int> read_fds;
    for (int i = 0; i < num_events; ++i) {
      // Make sure that the current fd hasn't been encountered before.
      ASSERT_EQ(read_fds.find(events[i].data.fd), read_fds.end());
      read_fds.insert(events[i].data.fd);
    }
    // Make sure that the first kNumPipes/2 read fds are in our set.
    for (int i = 0; i < kNumPipes / 2; ++i) {
      ASSERT_NE(read_fds.find(fd_pairs_[i][kRead]), read_fds.end());
    }
    // Makes sure the last kNumPipes/2 read fds are not in our set.
    for (int i = kNumPipes / 2; i < kNumPipes; ++i) {
      ASSERT_EQ(read_fds.find(fd_pairs_[i][kRead]), read_fds.end());
    }
  }

  void BasicEpollTest(bool edge_triggered) {
    InitializePipes();
    int epfd = epoll_create(1);
    ASSERT_NE(epfd, -1);
    // Register all read ends from fd_pairs_ with this epoll instance.
    int additional_flags = edge_triggered ? EPOLLET : 0;
    RegisterFds(epfd, kRead, additional_flags);
    std::vector<int> write_fds;
    // Only write to the first kNumPipes/2.
    for (int i = 0; i < kNumPipes / 2; ++i) {
      write_fds.push_back(fd_pairs_[i][kWrite]);
    }
    WriteToPipes(write_fds, kTestString);
    VerifyReadEvents(epfd);
    ASSERT_EQ(close(epfd), 0);
    ClosePipes();
  }

  void TimeoutTest(int sleep_dur, int timeout) {
    InitializePipes();
    int epfd = epoll_create(1);
    ASSERT_NE(epfd, -1);<commit_msg>Fix conditional expression warning in epoll_test<commit_after>/*
 *
 * Copyright 2018 Asylo authors
 *
 * 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 <sys/epoll.h>
#include <unistd.h>
#include <chrono>
#include <thread>

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/container/flat_hash_set.h"
#include "asylo/test/util/status_matchers.h"

namespace asylo {
namespace {

constexpr const char *kTestString = "Will this go through the pipe?";
constexpr size_t kBufferSize = 1024;
constexpr size_t kNumPipes = 8;
constexpr int kRead = 0;
constexpr int kWrite = 1;

class EpollTest : public ::testing::Test {
 protected:
  Status WriteData(int fd, const char *str) {
    ssize_t num_bytes_left = strlen(str);
    while (num_bytes_left > 0) {
      ssize_t num_bytes_written = write(fd, str, num_bytes_left);
      if (num_bytes_written < 0) {
        return Status(error::GoogleError::INTERNAL, "write() failed");
      }
      num_bytes_left -= num_bytes_written;
    }
    return Status::OkStatus();
  }

  Status ReadData(int fd, char *buf, size_t bytes_to_read) {
    while (bytes_to_read > 0) {
      int num_bytes_read = read(fd, buf, bytes_to_read);
      if (num_bytes_read < 0) {
        return Status(error::GoogleError::INTERNAL, "read() failed");
      }
      bytes_to_read -= num_bytes_read;
    }
    return Status::OkStatus();
  }

  void WriteToPipes(const std::vector<int> &write_fds, const char *str) {
    for (int fd : write_fds) {
      EXPECT_THAT(WriteData(fd, str), IsOk());
    }
  }

  void RegisterFds(int epfd, int pipe_idx, int additional_flags = 0) {
    for (size_t i = 0; i < kNumPipes; ++i) {
      // Create the epoll event we want to add.
      struct epoll_event ev;
      ev.events = pipe_idx == 0 ? EPOLLIN : EPOLLOUT;
      ev.events |= additional_flags;
      ev.data.fd = fd_pairs_[i][pipe_idx];
      ASSERT_NE(epoll_ctl(epfd, EPOLL_CTL_ADD, fd_pairs_[i][pipe_idx], &ev),
                -1);
    }
  }

  void InitializePipes() {
    for (int i = 0; i < kNumPipes; ++i) {
      ASSERT_EQ(pipe(fd_pairs_[i]), 0);
    }
  }

  void ClosePipes() {
    for (int i = 0; i < kNumPipes; ++i) {
      close(fd_pairs_[i][0]);
      close(fd_pairs_[i][1]);
    }
  }

  // Verify that only the first kNumPipes/2 fds have registered read events.
  void VerifyReadEvents(int epfd) {
    struct epoll_event events[kNumPipes];
    int num_events = epoll_wait(epfd, events, kNumPipes, -1);
    ASSERT_NE(num_events, -1);
    EXPECT_EQ(num_events, kNumPipes / 2);
    absl::flat_hash_set<int> read_fds;
    for (int i = 0; i < num_events; ++i) {
      // Make sure that the current fd hasn't been encountered before.
      ASSERT_EQ(read_fds.find(events[i].data.fd), read_fds.end());
      read_fds.insert(events[i].data.fd);
    }
    // Make sure that the first kNumPipes/2 read fds are in our set.
    for (int i = 0; i < kNumPipes / 2; ++i) {
      ASSERT_NE(read_fds.find(fd_pairs_[i][kRead]), read_fds.end());
    }
    // Makes sure the last kNumPipes/2 read fds are not in our set.
    for (int i = kNumPipes / 2; i < kNumPipes; ++i) {
      ASSERT_EQ(read_fds.find(fd_pairs_[i][kRead]), read_fds.end());
    }
  }

  void BasicEpollTest(bool edge_triggered) {
    InitializePipes();
    int epfd = epoll_create(1);
    ASSERT_NE(epfd, -1);
    // Register all read ends from fd_pairs_ with this epoll instance.
    if (edge_triggered) {
      RegisterFds(epfd, kRead, /*additional_flags=*/EPOLLET);
    } else {
      RegisterFds(epfd, kRead);
    }
    std::vector<int> write_fds;
    // Only write to the first kNumPipes/2.
    for (int i = 0; i < kNumPipes / 2; ++i) {
      write_fds.push_back(fd_pairs_[i][kWrite]);
    }
    WriteToPipes(write_fds, kTestString);
    VerifyReadEvents(epfd);
    ASSERT_EQ(close(epfd), 0);
    ClosePipes();
  }

  void TimeoutTest(int sleep_dur, int timeout) {
    InitializePipes();
    int epfd = epoll_create(1);
    ASSERT_NE(epfd, -1);
{'fraction_non_alphanumeric': 0.1238267556259188, 'fraction_numerical': 0.010516792943571187, 'mean_word_length': 3.213434969032873, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1671997', 'n_tokens_mistral': 3223, 'n_tokens_neox': 3154, 'n_words': 840}