TEST_F(TaskThreadTest, theTaskThreadShutsDownWhenTheQueueIsDestroyed) {
    // the TaskThread only has a weak pointer to the queue, once it goes out of scope the thread will shutdown
    TaskThread taskThread{createTaskQueue()};
    taskThread.start();

    // wait for the thread to shutdown
    std::this_thread::sleep_for(SHORT_TIMEOUT_MS);
    ASSERT_EQ(taskThread.isShutdown(), true);
}
TEST_F(TaskThreadTest, theTaskThreadShutsDownWhenTheQueueIsShutdown) {
    auto queue = createTaskQueue();
    TaskThread taskThread{queue};
    taskThread.start();

    queue->shutdown();

    // wait for the thread to shutdown
    std::this_thread::sleep_for(SHORT_TIMEOUT_MS);
    ASSERT_EQ(taskThread.isShutdown(), true);
}
void WSCoreBoundQueuesScheduler::init(){
  _status = START_UP;
  // set _queues to queues after new queues have been created to new tasks to be assigned to new queues
  // lock _queue mutex as queues are manipulated
  std::lock_guard<lock_t> lk(_queuesMutex);
  for (size_t i = 0; i < _queues; ++i) {
    task_queue_t *queue = createTaskQueue(i);
    queue->init();
    _taskQueues.push_back(queue);
  }
  _status = RUN;
}
TEST_F(TaskThreadTest, theTaskThreadReadsFromAGivenNonEmptyQueue) {
    auto queue = createTaskQueue();
    auto future = queue->push(TASK, VALUE);

    TaskThread taskThread{queue};
    taskThread.start();

    auto status = future.wait_for(SHORT_TIMEOUT_MS);
    ASSERT_EQ(status, std::future_status::ready);
    ASSERT_EQ(future.get(), VALUE);

    // shutting down the queue will lead to the thread shutting down
    queue->shutdown();
}
WSCoreBoundPriorityQueuesScheduler::WSCoreBoundPriorityQueuesScheduler(const int queues) : AbstractCoreBoundQueuesScheduler(){
  _status = START_UP;
  // set _queues to queues after new queues have been created to new tasks to be assigned to new queues
  // lock _queue mutex as queues are manipulated
  {
    std::lock_guard<lock_t> lk(_queuesMutex);
    if (queues <= getNumberOfCoresOnSystem()) {
      for (int i = 0; i < queues; ++i) {
        _taskQueues.push_back(createTaskQueue(i));
      }
      _queues = queues;
    } else {
      LOG4CXX_WARN(_logger, "number of queues exceeds available cores; set it to max available cores, which equals to " << std::to_string(getNumberOfCoresOnSystem()));
      for (int i = 0; i < getNumberOfCoresOnSystem(); ++i) {
        _taskQueues.push_back(createTaskQueue(i));
      }
      _queues = getNumberOfCoresOnSystem();
    }
  }
  for (unsigned i = 0; i < _taskQueues.size(); ++i) {
    static_cast<WSCoreBoundPriorityQueue *>(_taskQueues[i])->refreshQueues();
  }
  _status = RUN;
}
TEST_F(TaskThreadTest, theTaskThreadIsNotStartedUntilStartIsCalled) {
    auto queue = createTaskQueue();
    auto future = queue->push(TASK, VALUE);
    TaskThread taskThread{queue};

    // wait for long enough that the task would normall be run
    auto failedStatus = future.wait_for(SHORT_TIMEOUT_MS);
    ASSERT_EQ(failedStatus, std::future_status::timeout);

    // start the thread
    taskThread.start();

    // now it should succeed almost immediately
    auto successStatus = future.wait_for(SHORT_TIMEOUT_MS);
    ASSERT_EQ(successStatus, std::future_status::ready);
    ASSERT_EQ(future.get(), VALUE);

    // shutting down the queue will lead to the thread shutting down
    queue->shutdown();
}