Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c1a2deb6 authored by Erwin Jansen's avatar Erwin Jansen
Browse files

Rootcanal: do not starve the reader in unittest

On an M1 the writer thread can write faster than the reader can read.
This results in the reader never exiting the loop, causing the test to
hang.

We now lower the rate of writing to make sure the readers can always
keep up.

Bug: 251187705
Test: Unit tests now succeed on M1
Change-Id: Ia675c3b3b0613b2b00a588a803473a3d997bf0ee
parent ec6a7848
Loading
Loading
Loading
Loading
+30 −18
Original line number Original line Diff line number Diff line
@@ -32,8 +32,8 @@
#include <mutex>               // for mutex
#include <mutex>               // for mutex
#include <ratio>               // for ratio
#include <ratio>               // for ratio
#include <string>              // for string
#include <string>              // for string
#include <tuple>               // for tuple
#include <thread>
#include <thread>
#include <tuple>  // for tuple


#include "osi/include/osi.h"  // for OSI_NO_INTR
#include "osi/include/osi.h"  // for OSI_NO_INTR


@@ -125,6 +125,8 @@ class AsyncManagerSocketTest : public ::testing::Test {
  void SetUp() override {
  void SetUp() override {
    memset(server_buffer_, 0, kBufferSize);
    memset(server_buffer_, 0, kBufferSize);
    memset(client_buffer_, 0, kBufferSize);
    memset(client_buffer_, 0, kBufferSize);
    socket_fd_ = -1;
    connection_fd_ = -1;


    socket_fd_ = StartServer();
    socket_fd_ = StartServer();


@@ -139,7 +141,9 @@ class AsyncManagerSocketTest : public ::testing::Test {
  void TearDown() override {
  void TearDown() override {
    async_manager_.StopWatchingFileDescriptor(socket_fd_);
    async_manager_.StopWatchingFileDescriptor(socket_fd_);
    close(socket_fd_);
    close(socket_fd_);
    ASSERT_EQ(std::string_view(server_buffer_, kBufferSize), std::string_view(client_buffer_, kBufferSize));
    close(connection_fd_);
    ASSERT_EQ(std::string_view(server_buffer_, kBufferSize),
              std::string_view(client_buffer_, kBufferSize));
  }
  }


  int ConnectClient() {
  int ConnectClient() {
@@ -193,6 +197,8 @@ TEST_F(AsyncManagerSocketTest, TestOneConnection) {
}
}


TEST_F(AsyncManagerSocketTest, CanUnsubscribeInCallback) {
TEST_F(AsyncManagerSocketTest, CanUnsubscribeInCallback) {
  using namespace std::chrono_literals;

  int socket_cli_fd = ConnectClient();
  int socket_cli_fd = ConnectClient();
  WriteFromClient(socket_cli_fd);
  WriteFromClient(socket_cli_fd);
  AwaitServerResponse(socket_cli_fd);
  AwaitServerResponse(socket_cli_fd);
@@ -211,37 +217,40 @@ TEST_F(AsyncManagerSocketTest, CanUnsubscribeInCallback) {


  while (!stopped) {
  while (!stopped) {
    write(socket_cli_fd, data.data(), data.size());
    write(socket_cli_fd, data.data(), data.size());
    std::this_thread::sleep_for(5ms);
  }
  }


  SUCCEED();
  SUCCEED();
  close(socket_cli_fd);
  close(socket_cli_fd);
}
}



TEST_F(AsyncManagerSocketTest, CanUnsubscribeTaskFromWithinTask) {
TEST_F(AsyncManagerSocketTest, CanUnsubscribeTaskFromWithinTask) {
  Event running;
  Event running;
  using namespace std::chrono_literals;
  using namespace std::chrono_literals;
  async_manager_.ExecAsyncPeriodically(1, 1ms, 2ms, [&running, this]() {
  async_manager_.ExecAsyncPeriodically(1, 1ms, 2ms, [&running, this]() {
     EXPECT_TRUE(async_manager_.CancelAsyncTask(1)) << "We were scheduled, so cancel should return true";
    EXPECT_TRUE(async_manager_.CancelAsyncTask(1))
     EXPECT_FALSE(async_manager_.CancelAsyncTask(1)) << "We were not scheduled, so cancel should return false";
        << "We were scheduled, so cancel should return true";
    EXPECT_FALSE(async_manager_.CancelAsyncTask(1))
        << "We were not scheduled, so cancel should return false";
    running.set(true);
    running.set(true);
  });
  });


  EXPECT_TRUE(running.wait_for(10ms));
  EXPECT_TRUE(running.wait_for(10ms));
}
}



TEST_F(AsyncManagerSocketTest, UnsubScribeWaitsUntilCompletion) {
TEST_F(AsyncManagerSocketTest, UnsubScribeWaitsUntilCompletion) {
  using namespace std::chrono_literals;
  using namespace std::chrono_literals;
  Event running;
  Event running;
  bool cancel_done = false;
  bool cancel_done = false;
  bool task_complete = false;
  bool task_complete = false;
  async_manager_.ExecAsyncPeriodically(1, 1ms, 2ms, [&running, &cancel_done, &task_complete]() {
  async_manager_.ExecAsyncPeriodically(
      1, 1ms, 2ms, [&running, &cancel_done, &task_complete]() {
        // Let the other thread now we are in the callback..
        // Let the other thread now we are in the callback..
        running.set(true);
        running.set(true);
        // Wee bit of a hack that relies on timing..
        // Wee bit of a hack that relies on timing..
        std::this_thread::sleep_for(20ms);
        std::this_thread::sleep_for(20ms);
      EXPECT_FALSE(cancel_done) << "Task cancellation did not wait for us to complete!";
        EXPECT_FALSE(cancel_done)
            << "Task cancellation did not wait for us to complete!";
        task_complete = true;
        task_complete = true;
      });
      });


@@ -249,11 +258,14 @@ TEST_F(AsyncManagerSocketTest, UnsubScribeWaitsUntilCompletion) {
  auto start = std::chrono::system_clock::now();
  auto start = std::chrono::system_clock::now();


  // There is a 20ms wait.. so we know that this should take some time.
  // There is a 20ms wait.. so we know that this should take some time.
  EXPECT_TRUE(async_manager_.CancelAsyncTask(1)) << "We were scheduled, so cancel should return true";
  EXPECT_TRUE(async_manager_.CancelAsyncTask(1))
      << "We were scheduled, so cancel should return true";
  cancel_done = true;
  cancel_done = true;
  EXPECT_TRUE(task_complete) << "We managed to cancel a task while it was not yet finished.";
  EXPECT_TRUE(task_complete)
      << "We managed to cancel a task while it was not yet finished.";
  auto end = std::chrono::system_clock::now();
  auto end = std::chrono::system_clock::now();
  auto passed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
  auto passed_ms =
      std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
  EXPECT_GT(passed_ms.count(), 10);
  EXPECT_GT(passed_ms.count(), 10);
}
}