// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/components/nearby/condition_variable_impl.h"

#include <memory>

#include "base/bind.h"
#include "base/single_thread_task_runner.h"
#include "base/task/post_task.h"
#include "base/test/gtest_util.h"
#include "base/test/scoped_task_environment.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_restrictions.h"
#include "chromeos/components/nearby/lock_base.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace chromeos {

namespace nearby {

namespace {

class FakeLock : public LockBase {
 public:
  FakeLock() : condition_variable_(&lock_) {}
  ~FakeLock() override = default;

  // location::nearby::Lock:
  void lock() override {
    base::AutoLock al(lock_);
    ++num_locks_;
    condition_variable_.Signal();
  }

  void unlock() override {
    base::AutoLock al(lock_);
    ++num_unlocks_;
    condition_variable_.Signal();
  }

  // chromeos::nearby::LockBase:
  bool IsHeldByCurrentThread() override { return is_held_by_current_thread_; }

  void set_is_held_by_current_thread(bool value) {
    is_held_by_current_thread_ = value;
  }

  int num_locks() {
    base::AutoLock al(lock_);
    return num_locks_;
  }

  int num_unlocks() {
    base::AutoLock al(lock_);
    return num_unlocks_;
  }

  void WaitForLocksAndUnlocks(int expected_num_locks,
                              int expected_num_unlocks) {
    base::AutoLock al(lock_);
    while (expected_num_locks != num_locks_ ||
           expected_num_unlocks != num_unlocks_) {
      condition_variable_.Wait();
    }
  }

 private:
  base::Lock lock_;
  base::ConditionVariable condition_variable_;
  bool is_held_by_current_thread_ = false;
  int num_locks_ = 0;
  int num_unlocks_ = 0;

  DISALLOW_COPY_AND_ASSIGN(FakeLock);
};

}  // namespace

class ConditionVariableImplTest : public testing::Test {
 protected:
  ConditionVariableImplTest()
      : fake_lock_(std::make_unique<FakeLock>()),
        condition_variable_(
            std::make_unique<ConditionVariableImpl>(fake_lock_.get())) {}

  // testing::Test
  void TearDown() override {
    scoped_task_environment_.RunUntilIdle();
    EXPECT_EQ(fake_lock_->num_locks(), fake_lock_->num_unlocks());
  }

  location::nearby::ConditionVariable* condition_variable() {
    return condition_variable_.get();
  }

  FakeLock* fake_lock() { return fake_lock_.get(); }

  void WaitOnConditionVariableFromParallelSequence(bool should_succeed) {
    base::PostTask(
        FROM_HERE,
        base::BindOnce(&ConditionVariableImplTest::WaitOnConditionVariable,
                       base::Unretained(this), should_succeed));
  }

  // Invoked whenever attempting to verify that a parallel task has indeed
  // blocked, since there's no way to deterministically find out if that task
  // will ever unblock.
  void TinyTimeout() {
    base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
  }

  void VerifyNumLocksAndUnlocks(int expected_num_locks,
                                int expected_num_unlocks) {
    EXPECT_EQ(expected_num_locks, fake_lock_->num_locks());
    EXPECT_EQ(expected_num_unlocks, fake_lock_->num_unlocks());
  }

  // To ensure that |condition_variable_| is blocking as expected, wait until
  // its |fake_lock_| has been locked and unlocked once per blocked sequence.
  // Then manually wait, and verify afterwards that the number of locks and
  // unlocks remain unchanged.
  void VerifyBlockedConditionVariable(int expected_num_blocked_sequences) {
    fake_lock()->WaitForLocksAndUnlocks(
        expected_num_blocked_sequences /* expected_num_locks */,
        expected_num_blocked_sequences /* expected_num_unlocks */);
    TinyTimeout();
    VerifyNumLocksAndUnlocks(
        expected_num_blocked_sequences /* expected_num_locks */,
        expected_num_blocked_sequences /* expected_num_unlocks */);
  }

  base::test::ScopedTaskEnvironment scoped_task_environment_;

 private:
  void WaitOnConditionVariable(bool should_succeed) {
    const base::ScopedAllowBaseSyncPrimitivesForTesting allow_sync_primitives;

    // ConditionVariable::wait() should only be called by a thread that already
    // owns the associated Lock. This is not tested as the expected behavior is
    // either undefined or specified by the particular Lock implementation.
    fake_lock_->lock();

    if (should_succeed)
      condition_variable_->wait();
    else
      EXPECT_DCHECK_DEATH(condition_variable_->wait());

    // ConditionVariable::wait() will call Lock::lock() after unblocking, so
    // this undoes that.
    fake_lock_->unlock();
  }

  std::unique_ptr<FakeLock> fake_lock_;
  std::unique_ptr<location::nearby::ConditionVariable> condition_variable_;

  DISALLOW_COPY_AND_ASSIGN(ConditionVariableImplTest);
};

TEST_F(ConditionVariableImplTest,
       SingleSequence_BlocksOnWaitAndUnblocksOnNotify) {
  WaitOnConditionVariableFromParallelSequence(true /* should_succeed */);
  VerifyBlockedConditionVariable(1 /* expected_num_blocked_sequences */);

  // Should unblock after notify().
  condition_variable()->notify();
  scoped_task_environment_.RunUntilIdle();
  VerifyNumLocksAndUnlocks(2 /* expected_num_locks */,
                           2 /* expected_num_unlocks */);
}

TEST_F(ConditionVariableImplTest,
       MultipleSequences_BlocksOnWaitAndUnblocksOnNotify) {
  WaitOnConditionVariableFromParallelSequence(true /* should_succeed */);
  WaitOnConditionVariableFromParallelSequence(true /* should_succeed */);
  WaitOnConditionVariableFromParallelSequence(true /* should_succeed */);
  VerifyBlockedConditionVariable(3 /* expected_num_blocked_sequences */);

  // All should unblock after notify().
  condition_variable()->notify();
  scoped_task_environment_.RunUntilIdle();
  VerifyNumLocksAndUnlocks(6 /* expected_num_locks */,
                           6 /* expected_num_unlocks */);
}

TEST_F(ConditionVariableImplTest, ThreadCannotWaitIfStillOwnsLock) {
  fake_lock()->set_is_held_by_current_thread(true);
  WaitOnConditionVariableFromParallelSequence(false /* should_succeed */);
}

}  // namespace nearby

}  // namespace chromeos
