/*
 * Copyright (c) 2022 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.
 */

#ifdef USE_PURGEABLE_MEMORY
#include <thread>

#include "gtest/gtest.h"
#include "purgeable_mem_utils.h"
#include "utils.h"

#define private public
#define protected public
#include "app_state_subscriber.h"
#include "mem_mgr_client.h"
#include "memory_level_manager.h"
#include "memmgr_config_manager.h"
#include "purgeable_mem_manager.h"
#include "system_memory_level_config.h"
#undef private
#undef protected

namespace OHOS {
namespace Memory {
namespace {
static constexpr int32_t SLEEP_TIME = 500;
static constexpr int32_t SLEEP_TIME_LONG = 5000;
}
using namespace testing;
using namespace testing::ext;

class AppStateSubscriberTest : public AppStateSubscriber {
public:
    void OnConnected() override;
    void OnDisconnected() override;
    void OnAppStateChanged(int32_t pid, int32_t uid, int32_t state) override;
    void ForceReclaim(int32_t pid, int32_t uid) override;
    void OnTrim(SystemMemoryLevel level) override;
    void OnRemoteDied(const wptr<IRemoteObject> &object) override;
    int OnConnectedCallTimes = 0;
    int OnDisconnectedCallTimes = 0;
    int OnAppStateChangedCallTimes = 0;
    int ForceReclaimCallTimes = 0;
    int OnTrimCallTimes = 0;
    int OnRemoteDiedCallTimes = 0;
};

class PurgeableMemMgrTest : public testing::Test {
public:
    static void SetUpTestCase();
    static void TearDownTestCase();
    void SetUp();
    void TearDown();
    inline void SleepForFC()
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME));
    }
    inline void SleepForFiveSecond()
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_LONG));
    }
    static std::shared_ptr<MemMgrClient> memMgrClient_;
    static std::vector<std::shared_ptr<AppStateSubscriberTest>> appStateSubscriberTests;
};
std::vector<std::shared_ptr<AppStateSubscriberTest>> PurgeableMemMgrTest::appStateSubscriberTests =
    std::vector<std::shared_ptr<AppStateSubscriberTest>>();
void AppStateSubscriberTest::OnConnected()
{
    OnConnectedCallTimes++;
}

void AppStateSubscriberTest::OnDisconnected()
{
    OnDisconnectedCallTimes++;
}

void AppStateSubscriberTest::OnAppStateChanged(int32_t pid, int32_t uid, int32_t state)
{
    OnAppStateChangedCallTimes++;
}

void AppStateSubscriberTest::ForceReclaim(int32_t pid, int32_t uid)
{
    ForceReclaimCallTimes++;
}

void AppStateSubscriberTest::OnTrim(SystemMemoryLevel level)
{
    OnTrimCallTimes++;
}

void AppStateSubscriberTest::OnRemoteDied(const wptr<IRemoteObject> &object)
{
    OnRemoteDiedCallTimes++;
}

void PurgeableMemMgrTest::SetUpTestCase()
{
}

void PurgeableMemMgrTest::TearDownTestCase()
{
}

void PurgeableMemMgrTest::SetUp()
{
}

void PurgeableMemMgrTest::TearDown()
{
    for (auto appStateSubscriberTest_ : appStateSubscriberTests) {
        MemMgrClient::GetInstance().UnsubscribeAppState(*appStateSubscriberTest_);
    }
    appStateSubscriberTests.clear();
}

class PurgeableMemUtilsTest : public testing::Test {
public:
    static void SetUpTestCase();
    static void TearDownTestCase();
    void SetUp();
    void TearDown();
};

void PurgeableMemUtilsTest::SetUpTestCase()
{
}

void PurgeableMemUtilsTest::TearDownTestCase()
{
}

void PurgeableMemUtilsTest::SetUp()
{
}

void PurgeableMemUtilsTest::TearDown()
{
}

HWTEST_F(PurgeableMemMgrTest, SubscribeAppState_Test, TestSize.Level1)
{
    std::shared_ptr<AppStateSubscriberTest> appStateSubscriberTest_1 = std::make_shared<AppStateSubscriberTest>();
    EXPECT_NE(appStateSubscriberTest_1, nullptr);
    MemMgrClient::GetInstance().SubscribeAppState(*appStateSubscriberTest_1);
    appStateSubscriberTests.emplace_back(appStateSubscriberTest_1);
    SleepForFC();
    EXPECT_EQ(appStateSubscriberTest_1->OnConnectedCallTimes, 1);
    MemMgrClient::GetInstance().SubscribeAppState(*appStateSubscriberTest_1);
    SleepForFC();
    EXPECT_EQ(appStateSubscriberTest_1->OnConnectedCallTimes, 1);
    std::shared_ptr<AppStateSubscriberTest> appStateSubscriberTest_2 = std::make_shared<AppStateSubscriberTest>();
    EXPECT_NE(appStateSubscriberTest_2, nullptr);
    MemMgrClient::GetInstance().SubscribeAppState(*appStateSubscriberTest_2);
    appStateSubscriberTests.emplace_back(appStateSubscriberTest_2);
    SleepForFC();
    EXPECT_EQ(appStateSubscriberTest_1->OnConnectedCallTimes, 1);
    EXPECT_EQ(appStateSubscriberTest_2->OnConnectedCallTimes, 1);
}

