text: /*
   * Copyright (c) 2021 Huawei Device Co., Ltd.
   * 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.
   */
  
  // redefine private and protected since testcase need to invoke and test private function
  #include <gtest/gtest.h>
  #include "app_log_wrapper.h"
  #include "base_task_dispatcher.h"
  #include "task_dispatcher_context.h"
  #include "task_dispatcher.h"
  #include "spec_task_dispatcher.h"
  
  using namespace testing::ext;
  using namespace OHOS::AppExecFwk;
  
  class SpecTaskDispatcherModuleTest : public testing::Test {
  public:
      static void SetUpTestCase();
      static void TearDownTestCase();
      void SetUp();
      void TearDown();
      std::shared_ptr<SpecTaskDispatcher> ptrSpecTaskDispatcher;
  };
  
  void SpecTaskDispatcherModuleTest::SetUpTestCase()
  {}
  
  void SpecTaskDispatcherModuleTest::TearDownTestCase()
  {}
  
  void SpecTaskDispatcherModuleTest::SetUp()
  {
      std::string dispatcherName = SpecDispatcherConfig::MAIN;
      TaskPriority taskPriority = TaskPriority::HIGH;
      std::shared_ptr<SpecDispatcherConfig> config = std::make_shared<SpecDispatcherConfig>(dispatcherName, taskPriority);
      std::shared_ptr<EventRunner> runner = EventRunner::Create(true);
      ptrSpecTaskDispatcher = std::make_shared<SpecTaskDispatcher>(config, runner);
  }
  
  void SpecTaskDispatcherModuleTest::TearDown()
  {
      ptrSpecTaskDispatcher = nullptr;
  }
  
  /**
   * @tc.number: SpecTaskDispatcher_SyncDispatchTest_001
   * @tc.name: SyncDispatch
   * @tc.desc: Test SpecTaskDispatcher sync dispatch.
   */
  HWTEST_F(SpecTaskDispatcherModuleTest, SpecTaskDispatcher_SyncDispatchTest_001, TestSize.Level1)
  {
      auto name = std::string("SpecTaskDispatcher_SyncDispatchTest_001");
      GTEST_LOG_(INFO) << name << " start";
  
      std::atomic<int> count(0);
      EXPECT_TRUE(count.load() == 0);
      long sleep1 = 200;
      ptrSpecTaskDispatcher->SyncDispatch(std::make_shared<Runnable>([&]() {
          auto time = std::chrono::milliseconds(sleep1);
          std::this_thread::sleep_for(time);
          int index = count.fetch_add(1);
          EXPECT_TRUE(index == 0);
          GTEST_LOG_(INFO) << name << " SyncDispatch1  : sleep1 time=" << sleep1;
      }));
      // serial execute
      EXPECT_TRUE(count.load() == 1);
  
      long sleep2 = 100;
      ptrSpecTaskDispatcher->SyncDispatch(std::make_shared<Runnable>([&]() {
          auto time = std::chrono::milliseconds(sleep2);
          std::this_thread::sleep_for(time);
          int index = count.fetch_add(1);
          EXPECT_TRUE(index == 1);
          GTEST_LOG_(INFO) << name << " SyncDispatch2  : sleep2 time=" << sleep2;
      }));
      // serial execute
      EXPECT_TRUE(count.load() == 2);
      long wait = sleep1 + sleep2 + 100;
      auto time = std::chrono::milliseconds(wait);
      std::this_thread::sleep_for(time);
      EXPECT_TRUE(count.load() == 2);
      GTEST_LOG_(INFO) << name << " end";
  }
  
  /**
   * @tc.number: SpecTaskDispatcher_AsyncDispatchTest_001
   * @tc.name: AsyncDispatch
   * @tc.desc: Test SpecTaskDispatcher async dispatch.
   */
  HWTEST_F(SpecTaskDispatcherModuleTest, SpecTaskDispatcher_AsyncDispatchTest_001, TestSize.Level1)
  {
      auto name = std::string("SpecTaskDispatcher_AsyncDispatchTest_001");
      GTEST_LOG_(INFO) << name + " start";
  
      std::atomic<int> count(0);
      long sleep1 = 200;
      ptrSpecTaskDispatcher->AsyncDispatch(std::make_shared<Runnable>([&]() {
          auto time = std::chrono::milliseconds(sleep1);
          std::this_thread::sleep_for(time);
          int index = count.fetch_add(1);
          EXPECT_TRUE(index == 0);
          GTEST_LOG_(INFO) << name << " AsyncDispatch1  : sleep2 time=" << sleep1;
      }));
      // async execute
      EXPECT_TRUE(count.load() < 1);
      long sleep2 = 100;
      ptrSpecTaskDispatcher->AsyncDispatch(std::make_shared<Runnable>([&]() {
          auto time = std::chrono::milliseconds(sleep2);
          std::this_thread::sleep_for(time);
          int index = count.fetch_add(1);
          EXPECT_TRUE(index == 1);
          GTEST_LOG_(INFO) << name << " AsyncDispatch2  : sleep2 time=" << sleep2;
      }));
      EXPECT_TRUE(count.load() < 2);
      long wait = sleep1 + sleep2 + 100;
      auto time = std::chrono::milliseconds(wait);
      std::this_thread::sleep_for(time);
      EXPECT_TRUE(count.load() == 2);
      GTEST_LOG_(INFO) << name + " end";
  }
  
  /**
   * @tc.number: SpecTaskDispatcher_DelayDispatchTest_001
   * @tc.name: DelayDispatch
   * @tc.desc: Test SpecTaskDispatcher delay dispatch.
   */
  HWTEST_F(SpecTaskDispatcherModuleTest, SpecTaskDispatcher_DelayDispatchTest_001, TestSize.Level0)
  {
      auto name = std::string("SpecTaskDispatcher_DelayDispatchTest_001");
      GTEST_LOG_(INFO) << name + " start";
  
      std::atomic<int> count(0);
      int sleep1 = 2000;
      const std::shared_ptr<Runnable> runnanle = std::make_shared<Runnable>([&count, sleep = sleep1]() {
          int index = count.fetch_add(1);
          EXPECT_TRUE(index == 2);
          GTEST_LOG_(INFO) << "SpecTaskDispatcher_DelayDispatchTest_001 task" + std::to_string(index) + "end, elapsed" +
                                  std::to_string(sleep) + " ms";
      });
      ptrSpecTaskDispatcher->DelayDispatch(runnanle, sleep1);
      EXPECT_TRUE(count.load() == 0);
  
      int sleep2 = 1000;
      ptrSpecTaskDispatcher->DelayDispatch(std::make_shared<Runnable>([&count, sleep = sleep2]() {
          int index = count.fetch_add(1);
          EXPECT_TRUE(index == 0 || index == 1);
          GTEST_LOG_(INFO) << "SpecTaskDispatcher_DelayDispatchTest_001 task" + std::to_string(index) + "end, elapsed" +
                                  std::to_string(sleep) + " ms";
      }),
          sleep2);
      EXPECT_TRUE(count.load() == 0);
  
      int sleep3 = 1000;
      ptrSpecTaskDispatcher->DelayDispatch(std::make_shared<Runnable>([&count, sleep = sleep3]() {
          int index = count.fetch_add(1);
          EXPECT_TRUE(index == 0 || index == 1);
          GTEST_LOG_(INFO) << "SpecTaskDispatcher_DelayDispatchTest_001 task" + std::to_string(index) + "end, elapsed" +
                                  std::to_string(sleep) + " ms";
      }),
          sleep3);
      EXPECT_TRUE(count.load() == 0);
  
      {
          long wait = 100;
          auto time = std::chrono::milliseconds(wait);
          std::this_thread::sleep_for(time);
      }
      {
          long wait = 1000;
          GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms");
          auto time = std::chrono::milliseconds(wait);
          std::this_thread::sleep_for(time);
          EXPECT_TRUE(count.load() == 2);
      }
      {
          long wait = 500;
          GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms");
          auto time = std::chrono::milliseconds(wait);
          std::this_thread::sleep_for(time);
          EXPECT_TRUE(count.load() == 2);
      }
      {
          long wait = 1000;
          GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms");
          auto time = std::chrono::milliseconds(wait);
          std::this_thread::sleep_for(time);
          EXPECT_TRUE(count.load() == 3);
      }
      GTEST_LOG_(INFO) << name + " end";
  }
  
  /**
   * @tc.number: SpecTaskDispatcher_DelayDispatchTest_002
   * @tc.name: DelayDispatch
   * @tc.desc: Test SpecTaskDispatcher delay dispatch.
   */
  HWTEST_F(SpecTaskDispatcherModuleTest, SpecTaskDispatcher_DelayDispatchTest_002, TestSize.Level0)
  {
      auto name = std::string("SpecTaskDispatcher_DelayDispatchTest_002");
      GTEST_LOG_(INFO) << name + " start";
  
      int sleep1 = 2000;
      ptrSpecTaskDispatcher->DelayDispatch(std::make_shared<Runnable>(nullptr), sleep1);
      GTEST_LOG_(INFO) << name + " end";
  }
  
  /**
   * @tc.number: SpecTaskDispatcher_DelayDispatchTest_003
   * @tc.name: DelayDispatch
   * @tc.desc: Test SpecTaskDispatcher delay dispatch.
   */
  HWTEST_F(SpecTaskDispatcherModuleTest, SpecTaskDispatcher_DelayDispatchTest_003, TestSize.Level0)
  {
      auto name = std::string("SpecTaskDispatcher_DelayDispatchTest_003");
      GTEST_LOG_(INFO) << name + " start";
  
      int sleep1 = 2000;
      ptrSpecTaskDispatcher->DelayDispatch(nullptr, sleep1);
      GTEST_LOG_(INFO) << name + " end";
  }
  
  /**
   * @tc.number: SpecTaskDispatcher_DelayDispatchTest_004
   * @tc.name: DelayDispatch
   * @tc.desc: Test SpecTaskDispatcher delay dispatch.
   */
  HWTEST_F(SpecTaskDispatcherModuleTest, SpecTaskDispatcher_DelayDispatchTest_004, TestSize.Level0)
  {
      auto name = std::string("SpecTaskDispatcher_DelayDispatchTest_004");
      GTEST_LOG_(INFO) << name + " start";
  
      std::atomic<int> count(0);
      int sleep1 = -2000;
      ptrSpecTaskDispatcher->DelayDispatch(std::make_shared<Runnable>([&count, sleep = sleep1]() {
          int index = count.fetch_add(1);
          EXPECT_TRUE(index == 1 || index == 0);
          GTEST_LOG_(INFO) << "SpecTaskDispatcher_DelayDispatchTest_004 task" + std::to_string(index) + "end, elapsed" +
                                  std::to_string(sleep) + " ms";
      }),
          sleep1);
  
      int sleep2 = -1000;
      ptrSpecTaskDispatcher->DelayDispatch(std::make_shared<Runnable>([&count, sleep = sleep2]() {
          int index = count.fetch_add(1);
          EXPECT_TRUE(index == 0 || index == 1);
          GTEST_LOG_(INFO) << "SpecTaskDispatcher_DelayDispatchTest_004 task" + std::to_string(index) + "end, elapsed" +
                                  std::to_string(sleep) + " ms";
      }),
          sleep2);
  
      {
          long wait = 100;
          GTEST_LOG_(INFO) << ("wait for task, wait= " + std::to_string(wait) + " ms");
          auto time = std::chrono::milliseconds(wait);
          std::this_thread::sleep_for(time);
          EXPECT_TRUE(count.load() == 2);
      }
      GTEST_LOG_(INFO) << name + " end";
  }
  
  /**
   * @tc.number: SpecTaskDispatcher_ApplyDispatchTest_001
   * @tc.name: ApplyDispatch
   * @tc.desc: Test SpecTaskDispatcher apply dispatch.
   */
  HWTEST_F(SpecTaskDispatcherModuleTest, SpecTaskDispatcher_ApplyDispatchTest_001, TestSize.Level0)
  {
      auto name = std::string("SpecTaskDispatcher_ApplyDispatchTest_001");
      GTEST_LOG_(INFO) << name + " start";
  
      std::atomic<int> count(0);
      long sleep1 = 101;
      auto repeats1 = std::make_shared<IteratableTask<long>>([&](long index) {
          auto time = std::chrono::milliseconds(sleep1);
          std::this_thread::sleep_for(time);
          count.fetch_add(1);
          GTEST_LOG_(INFO) << name << "  repeats1 sleep1=" << sleep1;
      });
      ptrSpecTaskDispatcher->ApplyDispatch(repeats1, 10);
  
      long sleep2 = 100;
      auto repeats2 = std::make_shared<IteratableTask<long>>([&](long index) {
          auto time = std::chrono::milliseconds(sleep2);
          std::this_thread::sleep_for(time);
          count.fetch_add(1);
          GTEST_LOG_(INFO) << name << "  repeats2 sleep2=" << sleep2;
      });
      ptrSpecTaskDispatcher->ApplyDispatch(repeats2, 10);
  
      // async execute
      EXPECT_TRUE(count.load() < 20);
      long wait = sleep1 * 10 + sleep2 * 10 + 100 + 100;
      GTEST_LOG_(INFO) << name << "  main wait time=" << wait;
      auto time = std::chrono::milliseconds(wait);
      std::this_thread::sleep_for(time);
      EXPECT_TRUE(count.load() == 20);
      GTEST_LOG_(INFO) << name + " end";
  }