HWTEST_F(PurgeableMemMgrTest, UnsubscribeAppState_Test, TestSize.Level1)
{
    std::shared_ptr<AppStateSubscriberTest> appStateSubscriberTest_1 = std::make_shared<AppStateSubscriberTest>();
    EXPECT_NE(appStateSubscriberTest_1, nullptr);
    MemMgrClient::GetInstance().SubscribeAppState(*appStateSubscriberTest_1);
    appStateSubscriberTests.emplace_back(appStateSubscriberTest_1);
    SleepForFC();
    MemMgrClient::GetInstance().UnsubscribeAppState(*appStateSubscriberTest_1);
    SleepForFC();
    EXPECT_EQ(appStateSubscriberTest_1->OnDisconnectedCallTimes, 1);
}

HWTEST_F(PurgeableMemMgrTest, AppStateListener_Test, TestSize.Level1)
{
    auto subscriber = AppStateSubscriberTest();
    auto subscriberImpl = std::make_shared<AppStateSubscriber::AppStateSubscriberImpl>(subscriber);
    subscriberImpl->recipient_ = sptr<AppStateSubscriber::AppStateSubscriberImpl::DeathRecipient>(
        new AppStateSubscriber::AppStateSubscriberImpl::DeathRecipient(*subscriberImpl));
    subscriberImpl->OnConnected();
    EXPECT_EQ(subscriber.OnConnectedCallTimes, 1);
    subscriberImpl->OnDisconnected();
    EXPECT_EQ(subscriber.OnDisconnectedCallTimes, 1);
    SystemMemoryLevel level = SystemMemoryLevel::MEMORY_LEVEL_MODERATE;
    subscriberImpl->OnTrim(level);
    EXPECT_EQ(subscriber.OnTrimCallTimes, 1);
    int32_t pid = 2001;
    int32_t uid = 20012001;
    int32_t state = 1;
    subscriberImpl->OnAppStateChanged(pid, uid, state);
    EXPECT_EQ(subscriber.OnAppStateChangedCallTimes, 1);
    subscriberImpl->ForceReclaim(pid, uid);
    EXPECT_EQ(subscriber.ForceReclaimCallTimes, 1);
    subscriberImpl->recipient_->OnRemoteDied(nullptr);
    EXPECT_EQ(subscriber.OnRemoteDiedCallTimes, 1);
}

HWTEST_F(PurgeableMemUtilsTest, GetPurgeableHeapInfoTest, TestSize.Level1)
{
    int reclaimableKB;
    bool ret = PurgeableMemUtils::GetInstance().GetPurgeableHeapInfo(reclaimableKB);
    printf("ret=%d,reclaimableKB=%dKB\n", ret, reclaimableKB);
    ret = ret && reclaimableKB >= 0;
    EXPECT_EQ(ret, true);
}

HWTEST_F(PurgeableMemUtilsTest, GetProcPurgeableHeapInfoTest, TestSize.Level1)
{
    int reclaimableKB;
    bool ret = PurgeableMemUtils::GetInstance().GetProcPurgeableHeapInfo(1, reclaimableKB);
    printf("pid=%d,reclaimableKB=%dKB\n", 1, reclaimableKB);
    ret = ret && reclaimableKB >= 0;
    EXPECT_EQ(ret, true);
}

HWTEST_F(PurgeableMemUtilsTest, PurgeHeapAllTest, TestSize.Level1)
{
    bool ret = PurgeableMemUtils::GetInstance().PurgeHeapAll();
    EXPECT_EQ(ret, true);
}

HWTEST_F(PurgeableMemUtilsTest, PurgeHeapAllTestDebug1, TestSize.Level1)
{
    const char *path = PurgeableMemUtils::PATH_PURGE_HEAP.c_str();
    int fd = open(path, O_WRONLY);
    if (fd == -1) {
        printf("open %s failed!\n", path);
    }
    ASSERT_NE(fd, -1);
    close(fd);
}

HWTEST_F(PurgeableMemUtilsTest, PurgeHeapMemcgTest, TestSize.Level1)
{
    std::string memcgPath = "/dev/memcg";
    bool ret = PurgeableMemUtils::GetInstance().PurgeHeapMemcg(memcgPath, 1024);
    EXPECT_EQ(ret, true);
}

HWTEST_F(PurgeableMemUtilsTest, PurgeAshmAllTest, TestSize.Level1)
{
    bool ret = PurgeableMemUtils::GetInstance().PurgeAshmAll();
    EXPECT_EQ(ret, true);
}

HWTEST_F(PurgeableMemUtilsTest, PurgeAshmByIdWithTimeTest, TestSize.Level1)
{
    std::string idWithTime = "1000 1000";
    bool ret = PurgeableMemUtils::GetInstance().PurgeAshmByIdWithTime(idWithTime);
    EXPECT_EQ(ret, true);
}
} //namespace Memory
} //namespace OHOS
#endif // USE_PURGEABLE_MEMORY