text:
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------

#include "stdafx.h"

#include <stdlib.h>
#include <boost/test/unit_test.hpp>
#include "Common/boost-taef.h"

using namespace ktl;
using namespace TxnReplicator;
using namespace Data::StateManager;
using namespace Data::Utilities;

namespace StateManagerTests
{
    class CheckpointManagerTest : public StateManagerTestBase
    {
        // load the config object as its needed for the tracing to work
        Common::CommonConfig config;

    public:

        enum Enum
        {
            AllActive = 0,

            AllDeleted = 1,

            Both = 2,
        };

        KWString CreateFileName(__in KStringView const & name, __in KAllocator & allocator)
        {
            KWString fileStreamName(allocator, name);

            WCHAR currentDirectoryPathCharArray[MAX_PATH];
            GetCurrentDirectory(MAX_PATH, currentDirectoryPathCharArray);

            BOOL result = PathAppendW(currentDirectoryPathCharArray, fileStreamName);
            CODING_ERROR_ASSERT(result == 1);

            KWString fileName(allocator, Common::Path::GetPathGlobalNamespaceWstr().c_str());
            CODING_ERROR_ASSERT(NT_SUCCESS(fileName.Status()));

            KWString currentFilePath(allocator, currentDirectoryPathCharArray);
            CODING_ERROR_ASSERT(NT_SUCCESS(currentFilePath.Status()));

            fileName += currentFilePath;

            return fileName;
        }

        MetadataManager::SPtr CreateMetadataManagerAndPopulateMetadatas(__in Enum testMode, __in ULONG metadataCount, __out KSharedArray<Metadata::CSPtr>::SPtr & outArray)
        {
            MetadataManager::SPtr metadataManagerSPtr = TestHelper::CreateMetadataManager(GetAllocator());
            outArray = TestHelper::CreateMetadataArray(GetAllocator());

            for (LONG64 i = 0; i < metadataCount; i++)
            {
                KUri::CSPtr expectedName;
                wchar_t number = static_cast<wchar_t>(i);

                auto status = KUri::Create(KUriView(&number), GetAllocator(), expectedName);
                CODING_ERROR_ASSERT(NT_SUCCESS(status));

                auto metadata = TestHelper::CreateMetadata(*expectedName, false, i+1, GetAllocator());

                bool addActive = (Enum::AllActive == testMode);

                if (testMode == Enum::Both)
                {
                    addActive = (i % 2 == 1);
                }

                if (addActive)
                {
                    bool isAdded = metadataManagerSPtr->TryAdd(*expectedName, *metadata);
                    CODING_ERROR_ASSERT(isAdded == true);
                }
                else
                {
                    metadata->MetadataMode = MetadataMode::DelayDelete;
                    bool isAdded = metadataManagerSPtr->AddDeleted(i+1, *metadata);
                    CODING_ERROR_ASSERT(isAdded == true);
                }

                outArray->Append(metadata.RawPtr());
            }

            return metadataManagerSPtr;
        }

        void Test_PrepareCheckpoint_MultipleMetadata_SUCCESS(
            __in ULONG metadataCount,
            __in Enum testMode,
            __in FABRIC_STATE_PROVIDER_ID checkpointLSN,
            __in SerializationMode::Enum serializationMode)
        {
            KString::CSPtr workFolderPath = TestHelper::CreateFileString(GetAllocator(), L"Work");
            KString::SPtr replicaFolderPath = KPath::Combine(*workFolderPath, L"PID_RID", GetAllocator());
            Common::Directory::CreateDirectoryW(static_cast<LPCWSTR>(*replicaFolderPath));

            ApiDispatcher::SPtr apiDispatcher = ApiDispatcher::Create(
                *partitionedReplicaIdCSPtr_,
                *stateProviderFactorySPtr_,
                GetAllocator());

            CheckpointManager::SPtr checkpointManagerSPtr = nullptr;
            NTSTATUS status = CheckpointManager::Create(
                *partitionedReplicaIdCSPtr_,
                *apiDispatcher,
                *workFolderPath,
                *replicaFolderPath,
                serializationMode,
                GetAllocator(),
                checkpointManagerSPtr);
            CODING_ERROR_ASSERT(NT_SUCCESS(status));
            KSharedArray<Metadata::CSPtr>::SPtr metadataArray = nullptr;

            // Setup
            MetadataManager::SPtr metadataManager = CreateMetadataManagerAndPopulateMetadatas(testMode, metadataCount, metadataArray);
            checkpointManagerSPtr->PrepareCheckpoint(*metadataManager, checkpointLSN);

            // Test
            ULONG expectedActiveMetadataCount = 0;
            ULONG expectedDeletedMetadataCount = 0;

            if (testMode == Enum::AllActive)
            {
                expectedActiveMetadataCount = metadataCount;
            }
            else if (testMode == Enum::AllDeleted)
            {
                expectedDeletedMetadataCount = metadataCount;
            }
            else
            {
                expectedActiveMetadataCount = metadataCount / 2;
                expectedDeletedMetadataCount = metadataCount - expectedActiveMetadataCount;
            }

            KArray<Metadata::CSPtr> activeResult = checkpointManagerSPtr->GetPreparedActiveOrDeletedList(MetadataMode::Active);
            VERIFY_ARE_EQUAL(activeResult.Count(), expectedActiveMetadataCount);
            for (ULONG i = 0; i < expectedActiveMetadataCount; i++)
            {
                ULONG expectedMetadataIndex = static_cast<ULONG>(activeResult[i]->StateProviderId - 1);
                TestHelper::VerifyMetadata(activeResult[i].RawPtr(), (*metadataArray)[expectedMetadataIndex].RawPtr());
            }

            KArray<Metadata::CSPtr> deletedResult = checkpointManagerSPtr->GetPreparedActiveOrDeletedList(MetadataMode::DelayDelete);
            VERIFY_ARE_EQUAL(deletedResult.Count(), expectedDeletedMetadataCount);
            for (ULONG i = 0; i < expectedDeletedMetadataCount; i++)
            {
                ULONG expectedMetadataIndex = static_cast<ULONG>(deletedResult[i]->StateProviderId - 1);
                TestHelper::VerifyMetadata(deletedResult[i].RawPtr(), (*metadataArray)[expectedMetadataIndex].RawPtr());
            }

            VERIFY_ARE_EQUAL(checkpointManagerSPtr->PrepareCheckpointLSN, checkpointLSN);

            Common::Directory::Delete(static_cast<LPCWSTR>(*workFolderPath), true);
        }

        void Test_PerformCheckpointAsync_OneMetadata_SUCCESS(
            __in LONG64 checkpointLSN,
            __in SerializationMode::Enum serializationMode)
        {
            KString::CSPtr workFolderPath = TestHelper::CreateFileString(GetAllocator(), L"Work");
            KString::SPtr replicaFolderPath = KPath::Combine(*workFolderPath, L"PID_RID", GetAllocator());
            Common::Directory::CreateDirectoryW(static_cast<LPCWSTR>(*replicaFolderPath));

            ApiDispatcher::SPtr apiDispatcher = ApiDispatcher::Create(
                *partitionedReplicaIdCSPtr_,
                *stateProviderFactorySPtr_,
                GetAllocator());

            CheckpointManager::SPtr checkpointManagerSPtr = nullptr;
            NTSTATUS status = CheckpointManager::Create(
                *partitionedReplicaIdCSPtr_,
                *apiDispatcher,
                *workFolderPath,
                *replicaFolderPath,
                serializationMode,
                GetAllocator(),
                checkpointManagerSPtr);
            CODING_ERROR_ASSERT(NT_SUCCESS(status));
            KSharedArray<Metadata::CSPtr>::SPtr metadataArray = nullptr;

            // Setup
            MetadataManager::SPtr metadataManagerSPtr = TestHelper::CreateMetadataManager(GetAllocator());
            KUri::CSPtr expectedName;
            status = KUri::Create(KUriView(L"fabric:/sps/sp"), GetAllocator(), expectedName);
            CODING_ERROR_ASSERT(NT_SUCCESS(status));

            auto metadata = TestHelper::CreateMetadata(*expectedName, false, GetAllocator());
            bool isAdded = metadataManagerSPtr->TryAdd(*expectedName, *metadata);
            VERIFY_IS_TRUE(isAdded);
            checkpointManagerSPtr->PrepareCheckpoint(*metadataManagerSPtr, checkpointLSN);
            SyncAwait(checkpointManagerSPtr->PerformCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));

            // Test
            auto tempCheckpointFile = KPath::Combine(*replicaFolderPath, TempCheckpointPrefix, GetAllocator());

            CheckpointFile::SPtr checkpointFileReopenSPtr = nullptr;
            status = CheckpointFile::Create(
                *partitionedReplicaIdCSPtr_,
                KWString(GetAllocator(), *tempCheckpointFile),
                GetAllocator(),
                checkpointFileReopenSPtr);
            CODING_ERROR_ASSERT(NT_SUCCESS(status));
            SyncAwait(checkpointFileReopenSPtr->ReadAsync(CancellationToken::None));

            auto enumerator = checkpointFileReopenSPtr->GetAsyncEnumerator();
            ULONG32 i = 0;

            while (SyncAwait(enumerator->MoveNextAsync(CancellationToken::None)))
            {
                auto sermeta = enumerator->GetCurrent();
                CODING_ERROR_ASSERT(sermeta->StateProviderId == metadata->StateProviderId);
                CODING_ERROR_ASSERT(sermeta->ParentStateProviderId == metadata->ParentId);
                CODING_ERROR_ASSERT(sermeta->CreateLSN == metadata->CreateLSN);
                CODING_ERROR_ASSERT(sermeta->DeleteLSN == metadata->DeleteLSN);

                ++i;
            }

            CODING_ERROR_ASSERT(i == 1);

            SyncAwait(enumerator->CloseAsync());

            Common::Directory::Delete(static_cast<LPCWSTR>(*workFolderPath), true);
        }

        void Test_RecoverCheckpointAsync_MultipleMetadata_SUCCESS(
            __in ULONG metadataCount,
            __in LONG64 checkpointLSN,
            __in Enum testMode,
            __in SerializationMode::Enum serializationMode)
        {
            KString::CSPtr workFolderPath = TestHelper::CreateFileString(GetAllocator(), L"Work");
            KString::SPtr replicaFolderPath = KPath::Combine(*workFolderPath, L"PID_RID", GetAllocator());
            Common::Directory::CreateDirectoryW(static_cast<LPCWSTR>(*replicaFolderPath));

            ApiDispatcher::SPtr apiDispatcher = ApiDispatcher::Create(
                *partitionedReplicaIdCSPtr_,
                *stateProviderFactorySPtr_,
                GetAllocator());

            CheckpointManager::SPtr checkpointManagerSPtr = nullptr;
            NTSTATUS status = CheckpointManager::Create(
                *partitionedReplicaIdCSPtr_,
                *apiDispatcher,
                *workFolderPath,
                *replicaFolderPath,
                serializationMode,
                GetAllocator(),
                checkpointManagerSPtr);
            CODING_ERROR_ASSERT(NT_SUCCESS(status));
            KSharedArray<Metadata::CSPtr>::SPtr metadataArray = nullptr;

            // Setup
            MetadataManager::SPtr metadataManager = CreateMetadataManagerAndPopulateMetadatas(testMode, metadataCount, metadataArray);
            checkpointManagerSPtr->PrepareCheckpoint(*metadataManager, checkpointLSN);
            SyncAwait(checkpointManagerSPtr->PerformCheckpointAsync(*metadataManager, CancellationToken::None));
            SyncAwait(checkpointManagerSPtr->CompleteCheckpointAsync(*metadataManager, CancellationToken::None));

            CheckpointManager::SPtr recoverCheckpointManagerSPtr = nullptr;
            status = CheckpointManager::Create(
                *partitionedReplicaIdCSPtr_,
                *apiDispatcher,
                *workFolderPath,
                *replicaFolderPath,
                serializationMode,
                GetAllocator(),
                recoverCheckpointManagerSPtr);
            MetadataManager::SPtr recoverMetadataManagerSPtr = TestHelper::CreateMetadataManager(GetAllocator());
            auto result = SyncAwait(recoverCheckpointManagerSPtr->RecoverCheckpointAsync(*recoverMetadataManagerSPtr, CancellationToken::None));

            // Tests
            VerifyFileExistAndCleanUpFile(*replicaFolderPath, true, false, false, *recoverCheckpointManagerSPtr);

            // verify the state of the result of RecoverCheckpointAsync
            VERIFY_ARE_EQUAL(metadataArray->Count(), metadataCount);
            VERIFY_ARE_EQUAL(result->Count(), metadataCount);
            for (ULONG i = 0; i < metadataCount; i++)
            {
                ULONG expectedMetadataIndex = static_cast<ULONG>((*result)[i]->StateProviderId - 1);
                TestHelper::VerifyMetadata((*result)[i].RawPtr(), (*metadataArray)[expectedMetadataIndex].RawPtr());
            }

            // verify the active metadata of metadatamanager
            auto metadataEnumerator = recoverMetadataManagerSPtr->GetMetadataCollection();
            ULONG count = 0;
            while (metadataEnumerator->MoveNext())
            {
                Metadata::SPtr current = (metadataEnumerator->Current()).Value;
                ULONG expectedMetadataIndex = static_cast<ULONG>(current->StateProviderId - 1);
                TestHelper::VerifyMetadata(current.RawPtr(), (*metadataArray)[expectedMetadataIndex].RawPtr());
                count++;
            }

            VERIFY_ARE_EQUAL(count, metadataCount / 2);

            KSharedArray<Metadata::CSPtr>::SPtr softDeletedMetadataArray = nullptr;
            status = recoverMetadataManagerSPtr->GetDeletedConstMetadataArray(softDeletedMetadataArray);
            VERIFY_IS_TRUE(NT_SUCCESS(status));

            count = 0;
            for (Metadata::CSPtr current : *softDeletedMetadataArray)
            {
                ULONG expectedMetadataIndex = static_cast<ULONG>(current->StateProviderId - 1);
                TestHelper::VerifyMetadata(current.RawPtr(), (*metadataArray)[expectedMetadataIndex].RawPtr());
                count++;
            }

            VERIFY_ARE_EQUAL(count, metadataCount / 2);

            Common::Directory::Delete(static_cast<LPCWSTR>(*workFolderPath), true);
        }

        //
        // CheckpointFile Refactory regression test, to cover the case that in the RecoverCheckpointAsync
        // call, the file stream closed before exception thrown during the metadata enumeration. So there
        // is no file leak
        // Algorithm:
        //     1. Create the metadataManager
        //     2. Populate the metadatas and take checkpoint
        //     3. Inject CreateStateProvider failure
        //     4. Create a new metadataManager and call Recover
        //     5. Verify the exception thrown
        // Note: It will assert in CheckpointFileAsyncEnumerator destructor if CloseAsync is not called before exception throw.
        //
        void Test_RecoverCheckpointAsync_Throw_NoFileStreamLeak(
            __in ULONG metadataCount,
            __in LONG64 checkpointLSN,
            __in Enum testMode,
            __in SerializationMode::Enum serializationMode)
        {
            KString::CSPtr workFolderPath = TestHelper::CreateFileString(GetAllocator(), L"Work");
            KString::SPtr replicaFolderPath = KPath::Combine(*workFolderPath, L"PID_RID", GetAllocator());
            Common::Directory::CreateDirectoryW(static_cast<LPCWSTR>(*replicaFolderPath));
            bool isThrow = false;

            ApiDispatcher::SPtr apiDispatcher = ApiDispatcher::Create(
                *partitionedReplicaIdCSPtr_,
                *stateProviderFactorySPtr_,
                GetAllocator());

            CheckpointManager::SPtr checkpointManagerSPtr = nullptr;
            NTSTATUS status = CheckpointManager::Create(
                *partitionedReplicaIdCSPtr_,
                *apiDispatcher,
                *workFolderPath,
                *replicaFolderPath,
                serializationMode,
                GetAllocator(),
                checkpointManagerSPtr);
            CODING_ERROR_ASSERT(NT_SUCCESS(status));
            KSharedArray<Metadata::CSPtr>::SPtr metadataArray = nullptr;

            // Setup
            MetadataManager::SPtr metadataManager = CreateMetadataManagerAndPopulateMetadatas(testMode, metadataCount, metadataArray);
            checkpointManagerSPtr->PrepareCheckpoint(*metadataManager, checkpointLSN);
            SyncAwait(checkpointManagerSPtr->PerformCheckpointAsync(*metadataManager, CancellationToken::None));
            SyncAwait(checkpointManagerSPtr->CompleteCheckpointAsync(*metadataManager, CancellationToken::None));

            CheckpointManager::SPtr recoverCheckpointManagerSPtr = nullptr;
            status = CheckpointManager::Create(
                *partitionedReplicaIdCSPtr_,
                *apiDispatcher,
                *workFolderPath,
                *replicaFolderPath,
                serializationMode,
                GetAllocator(),
                recoverCheckpointManagerSPtr);
            CODING_ERROR_ASSERT(NT_SUCCESS(status));

            MetadataManager::SPtr recoverMetadataManagerSPtr = TestHelper::CreateMetadataManager(GetAllocator());

            // Inject create state provider failure, so the RecoverCheckpointAsync call will throw exception
            stateProviderFactorySPtr_->FaultAPI = FaultStateProviderType::Constructor;

            try
            {
                auto result = SyncAwait(recoverCheckpointManagerSPtr->RecoverCheckpointAsync(*recoverMetadataManagerSPtr, CancellationToken::None));
            }
            catch (Exception & exception)
            {
                // Verify the exception thrown and it's the one we expected
                isThrow = true;
                CODING_ERROR_ASSERT(exception.GetStatus() == SF_STATUS_COMMUNICATION_ERROR);
            }

            // Verify the exception catched.
            CODING_ERROR_ASSERT(isThrow);

            Common::Directory::Delete(static_cast<LPCWSTR>(*workFolderPath), true);
        }

        void Test_Clean_CurrentAndTmpFiles_SUCCESS(
            __in ULONG metadataCount,
            __in LONG64 checkpointLSN,
            __in SerializationMode::Enum serializationMode)
        {
            KString::CSPtr workFolderPath = TestHelper::CreateFileString(GetAllocator(), L"Work");
            KString::SPtr replicaFolderPath = KPath::Combine(*workFolderPath, L"PID_RID", GetAllocator());
            Common::Directory::CreateDirectoryW(static_cast<LPCWSTR>(*replicaFolderPath));

            ApiDispatcher::SPtr apiDispatcher = ApiDispatcher::Create(
                *partitionedReplicaIdCSPtr_,
                *stateProviderFactorySPtr_,
                GetAllocator());

            CheckpointManager::SPtr checkpointManagerSPtr = nullptr;
            NTSTATUS status = CheckpointManager::Create(
                *partitionedReplicaIdCSPtr_,
                *apiDispatcher,
                *workFolderPath,
                *replicaFolderPath,
                serializationMode,
                GetAllocator(),
                checkpointManagerSPtr);
            CODING_ERROR_ASSERT(NT_SUCCESS(status));
            KSharedArray<Metadata::CSPtr>::SPtr metadataArray = nullptr;

            // Setup
            MetadataManager::SPtr metadataManager = CreateMetadataManagerAndPopulateMetadatas(Enum::Both, metadataCount, metadataArray);
            checkpointManagerSPtr->PrepareCheckpoint(*metadataManager, checkpointLSN);
            SyncAwait(checkpointManagerSPtr->PerformCheckpointAsync(*metadataManager, CancellationToken::None));
            SyncAwait(checkpointManagerSPtr->CompleteCheckpointAsync(*metadataManager, CancellationToken::None));
            SyncAwait(checkpointManagerSPtr->PerformCheckpointAsync(*metadataManager, CancellationToken::None));

            // Tests
            VerifyFileExistAndCleanUpFile(*replicaFolderPath, true, true, false, *checkpointManagerSPtr);

            Common::Directory::Delete(static_cast<LPCWSTR>(*workFolderPath), true);
        }

        void Test_Recover_ShutdownBeforeOrAfterComplete_SUCCESS(
            __in ULONG metadataCount,
            __in LONG64 checkpointLSN,
            __in Enum testMode,
            __in bool shutdownBeforeComplete,
            __in SerializationMode::Enum serializationMode)
        {
            KString::CSPtr workFolderPath = TestHelper::CreateFileString(GetAllocator(), L"Work");
            KString::SPtr replicaFolderPath = KPath::Combine(*workFolderPath, L"PID_RID", GetAllocator());
            Common::Directory::CreateDirectoryW(static_cast<LPCWSTR>(*replicaFolderPath));

            ApiDispatcher::SPtr apiDispatcher = ApiDispatcher::Create(
                *partitionedReplicaIdCSPtr_,
                *stateProviderFactorySPtr_,
                GetAllocator());

            CheckpointManager::SPtr checkpointManagerSPtr = nullptr;
            NTSTATUS status = CheckpointManager::Create(
                *partitionedReplicaIdCSPtr_,
                *apiDispatcher,
                *workFolderPath,
                *replicaFolderPath,
                serializationMode,
                GetAllocator(),
                checkpointManagerSPtr);
            CODING_ERROR_ASSERT(NT_SUCCESS(status));
            KSharedArray<Metadata::CSPtr>::SPtr metadataArray = nullptr;

            // Setup
            MetadataManager::SPtr metadataManager = CreateMetadataManagerAndPopulateMetadatas(testMode, metadataCount, metadataArray);
            checkpointManagerSPtr->PrepareCheckpoint(*metadataManager, checkpointLSN);
            SyncAwait(checkpointManagerSPtr->PerformCheckpointAsync(*metadataManager, CancellationToken::None));

            if(!shutdownBeforeComplete)
            {
                SyncAwait(checkpointManagerSPtr->CompleteCheckpointAsync(*metadataManager, CancellationToken::None));
            }

            // Mock the situation shutdown here, and recreate matadatamanager to call CompleteCheckpoint and recover from checkpoint file
            MetadataManager::SPtr newMetadataManager = TestHelper::CreateMetadataManager(GetAllocator());
            SyncAwait(checkpointManagerSPtr->CompleteCheckpointAsync(*newMetadataManager, CancellationToken::None));

            CheckpointManager::SPtr recoverCheckpointManagerSPtr = nullptr;
            status = CheckpointManager::Create(
                *partitionedReplicaIdCSPtr_,
                *apiDispatcher,
                *workFolderPath,
                *replicaFolderPath,
                serializationMode,
                GetAllocator(),
                recoverCheckpointManagerSPtr);

            MetadataManager::SPtr recoverMetadataManagerSPtr = TestHelper::CreateMetadataManager(GetAllocator());
            auto result = SyncAwait(recoverCheckpointManagerSPtr->RecoverCheckpointAsync(*recoverMetadataManagerSPtr, CancellationToken::None));

            // Tests
            VerifyFileExistAndCleanUpFile(*replicaFolderPath, true, false, false, *recoverCheckpointManagerSPtr);

            // Verify the state of the result of RecoverCheckpointAsync
            VERIFY_ARE_EQUAL(metadataArray->Count(), metadataCount);
            VERIFY_ARE_EQUAL(result->Count(), metadataCount);
            for (ULONG i = 0; i < metadataCount; i++)
            {
                ULONG expectedMetadataIndex = static_cast<ULONG>((*result)[i]->StateProviderId - 1);
                TestHelper::VerifyMetadata((*result)[i].RawPtr(), (*metadataArray)[expectedMetadataIndex].RawPtr());
            }

            // verify the active metadata of metadatamanager
            auto metadataEnumerator = recoverMetadataManagerSPtr->GetMetadataCollection();
            ULONG count = 0;
            while (metadataEnumerator->MoveNext())
            {
                Metadata::SPtr current = (metadataEnumerator->Current()).Value;
                ULONG expectedMetadataIndex = static_cast<ULONG>(current->StateProviderId - 1);
                TestHelper::VerifyMetadata(current.RawPtr(), (*metadataArray)[expectedMetadataIndex].RawPtr());
                count++;
            }

            VERIFY_ARE_EQUAL(count, metadataCount / 2);

            KSharedArray<Metadata::CSPtr>::SPtr softDeletedMetadataArray = nullptr;
            status = recoverMetadataManagerSPtr->GetDeletedConstMetadataArray(softDeletedMetadataArray);
            VERIFY_IS_TRUE(NT_SUCCESS(status));

            count = 0;
            for (Metadata::CSPtr current : *softDeletedMetadataArray)
            {
                ULONG expectedMetadataIndex = static_cast<ULONG>(current->StateProviderId - 1);
                TestHelper::VerifyMetadata(current.RawPtr(), (*metadataArray)[expectedMetadataIndex].RawPtr());
                count++;
            }

            VERIFY_ARE_EQUAL(count, metadataCount / 2);

            Common::Directory::Delete(static_cast<LPCWSTR>(*workFolderPath), true);
        }

        void VerifyFileExistAndCleanUpFile(
            __in KStringView const & replicaPath,
            __in bool expectedCPTFileExist,
            __in bool expectedTMPFileExist,
            __in bool expectedBKPFileExist,
            __in CheckpointManager & checkpointManager)
        {
            KString::SPtr currentCheckpointFile = KPath::Combine(replicaPath, CurrentCheckpointPrefix, GetAllocator());
            KString::SPtr tempCheckpointFile = KPath::Combine(replicaPath, TempCheckpointPrefix, GetAllocator());
            KString::SPtr backupCheckpointFile = KPath::Combine(replicaPath, BackupCheckpointPrefix, GetAllocator());

            VERIFY_ARE_EQUAL(Common::File::Exists(static_cast<LPCWSTR>(*currentCheckpointFile)), expectedCPTFileExist);
            VERIFY_ARE_EQUAL(Common::File::Exists(static_cast<LPCWSTR>(*tempCheckpointFile)), expectedTMPFileExist);
            VERIFY_ARE_EQUAL(Common::File::Exists(static_cast<LPCWSTR>(*backupCheckpointFile)), expectedBKPFileExist);

            checkpointManager.Clean();
            VERIFY_IS_FALSE(Common::File::Exists(static_cast<LPCWSTR>(*currentCheckpointFile)));
            VERIFY_IS_FALSE(Common::File::Exists(static_cast<LPCWSTR>(*tempCheckpointFile)));

            if(Common::File::Exists(static_cast<LPCWSTR>(*backupCheckpointFile)))
            {
                KString::CSPtr filePath = TestHelper::CreateFileString(GetAllocator(), BackupCheckpointPrefix);
                Common::File::Delete(static_cast<LPCWSTR>(*filePath), true);
            }
        }

        KStringView const CurrentCheckpointPrefix = L"StateManager.cpt";
        KStringView const TempCheckpointPrefix = L"StateManager.tmp";
        KStringView const BackupCheckpointPrefix = L"StateManager.bkp";
    };

    BOOST_FIXTURE_TEST_SUITE(CheckpointManagerTestSuite, CheckpointManagerTest)

    // Create checkpointManagerSPtr test
    BOOST_AUTO_TEST_CASE(Create_SUCCESS)
    {
        KString::CSPtr workFolderPath = TestHelper::CreateFileString(GetAllocator(), L"Work");
        KString::SPtr replicaFolderPath = KPath::Combine(*workFolderPath, L"PID_RID", GetAllocator());
        Common::Directory::CreateDirectoryW(static_cast<LPCWSTR>(*replicaFolderPath));

        ApiDispatcher::SPtr apiDispatcher = ApiDispatcher::Create(
            *partitionedReplicaIdCSPtr_,
            *stateProviderFactorySPtr_,
            GetAllocator());

        CheckpointManager::SPtr checkpointManagerSPtr = nullptr;
        NTSTATUS status = CheckpointManager::Create(
            *partitionedReplicaIdCSPtr_,
            *apiDispatcher,
            *workFolderPath,
            *replicaFolderPath,
            SerializationMode::Native,
            GetAllocator(),
            checkpointManagerSPtr);
        CODING_ERROR_ASSERT(NT_SUCCESS(status));

        // Test
        VERIFY_ARE_EQUAL(checkpointManagerSPtr->PrepareCheckpointLSN, FABRIC_INVALID_SEQUENCE_NUMBER);

        Common::Directory::Delete(static_cast<LPCWSTR>(*workFolderPath), true);
    }

    // PrepareCheckpoint function test with no Metadata
    // both GetPreparedActiveList and GetPreparedDeletedList should return 0
    BOOST_AUTO_TEST_CASE(PrepareCheckpoint_EmptyMetadata_SUCCESS)
    {
        ULONG const metadataCount = 0;
        LONG64 const checkpointLSN = 1;

        Test_PrepareCheckpoint_MultipleMetadata_SUCCESS(metadataCount, Enum::Both, checkpointLSN, SerializationMode::Native);
    }

    BOOST_AUTO_TEST_CASE(PrepareCheckpoint_EmptyMetadata_Managed_SUCCESS)
    {
        ULONG const metadataCount = 0;
        LONG64 const checkpointLSN = 1;

        Test_PrepareCheckpoint_MultipleMetadata_SUCCESS(metadataCount, Enum::Both, checkpointLSN, SerializationMode::Managed);
    }

    // PrepareCheckpoint function test, with all active metadatas populated,
    // After calling PrepareCheckpoint, GetPreparedActiveList should return all active metadatas
    BOOST_AUTO_TEST_CASE(PrepareCheckpoint_OneActiveMetadatas_InGetPreparedActiveList)
    {
        ULONG const metadataCount = 1;
        LONG64 const checkpointLSN = 1;

        Test_PrepareCheckpoint_MultipleMetadata_SUCCESS(metadataCount, Enum::AllActive, checkpointLSN, SerializationMode::Native);
    }

    BOOST_AUTO_TEST_CASE(PrepareCheckpoint_MultipleActiveMetadatas_AllInGetPreparedActiveList)
    {
        ULONG const metadataCount = 1024;
        LONG64 const checkpointLSN = 1;

        Test_PrepareCheckpoint_MultipleMetadata_SUCCESS(metadataCount, Enum::AllActive, checkpointLSN, SerializationMode::Native);
    }

    // PrepareCheckpoint function test, with all SoftDeleted metadatas populated,
    // After calling PrepareCheckpoint, GetPreparedActiveList should return 0 active metadatas, because all metadata are SoftDeleted
    BOOST_AUTO_TEST_CASE(PrepareCheckpoint_OneSoftDeletedMetadatas_InGetPreparedDeletedList)
    {
        ULONG const metadataCount = 1;
        LONG64 const checkpointLSN = 1;

        Test_PrepareCheckpoint_MultipleMetadata_SUCCESS(metadataCount, Enum::AllDeleted, checkpointLSN, SerializationMode::Native);
    }

    BOOST_AUTO_TEST_CASE(PrepareCheckpoint_MultipleSoftDeletedMetadatas_AllInGetPreparedDeletedList)
    {
        ULONG const metadataCount = 1024;
        LONG64 const checkpointLSN = 1;

        Test_PrepareCheckpoint_MultipleMetadata_SUCCESS(metadataCount, Enum::AllDeleted, checkpointLSN, SerializationMode::Native);
    }

    BOOST_AUTO_TEST_CASE(PrepareCheckpoint_MultipleSoftDeletedMetadatas_Managed_AllInGetPreparedDeletedList)
    {
        ULONG const metadataCount = 1024;
        LONG64 const checkpointLSN = 1;

        Test_PrepareCheckpoint_MultipleMetadata_SUCCESS(metadataCount, Enum::AllDeleted, checkpointLSN, SerializationMode::Managed);
    }

    // PrepareCheckpoint function test, with both active metadatas and SoftDeleted metadatas populated,
    // when we populate Metadatas, we insert half active metadatas and half SoftDeleted metadatas
    // After calling PrepareCheckpoint, GetPreparedActiveList should get all active metadatas, and GetPreparedDeletedList return all SoftDeleted metadatas
    BOOST_AUTO_TEST_CASE(PrepareCheckpoint_ActiveAndSoftDeleted_SUCCESS)
    {
        ULONG const metadataCount = 1024;
        LONG64 const checkpointLSN = 1;

        Test_PrepareCheckpoint_MultipleMetadata_SUCCESS(metadataCount, Enum::Both, checkpointLSN, SerializationMode::Native);
    }

    // PerformCheckpointAsync function test, with one metadata
    // after calling PerformCheckpointAsync, open the checkpoint file and verify the metadata is correct
    BOOST_AUTO_TEST_CASE(PerformCheckpointAsync_OneMetadata_SUCCESS)
    {
        LONG64 const checkpointLSN = 1;

        Test_PerformCheckpointAsync_OneMetadata_SUCCESS(checkpointLSN, SerializationMode::Native);
    }

    BOOST_AUTO_TEST_CASE(PerformCheckpointAsync_OneMetadata_Managed_SUCCESS)
    {
        LONG64 const checkpointLSN = 1;

        Test_PerformCheckpointAsync_OneMetadata_SUCCESS(checkpointLSN, SerializationMode::Managed);
    }

    // CompleteCheckpointAsync with only temp checkpoint file exists, which will change the temp file to current checkpoint file
    BOOST_AUTO_TEST_CASE(CompleteCheckpointAsync_TmpFileExist_SUCCESS)
    {
        KString::CSPtr workFolderPath = TestHelper::CreateFileString(GetAllocator(), L"Work");
        KString::SPtr replicaFolderPath = KPath::Combine(*workFolderPath, L"PID_RID", GetAllocator());
        Common::Directory::CreateDirectoryW(static_cast<LPCWSTR>(*replicaFolderPath));
        LONG64 const checkpointLSN = 1;

        ApiDispatcher::SPtr apiDispatcher = ApiDispatcher::Create(
            *partitionedReplicaIdCSPtr_,
            *stateProviderFactorySPtr_,
            GetAllocator());

        CheckpointManager::SPtr checkpointManagerSPtr = nullptr;
        NTSTATUS status = CheckpointManager::Create(
            *partitionedReplicaIdCSPtr_,
            *apiDispatcher,
            *workFolderPath,
            *replicaFolderPath,
            SerializationMode::Native,
            GetAllocator(),
            checkpointManagerSPtr);
        CODING_ERROR_ASSERT(NT_SUCCESS(status));
        KSharedArray<Metadata::CSPtr>::SPtr metadataArray = nullptr;

        // Setup
        MetadataManager::SPtr metadataManagerSPtr = TestHelper::CreateMetadataManager(GetAllocator());
        KUri::CSPtr expectedName;
        status = KUri::Create(KUriView(L"fabric:/sps/sp"), GetAllocator(), expectedName);
        CODING_ERROR_ASSERT(NT_SUCCESS(status));

        auto metadata = TestHelper::CreateMetadata(*expectedName, false, GetAllocator());
        bool isAdded = metadataManagerSPtr->TryAdd(*expectedName, *metadata);
        VERIFY_IS_TRUE(isAdded);
        checkpointManagerSPtr->PrepareCheckpoint(*metadataManagerSPtr, checkpointLSN);
        SyncAwait(checkpointManagerSPtr->PerformCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));
        SyncAwait(checkpointManagerSPtr->CompleteCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));

        // Test
        KString::SPtr currentCheckpointFile = KPath::Combine(*replicaFolderPath, CurrentCheckpointPrefix, GetAllocator());
        auto tmpFileName = KWString(GetAllocator(), *currentCheckpointFile);

        CheckpointFile::SPtr checkpointFileReopenSPtr = nullptr;
        status = CheckpointFile::Create(
            *partitionedReplicaIdCSPtr_,
            tmpFileName,
            GetAllocator(),
            checkpointFileReopenSPtr);
        CODING_ERROR_ASSERT(NT_SUCCESS(status));
        SyncAwait(checkpointFileReopenSPtr->ReadAsync(CancellationToken::None));

        auto enumerator = checkpointFileReopenSPtr->GetAsyncEnumerator();
        ULONG32 i = 0;

        while (SyncAwait(enumerator->MoveNextAsync(CancellationToken::None)))
        {
            auto sermeta = enumerator->GetCurrent();
            CODING_ERROR_ASSERT(sermeta->StateProviderId == metadata->StateProviderId);
            CODING_ERROR_ASSERT(sermeta->ParentStateProviderId == metadata->ParentId);
            CODING_ERROR_ASSERT(sermeta->CreateLSN == metadata->CreateLSN);
            CODING_ERROR_ASSERT(sermeta->DeleteLSN == metadata->DeleteLSN);

            ++i;
        }

        CODING_ERROR_ASSERT(i == 1);
        SyncAwait(enumerator->CloseAsync());

        VerifyFileExistAndCleanUpFile(*replicaFolderPath, true, false, false, *checkpointManagerSPtr);

        Common::Directory::Delete(static_cast<LPCWSTR>(*workFolderPath), true);
    }

    // CompleteCheckpointAsync with only backup file exists, in this case, current checkpoint file must exists
    BOOST_AUTO_TEST_CASE(CompleteCheckpointAsync_BkpFileExist_SUCCESS)
    {
        KString::CSPtr workFolderPath = TestHelper::CreateFileString(GetAllocator(), L"Work");
        KString::SPtr replicaFolderPath = KPath::Combine(*workFolderPath, L"PID_RID", GetAllocator());
        Common::Directory::CreateDirectoryW(static_cast<LPCWSTR>(*replicaFolderPath));
        LONG64 const checkpointLSN = 1;

        ApiDispatcher::SPtr apiDispatcher = ApiDispatcher::Create(
            *partitionedReplicaIdCSPtr_,
            *stateProviderFactorySPtr_,
            GetAllocator());

        CheckpointManager::SPtr checkpointManagerSPtr = nullptr;
        NTSTATUS status = CheckpointManager::Create(
            *partitionedReplicaIdCSPtr_,
            *apiDispatcher,
            *workFolderPath,
            *replicaFolderPath,
            SerializationMode::Native,
            GetAllocator(),
            checkpointManagerSPtr);
        CODING_ERROR_ASSERT(NT_SUCCESS(status));
        KSharedArray<Metadata::CSPtr>::SPtr metadataArray = nullptr;

        // Setup
        MetadataManager::SPtr metadataManagerSPtr = TestHelper::CreateMetadataManager(GetAllocator());
        KUri::CSPtr expectedName;
        status = KUri::Create(KUriView(L"fabric:/sps/sp"), GetAllocator(), expectedName);
        CODING_ERROR_ASSERT(NT_SUCCESS(status));

        auto metadata = TestHelper::CreateMetadata(*expectedName, false, GetAllocator());
        bool isAdded = metadataManagerSPtr->TryAdd(*expectedName, *metadata);
        VERIFY_IS_TRUE(isAdded);
        checkpointManagerSPtr->PrepareCheckpoint(*metadataManagerSPtr, checkpointLSN);
        SyncAwait(checkpointManagerSPtr->PerformCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));
        SyncAwait(checkpointManagerSPtr->CompleteCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));
        SyncAwait(checkpointManagerSPtr->PerformCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));

        // Test
        KString::SPtr tempCheckpointFileString = KPath::Combine(*replicaFolderPath, TempCheckpointPrefix, GetAllocator());
        KString::SPtr backupCheckpointFileString = KPath::Combine(*replicaFolderPath, BackupCheckpointPrefix, GetAllocator());

        auto errorCode = Common::File::Move(
            static_cast<LPCWSTR>(*tempCheckpointFileString),
            static_cast<LPCWSTR>(*backupCheckpointFileString));
        VERIFY_IS_TRUE(errorCode.IsSuccess());

        SyncAwait(checkpointManagerSPtr->CompleteCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));

        VerifyFileExistAndCleanUpFile(*replicaFolderPath, true, false, false, *checkpointManagerSPtr);

        Common::Directory::Delete(static_cast<LPCWSTR>(*workFolderPath), true);
    }

    // CompleteCheckpointAsync with only current checkpoint file exists, which means the complete already been called
    BOOST_AUTO_TEST_CASE(CompleteCheckpointAsync_CptFileExist_SUCCESS)
    {
        KString::CSPtr workFolderPath = TestHelper::CreateFileString(GetAllocator(), L"Work");
        KString::SPtr replicaFolderPath = KPath::Combine(*workFolderPath, L"PID_RID", GetAllocator());
        Common::Directory::CreateDirectoryW(static_cast<LPCWSTR>(*replicaFolderPath));
        LONG64 const checkpointLSN = 1;

        ApiDispatcher::SPtr apiDispatcher = ApiDispatcher::Create(
            *partitionedReplicaIdCSPtr_,
            *stateProviderFactorySPtr_,
            GetAllocator());

        CheckpointManager::SPtr checkpointManagerSPtr = nullptr;
        NTSTATUS status = CheckpointManager::Create(
            *partitionedReplicaIdCSPtr_,
            *apiDispatcher,
            *workFolderPath,
            *replicaFolderPath,
            SerializationMode::Native,
            GetAllocator(),
            checkpointManagerSPtr);
        CODING_ERROR_ASSERT(NT_SUCCESS(status));
        KSharedArray<Metadata::CSPtr>::SPtr metadataArray = nullptr;

        // Setup
        MetadataManager::SPtr metadataManagerSPtr = TestHelper::CreateMetadataManager(GetAllocator());
        KUri::CSPtr expectedName;
        status = KUri::Create(KUriView(L"fabric:/sps/sp"), GetAllocator(), expectedName);
        CODING_ERROR_ASSERT(NT_SUCCESS(status));

        auto metadata = TestHelper::CreateMetadata(*expectedName, false, GetAllocator());
        bool isAdded = metadataManagerSPtr->TryAdd(*expectedName, *metadata);
        VERIFY_IS_TRUE(isAdded);
        checkpointManagerSPtr->PrepareCheckpoint(*metadataManagerSPtr, checkpointLSN);
        SyncAwait(checkpointManagerSPtr->PerformCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));
        SyncAwait(checkpointManagerSPtr->CompleteCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));
        SyncAwait(checkpointManagerSPtr->CompleteCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));

        // Test
        VerifyFileExistAndCleanUpFile(*replicaFolderPath, true, false, false, *checkpointManagerSPtr);

        Common::Directory::Delete(static_cast<LPCWSTR>(*workFolderPath), true);
    }

    // Mock the situation that some replicas called CompleteCheckpointAsync but some not.
    // In this case, the CompleteCheckpointAsync will be called twice
    BOOST_AUTO_TEST_CASE(CompleteCheckpointAsync_DoubleCall_SUCCESS)
    {
        KString::CSPtr workFolderPath = TestHelper::CreateFileString(GetAllocator(), L"Work");
        KString::SPtr replicaFolderPath = KPath::Combine(*workFolderPath, L"PID_RID", GetAllocator());
        Common::Directory::CreateDirectoryW(static_cast<LPCWSTR>(*replicaFolderPath));
        LONG64 const checkpointLSN = 1;

        ApiDispatcher::SPtr apiDispatcher = ApiDispatcher::Create(
            *partitionedReplicaIdCSPtr_,
            *stateProviderFactorySPtr_,
            GetAllocator());

        CheckpointManager::SPtr checkpointManagerSPtr = nullptr;
        NTSTATUS status = CheckpointManager::Create(
            *partitionedReplicaIdCSPtr_,
            *apiDispatcher,
            *workFolderPath,
            *replicaFolderPath,
            SerializationMode::Native,
            GetAllocator(),
            checkpointManagerSPtr);
        CODING_ERROR_ASSERT(NT_SUCCESS(status));
        KSharedArray<Metadata::CSPtr>::SPtr metadataArray = nullptr;

        // Setup
        MetadataManager::SPtr metadataManagerSPtr = TestHelper::CreateMetadataManager(GetAllocator());
        KUri::CSPtr expectedName;
        status = KUri::Create(KUriView(L"fabric:/sps/sp"), GetAllocator(), expectedName);
        CODING_ERROR_ASSERT(NT_SUCCESS(status));

        auto metadata = TestHelper::CreateMetadata(*expectedName, false, GetAllocator());
        bool isAdded = metadataManagerSPtr->TryAdd(*expectedName, *metadata);
        VERIFY_IS_TRUE(isAdded);
        checkpointManagerSPtr->PrepareCheckpoint(*metadataManagerSPtr, checkpointLSN);
        SyncAwait(checkpointManagerSPtr->PerformCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));
        SyncAwait(checkpointManagerSPtr->CompleteCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));
        SyncAwait(checkpointManagerSPtr->CompleteCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));

        // Test
        KString::SPtr currentCheckpointFile = KPath::Combine(*replicaFolderPath, CurrentCheckpointPrefix, GetAllocator());
        KWString fileName(GetAllocator(), *currentCheckpointFile);

        CheckpointFile::SPtr checkpointFileReopenSPtr = nullptr;
        status = CheckpointFile::Create(
            *partitionedReplicaIdCSPtr_,
            fileName,
            GetAllocator(),
            checkpointFileReopenSPtr);
        CODING_ERROR_ASSERT(NT_SUCCESS(status));
        SyncAwait(checkpointFileReopenSPtr->ReadAsync(CancellationToken::None));

        auto enumerator = checkpointFileReopenSPtr->GetAsyncEnumerator();
        ULONG32 i = 0;

        while (SyncAwait(enumerator->MoveNextAsync(CancellationToken::None)))
        {
            auto sermeta = enumerator->GetCurrent();
            CODING_ERROR_ASSERT(sermeta->StateProviderId == metadata->StateProviderId);
            CODING_ERROR_ASSERT(sermeta->ParentStateProviderId == metadata->ParentId);
            CODING_ERROR_ASSERT(sermeta->CreateLSN == metadata->CreateLSN);
            CODING_ERROR_ASSERT(sermeta->DeleteLSN == metadata->DeleteLSN);

            ++i;
        }

        CODING_ERROR_ASSERT(i == 1);
        SyncAwait(enumerator->CloseAsync());

        VerifyFileExistAndCleanUpFile(*replicaFolderPath, true, false, false, *checkpointManagerSPtr);

        Common::Directory::Delete(static_cast<LPCWSTR>(*workFolderPath), true);
    }

    // RecoverCheckpointAsync test should recover from checkpoint file which has both active and deleted Metadata
    BOOST_AUTO_TEST_CASE(RecoverCheckpointAsync_WithActiveAndDeletedMetadata_SUCCESS)
    {
        LONG64 const checkpointLSN = 1;
        ULONG const metadataCount = 10;

        Test_RecoverCheckpointAsync_MultipleMetadata_SUCCESS(metadataCount, checkpointLSN, Enum::Both, SerializationMode::Native);
    }

    // Mock the situation that shutdown happened after PerformCheckpointAsync, so the temp checkpoint file is saved,
    // In this case, we recreate the matadatamanager to call CompleteCheckpointAsync and RecoverCheckpointAsync should recover the origin states
    BOOST_AUTO_TEST_CASE(Recover_ShutdownBeforeComplete_SUCCESS)
    {
        LONG64 const checkpointLSN = 1;
        ULONG const metadataCount = 10;

        Test_Recover_ShutdownBeforeOrAfterComplete_SUCCESS(metadataCount, checkpointLSN, Enum::Both, true, SerializationMode::Native);
    }

    // Mock the situation that shutdown happened after CompleteCheckpointAsync, so the current checkpoint file is saved,
    // In this case, we recreate the matadatamanager to call CompleteCheckpointAsync and RecoverCheckpointAsync should recover the origin states
    BOOST_AUTO_TEST_CASE(Recover_ShutdownAfterComplete_SUCCESS)
    {
        LONG64 const checkpointLSN = 1;
        ULONG const metadataCount = 10;

        Test_Recover_ShutdownBeforeOrAfterComplete_SUCCESS(metadataCount, checkpointLSN, Enum::Both, false, SerializationMode::Native);
    }

    // Call recover with no checkpoint file exists, in this case, it will call PerformCheckpointAsync and CompleteCheckpointAsync
    // the checkpoint file will be generated but RecoverCheckpointAsync will return nullptr.
    BOOST_AUTO_TEST_CASE(RecoverCheckpointAsync_NoCheckpointFileExist_SUCCESS)
    {
        KString::CSPtr workFolderPath = TestHelper::CreateFileString(GetAllocator(), L"Work");
        KString::SPtr replicaFolderPath = KPath::Combine(*workFolderPath, L"PID_RID", GetAllocator());
        Common::Directory::CreateDirectoryW(static_cast<LPCWSTR>(*replicaFolderPath));

        ApiDispatcher::SPtr apiDispatcher = ApiDispatcher::Create(
            *partitionedReplicaIdCSPtr_,
            *stateProviderFactorySPtr_,
            GetAllocator());

        CheckpointManager::SPtr checkpointManagerSPtr = nullptr;
        NTSTATUS status = CheckpointManager::Create(
            *partitionedReplicaIdCSPtr_,
            *apiDispatcher,
            *workFolderPath,
            *replicaFolderPath,
            SerializationMode::Native,
            GetAllocator(),
            checkpointManagerSPtr);
        CODING_ERROR_ASSERT(NT_SUCCESS(status));

        MetadataManager::SPtr recoverMetadataManagerSPtr = TestHelper::CreateMetadataManager(GetAllocator());
        auto result = SyncAwait(checkpointManagerSPtr->RecoverCheckpointAsync(*recoverMetadataManagerSPtr, CancellationToken::None));

        // Tests
        CODING_ERROR_ASSERT(result == nullptr);
        VerifyFileExistAndCleanUpFile(*replicaFolderPath, true, false, false, *checkpointManagerSPtr);
        Common::Directory::Delete(static_cast<LPCWSTR>(*workFolderPath), true);
    }

    // The clean function will remove current checkpoint file and temp checkpoint file
    BOOST_AUTO_TEST_CASE(Clean_CurrentAndTempFile_SUCCESS)
    {
        LONG64 const checkpointLSN = 1;
        ULONG const metadataCount = 10;

        Test_Clean_CurrentAndTmpFiles_SUCCESS(metadataCount, checkpointLSN, SerializationMode::Native);
    }

    // RDBug 9809142:RecoverCheckpointAsync_Throw_NoFileStreamLeak test failed on linux retail build
#if !defined(PLATFORM_UNIX)
    //
    // Scenario:        CheckpointFile Refactory regression test, to cover the case that in the RecoverCheckpointAsync
    //                  call, the file stream closed before exception thrown during the metadata enumeration.
    // Note:            It will assert in CheckpointFileAsyncEnumerator destructor if CloseAsync is not called before
    //                  exception throw.
    // Expected Result: Exception should throw and no file leak.
    //
    BOOST_AUTO_TEST_CASE(RecoverCheckpointAsync_Throw_NoFileStreamLeak)
    {
        LONG64 const checkpointLSN = 1;
        ULONG const metadataCount = 10;

        Test_RecoverCheckpointAsync_Throw_NoFileStreamLeak(metadataCount, checkpointLSN, Enum::Both, SerializationMode::Native);
    }
#endif

    // Goal: Test used to verify the PrepareCheckpointLSN is correctly set when we do the checkpoint,
    // and PrepareCheckpointLSN is correctly read when we recover from the checkpoint file.
    BOOST_AUTO_TEST_CASE(PrepareCheckpointLSN_SetAndGet)
    {
        KString::CSPtr workFolderPath = TestHelper::CreateFileString(GetAllocator(), L"Work");
        KString::SPtr replicaFolderPath = KPath::Combine(*workFolderPath, L"PID_RID", GetAllocator());
        Common::Directory::CreateDirectoryW(static_cast<LPCWSTR>(*replicaFolderPath));
        LONG64 const checkpointLSN = 16;

        // Setup
        ApiDispatcher::SPtr apiDispatcher = ApiDispatcher::Create(
            *partitionedReplicaIdCSPtr_,
            *stateProviderFactorySPtr_,
            GetAllocator());

        CheckpointManager::SPtr checkpointManagerSPtr = nullptr;
        NTSTATUS status = CheckpointManager::Create(
            *partitionedReplicaIdCSPtr_,
            *apiDispatcher,
            *workFolderPath,
            *replicaFolderPath,
            SerializationMode::Native,
            GetAllocator(),
            checkpointManagerSPtr);
        VERIFY_IS_TRUE(NT_SUCCESS(status));
        KSharedArray<Metadata::CSPtr>::SPtr metadataArray = nullptr;

        MetadataManager::SPtr metadataManagerSPtr = TestHelper::CreateMetadataManager(GetAllocator());
        KUri::CSPtr expectedName;
        status = KUri::Create(KUriView(L"fabric:/sps/sp"), GetAllocator(), expectedName);
        VERIFY_IS_TRUE(NT_SUCCESS(status));

        checkpointManagerSPtr->PrepareCheckpoint(*metadataManagerSPtr, checkpointLSN);
        SyncAwait(checkpointManagerSPtr->PerformCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));
        SyncAwait(checkpointManagerSPtr->CompleteCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));

        // Test
        // After the PrepareCheckpoint function call, the PrepareCheckpointLSN in checkpointManager should be set to the correct number.
        VERIFY_ARE_EQUAL(checkpointManagerSPtr->PrepareCheckpointLSN, checkpointLSN);

        KString::SPtr currentCheckpointFile = KPath::Combine(*replicaFolderPath, CurrentCheckpointPrefix, GetAllocator());
        KWString fileName(GetAllocator(), *currentCheckpointFile);

        // Open the checkpoint file, the file should have the expected PrepareCheckpointLSN
        CheckpointFile::SPtr checkpointFileReopenSPtr = nullptr;
        status = CheckpointFile::Create(
            *partitionedReplicaIdCSPtr_,
            fileName,
            GetAllocator(),
            checkpointFileReopenSPtr);
        VERIFY_IS_TRUE(NT_SUCCESS(status));
        SyncAwait(checkpointFileReopenSPtr->ReadAsync(CancellationToken::None));

        // After reading from the checkpoint file, the PrepareCheckpointLSN should be as expected
        VERIFY_ARE_EQUAL(checkpointFileReopenSPtr->PropertiesSPtr->PrepareCheckpointLSN, checkpointLSN);

        // Create a new checkpoint manager and recover the checkpoint, the PrepareCheckpointLSN should as expected.
        CheckpointManager::SPtr newCheckpointManagerSPtr = nullptr;
        status = CheckpointManager::Create(
            *partitionedReplicaIdCSPtr_,
            *apiDispatcher,
            *workFolderPath,
            *replicaFolderPath,
            SerializationMode::Native,
            GetAllocator(),
            newCheckpointManagerSPtr);
        VERIFY_IS_TRUE(NT_SUCCESS(status));

        VERIFY_ARE_EQUAL(newCheckpointManagerSPtr->PrepareCheckpointLSN, FABRIC_INVALID_SEQUENCE_NUMBER);
        SyncAwait(newCheckpointManagerSPtr->RecoverCheckpointAsync(*metadataManagerSPtr, CancellationToken::None));
        VERIFY_ARE_EQUAL(newCheckpointManagerSPtr->PrepareCheckpointLSN, checkpointLSN);

        VerifyFileExistAndCleanUpFile(*replicaFolderPath, true, false, false, *checkpointManagerSPtr);

        Common::Directory::Delete(static_cast<LPCWSTR>(*workFolderPath), true);
    }

    BOOST_AUTO_TEST_SUITE_END()
}

max_stars_repo_name: AnthonyM/service-fabric

max_issues_repo_name: AnthonyM/service-fabric

max_forks_repo_name: AnthonyM/service-fabric


text:
/** A test program for a continuous busy loop timer

For discussion see http://stackoverflow.com/q/40320926/16582

*/

#include <windows.h>
#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>

#include <boost/asio.hpp>
#include <boost/asio/high_resolution_timer.hpp>

#include "cRunCount.h"
#include "cTimerBusyLoop.h"

using namespace std;

/** Timer for sub-millisecond times, using busy loop running in own thread */
raven::set::cTimerBusyLoopContinuous Timer;

/** Frequency counter from https://github.com/JamesBremner/raven-set
 Construct to report after 2000 calls
*/
raven::set::cRunCount        myRunCounter( 2000 );

/** Length of timed wait */
int WaitMicroSecs;

/** Target frequency */
int TargetHz;

/** The event loop */
boost::asio::io_service io_service;

/** Timer used when wait is more than 1 millisecond */
boost::asio::high_resolution_timer  * myPlaybackTimer;

/** Function forward declerations */
void StartWait();
void handle_expire(const boost::system::error_code& );

void CheckBusyLoopDone()
{
    // read completion flag
    if( ! Timer.IsDone() )
    {
        // still running
        // post the next check
        // in a real application, this would allow other processing
        // to execute in this thread
        io_service.post( CheckBusyLoopDone );
    }
    else
    {
        // busy loop timer completed
        // execute completion handler
        handle_expire( boost::system::error_code() );
    }
}

/** Set up for next tests */
void NextTestDelay()
{
    // check if test is over
    if( TargetHz >= 5000 )
    {
        cout << "Test completed\n";

        // request the busy loop to stop
        Timer.Stop();

        // stop the event loop
        // Do not do this in real application!
        // but this causes the test program to shut down cleanly
        io_service.stop();
    }

    // target frequency for next tests
    TargetHz += 1000;

    // fudge factor
    // the idea here is that we reduce the actual wait time
    // to allow for the time taken setting up and tearing down
    // However, I would think that this would be very short
    // for the continuous busy loop counter
    // so I do not understand why this is so large
    // and so dependant on the TargetHz
    // the actual value has been set by experimentation on my machine
    const int overheadmsecs = 10 + TargetHz / 300;

    // Calculate microseconds wait required
    WaitMicroSecs = 1000000 / TargetHz - overheadmsecs;

    Timer.WaitMicroSecs( WaitMicroSecs );

}

/** Called when timer expires

In production code this would start the next read
but for this test it simply restarts the timer

*/
void handle_expire(const boost::system::error_code& /*e*/)
{
    if( myRunCounter.Count() )
    {
        // The run counter has been called reuired times, output report
        cout << "Target " << TargetHz << " Hz Actual: "
             //            << WaitMicroSecs << " microsecs ( nominal "
             //         << 1000000 / WaitMicroSecs << " Hz ) -> "
             << (int)myRunCounter.Hz() << " Hz, delta "
             << (int)(myRunCounter.Hz() - TargetHz) << "\n";

        // check if test complete
        NextTestDelay();
    }

    // start next timed wait
    StartWait();
}

/** Called to start a new timed wait */
void StartWait()
{
    if( WaitMicroSecs > 1000 )
    {
        // use high performance timer
        // which should be reliable for waits longer than a millisecond

        myPlaybackTimer->expires_from_now(
            std::chrono::microseconds( WaitMicroSecs ) );
        myPlaybackTimer->async_wait( handle_expire );
    }
    else
    {
        //cout << "StartWait ";
        // too fast for clock interupt timer
        // so start busy loop timer in its own thread
        Timer.Wait();

        // post the first check for timer completion
        io_service.post( CheckBusyLoopDone );
    }

}

int main( int argc, char * argv[])
{
    cout << "Busy Loop Continuous timer\n";

    // ensure that the interrupt clock rate is at its maximum
    // 1 millisecond
    MMRESULT  res = timeBeginPeriod( 1 );
    if( res != TIMERR_NOERROR )
    {
        cout << "timeBeginPeriod no can do\n";
        exit(1);
    }

    // start the busy loop timer
    // for now this will just spin in its own thread
    // "waiting" for a request to start timing
    Timer.Run();

    TargetHz = 0;
    NextTestDelay();

    myPlaybackTimer = new boost::asio::high_resolution_timer( io_service );

    // Start first wait
    StartWait();

    // start event loop
    io_service.run();

    return 0;
}

ext: cpp

max_stars_repo_name: JamesBremner/raven-set

max_issues_repo_name: JamesBremner/raven-set

max_forks_repo_name: JamesBremner/raven-set


text:
/* $Id: TemplateFilter.cpp,v 1.17 2013/11/26 08:52:15 severin Exp $ */

/***

NAME - EEDB::SPStreams::TemplateFilter

SYNOPSIS

DESCRIPTION

a simple SPStream which has an internal buffer. allows for external filling of buffer
or to fill from the source_stream();

CONTACT

Jessica Severin <severin@gsc.riken.jp>

LICENSE

 * Software License Agreement (BSD License)
 * EdgeExpressDB [eeDB] system
 * copyright (c) 2007-2013 Jessica Severin RIKEN OSC
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Jessica Severin RIKEN OSC nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

APPENDIX

The rest of the documentation details each of the object methods. Internal methods are usually preceded with a _

***/

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <stdarg.h>
#include <rapidxml.hpp>  //rapidxml must be include before boost
#include <boost/algorithm/string.hpp>
#include <EEDB/Feature.h>
#include <EEDB/Experiment.h>
#include <EEDB/Symbol.h>
#include <EEDB/SPStream.h>
#include <EEDB/SPStreams/TemplateFilter.h>

using namespace std;
using namespace MQDB;

const char*  EEDB::SPStreams::TemplateFilter::class_name = "EEDB::SPStreams::TemplateFilter";

//function prototypes
MQDB::DBObject* _spstream_templatefilter_next_in_stream_func(EEDB::SPStream* node) {
  return ((EEDB::SPStreams::TemplateFilter*)node)->_next_in_stream();
}
void _spstream_templatefilter_reset_stream_node_func(EEDB::SPStream* node) {
  ((EEDB::SPStreams::TemplateFilter*)node)->_reset_stream_node();
}
void _spstream_templatefilter_delete_func(MQDB::DBObject *obj) {
  delete (EEDB::SPStreams::TemplateFilter*)obj;
}
void _spstream_templatefilter_xml_func(MQDB::DBObject *obj, string &xml_buffer) {
  ((EEDB::SPStreams::TemplateFilter*)obj)->_xml(xml_buffer);
}
bool _spstream_templatefilter_stream_by_named_region_func(EEDB::SPStream* node, string assembly_name, string chrom_name, long int start, long int end) {
  return ((EEDB::SPStreams::TemplateFilter*)node)->_stream_by_named_region(assembly_name, chrom_name, start, end);
}

EEDB::SPStreams::TemplateFilter::TemplateFilter() {
  init();
}

EEDB::SPStreams::TemplateFilter::~TemplateFilter() {
}

void EEDB::SPStreams::TemplateFilter::init() {
  EEDB::SPStreams::MergeStreams::init();
  _classname                  = EEDB::SPStreams::TemplateFilter::class_name;
  _module_name                = "TemplateFilter";

  _funcptr_delete             = _spstream_templatefilter_delete_func;
  _funcptr_xml                = _spstream_templatefilter_xml_func;
  _funcptr_simple_xml         = _spstream_templatefilter_xml_func;

  _funcptr_next_in_stream           = _spstream_templatefilter_next_in_stream_func;
  _funcptr_reset_stream_node        = _spstream_templatefilter_reset_stream_node_func;
  _funcptr_stream_by_named_region   = _spstream_templatefilter_stream_by_named_region_func;

  _overlap_mode          = "area";
  _ignore_strand         = false;
  _overlap_state         = true;
  _overlap_distance      = 0;
  _template_stream_empty     = false;
  _template_stream_primed    = false;
  _overlap_check_subfeatures = false; //extend overlap logic to require subfeature overlap
  _template_buffer.clear();
}

void EEDB::SPStreams::TemplateFilter::display_info() {
  printf("%s\n", display_desc().c_str());
}

string EEDB::SPStreams::TemplateFilter::display_desc() {
  return "TemplateFilter";
}

string EEDB::SPStreams::TemplateFilter::display_contents() {
  return display_desc();
}

////////////////////////////////////////////////////////////////////////////
//
// override method for subclasses which will
// do all the work
//
///////////////////////////////////////////////////////////////////////////

MQDB::DBObject* EEDB::SPStreams::TemplateFilter::_next_in_stream() {
  MQDB::DBObject *obj;

  if(_source_stream!=NULL) {
    while((obj = _source_stream->next_in_stream()) != NULL) {

      //non-features on the primary source stream
      //are just passed through this module
      if(obj->classname() != EEDB::Feature::class_name) {
        return obj;
      }

      //if object passes overlap-test, return it
      if(_process_feature((EEDB::Feature*)obj) == _overlap_state) { return obj; }
      obj->release();
    }
  }

  // input stream is empty so done
  return NULL;
}

/***** reset_stream_node
  Description: re-initialize this stream node prior to reconfiguring stream
*****/

void EEDB::SPStreams::TemplateFilter::_reset_stream_node() {
  EEDB::SPStreams::MergeStreams::_reset_stream_node();

  for(unsigned int i=0; i<_template_buffer.size(); i++) {
    _template_buffer[i]->release();
  }
  _template_buffer.clear();
  _template_stream_empty = false;
  _template_stream_primed= false;
}

bool EEDB::SPStreams::TemplateFilter::_stream_by_named_region(string assembly_name, string chrom_name, long int start, long int end) {
  _region_start = start;
  _region_end   = end;

  if((side_stream() == NULL) || (source_stream() == NULL)) {
    _template_stream_empty = true;
    return true;
  }
  //primary stream is dominant one, so side becomes slave to it
  //side stream is primed when needed in _process_feature()
  return source_stream()->stream_by_named_region(assembly_name, chrom_name, start, end);
}

//
////////////////////////////////////////////////////////////
//

bool  EEDB::SPStreams::TemplateFilter::_process_feature(EEDB::Feature *feature) {
  deque<EEDB::Feature*>::iterator tb_it;
  EEDB::Feature *sidefeature = NULL;

  if(!_template_stream_primed) {
    //feature is first valid feature on primary stream so use it to slave the side stream
    side_stream()->stream_by_named_region(feature->assembly_name(), feature->chrom_name(), feature->chrom_start(), -1);
    _template_stream_primed = true;
    //fprintf(stderr, "TemplateFilter prime with first feature %s\n", feature->simple_xml().c_str());
  }

  //make sure we have at least one feature in template_buffer
  if(_template_buffer.empty()) { _extend_template_buffer(); }
  if(_template_buffer.empty()) { return false; }  //no more templates to process

  //
  // trim/extend _template_buffer till first feature overlaps with current feature.
  //
  tb_it = _template_buffer.begin();
  while((tb_it!=_template_buffer.end()) and ((*tb_it)->chrom_end() < feature->chrom_start())) {
    (*tb_it)->release();
    _template_buffer.pop_front();
    if(_template_buffer.empty()) { _extend_template_buffer(); }
    tb_it = _template_buffer.begin();
  }
  // extend buffer as needed
  if(!_template_buffer.empty()) {
    sidefeature = _template_buffer.back();
    while(sidefeature and (sidefeature->chrom_start() <= feature->chrom_end())) {
      sidefeature = _extend_template_buffer();
    }
  }
  sidefeature = NULL;
  if(_template_buffer.empty()) { return false; }  //no more templates to process

  //
  // then process the overlaps in the _template_buffer
  //
  for(unsigned int i=0; i<_template_buffer.size(); i++) {
    sidefeature = _template_buffer[i];
    if(!_ignore_strand and (sidefeature->strand() != ' ') and (feature->strand()!=' ') and
       (feature->strand() != sidefeature->strand())) { continue; }
    if(_overlap_check(feature, sidefeature)) {
      return true; //if not labeling, the first overlap is good enough
    }
  }
  return false;
}

EEDB::Feature*  EEDB::SPStreams::TemplateFilter::_extend_template_buffer() {
  if(_side_stream==NULL) { return NULL; }
  if(_template_stream_empty) { return NULL; }
  MQDB::DBObject *obj = _side_stream->next_in_stream();
  while(obj!=NULL and (obj->classname() != EEDB::Feature::class_name)) {
    obj->release();
    obj = _side_stream->next_in_stream();
  }
  //side_stream is presorted so push_back retains that sort order
  if(obj==NULL) { _template_stream_empty = true; }
  else { _template_buffer.push_back((EEDB::Feature*)obj); }
  return (EEDB::Feature*)obj;
}

bool  EEDB::SPStreams::TemplateFilter::_overlap_check(EEDB::Feature *feature, EEDB::Feature *sidefeature) {
  if(feature==NULL) { return false; }
  if(sidefeature==NULL) { return false; }

  //_overlap_mode "modifies" the input stream, not the template/side stream features
  long int start = feature->chrom_start();
  long int end   = feature->chrom_end();
  if(_overlap_mode == "5end") {
    if(feature->strand() == '+') { end   = start; }
    if(feature->strand() == '-') { start = end; }
  }
  if(_overlap_mode == "3end") {
    if(feature->strand() == '+') { start = end; }
    if(feature->strand() == '-') { end   = start; }
  }

  // for feature    ::   ORDER BY chrom_start, chrom_end
  // chrom() checking must be done before this call.
  if(end   < sidefeature->chrom_start() - _overlap_distance) { return false; } //feature ends before sidefeature starts (f1<f2)
  if(start > sidefeature->chrom_end()   + _overlap_distance) { return false; } //feature starts after sidefeature ends  (f1>f2)

  if(_overlap_check_subfeatures) {
    if(!sidefeature->subfeature_overlap_check(feature)) { return false; }
  }
  return true;
}

/*****************************************************************************************/

void EEDB::SPStreams::TemplateFilter::_xml(string &xml_buffer) {
  _xml_start(xml_buffer);  //from SPStream superclass

  //older style of <ignore_strand value="1" />
  if(_ignore_strand) { xml_buffer.append("<ignore_strand>true</ignore_strand>"); }
  if(_overlap_state==false) { xml_buffer.append("<inverse>true</inverse>"); }
  if(_overlap_check_subfeatures) { xml_buffer.append("<overlap_subfeatures>true</overlap_subfeatures>"); }

  if(!_overlap_mode.empty()) {
    xml_buffer.append("<overlap_mode>");
    xml_buffer.append(_overlap_mode);
    xml_buffer.append("</overlap_mode>");
  }

  if(_overlap_distance > 0) {
    char buffer[256];
    snprintf(buffer, 256, "<distance>%ld</distance>", _overlap_distance);
    xml_buffer.append(buffer);
  }

  _xml_end(xml_buffer);  //from superclass
}

EEDB::SPStreams::TemplateFilter::TemplateFilter(void *xml_node) {
  //constructor using a rapidxml <spstream> description
  init();
  if(xml_node==NULL) { return; }

  rapidxml::xml_node<>      *root_node = (rapidxml::xml_node<>*)xml_node;
  rapidxml::xml_node<>      *node;
  rapidxml::xml_attribute<> *attr;

  if(string(root_node->name()) != "spstream") { return; }

  if((node = root_node->first_node("ignore_strand")) != NULL) {
    if(string(node->value()) == "true") { _ignore_strand=true; }
    else if((attr = node->first_attribute("value")) and (string(attr->value())=="1")) {
      _ignore_strand=true;
    }
  }
  if((node = root_node->first_node("is_strand_sensitive")) != NULL) {
    if((attr = node->first_attribute("value")) and (string(attr->value())=="0")) {
      _ignore_strand=true;
    }
  }
  if((node = root_node->first_node("inverse")) != NULL) {
    if(string(node->value()) == "true") { _overlap_state=false; }
    else if((attr = node->first_attribute("value")) and (string(attr->value())=="1")) {
      _overlap_state=false;
    }
  }
  if((node = root_node->first_node("overlap_subfeatures")) != NULL) {
    _overlap_check_subfeatures=false;
    if(string(node->value()) == "true") { _overlap_check_subfeatures=true; }
  }

  if((node = root_node->first_node("overlap_mode")) != NULL) {
    _overlap_mode=node->value();
  }

  if((node = root_node->first_node("distance")) != NULL) {
    _overlap_distance = strtol(node->value(), NULL, 10);
  }

  if((node = root_node->first_node("side_stream")) != NULL) {
    create_side_stream_from_xml(node);
  }
}


text:
// Copyright Henrik Steffen Gaßmann 2020
//
// Distributed under the Boost Software License, Version 1.0.
//         (See accompanying file LICENSE or copy at
//           https://www.boost.org/LICENSE_1_0.txt)

#include <dplx/dp/encoder/core.hpp>
#include <dplx/dp/encoder/narrow_strings.hpp>

#include <string>
#include <string_view>

#include <boost/unordered_map.hpp>

#include "boost-test.hpp"
#include "encoder.test_utils.hpp"
#include "test_output_stream.hpp"
#include "test_utils.hpp"

namespace dp_tests
{

BOOST_AUTO_TEST_SUITE(encoder)

BOOST_FIXTURE_TEST_SUITE(string, default_encoding_fixture)

using namespace std::string_view_literals;

static_assert(dp::encodable<std::u8string, test_output_stream<>>);
static_assert(dp::encodable<std::u8string_view, test_output_stream<>>);

static_assert(dp::encodable<std::string, test_output_stream<>>);
static_assert(dp::encodable<std::string_view, test_output_stream<>>);

template <typename Char>
struct basic_string_sample
{
    std::size_t prefix_length;
    std::array<std::byte, 8> expected_prefix;
    std::basic_string_view<Char> content;
};
using string_sample = basic_string_sample<char>;
using u8string_sample = basic_string_sample<char8_t>;

template <typename Char>
auto boost_test_print_type(std::ostream &s,
                           basic_string_sample<Char> const &sample)
        -> std::ostream &
{
    std::string_view charView(
            reinterpret_cast<char const *>(sample.content.data()),
            sample.content.size());

    fmt::print(s, "string_sample{{.content={}, .expected_prefix={{", charView);
    for (auto b : std::span<std::byte const>(sample.expected_prefix)
                          .first(sample.prefix_length))
    {
        fmt::print(s, "{:2x}", static_cast<std::uint8_t>(b));
    }
    fmt::print(s, "}}");

    return s;
}

constexpr u8string_sample u8string_samples[]
        = {{1, make_byte_array<8>({0b011'00000}), u8""sv},
           {1,
            make_byte_array<8, int>({0b011'00000 | 11, u8'h', u8'e', u8'l',
                                     u8'l', u8'o', u8' ', u8'w'}),
            u8"hello world"sv}};

BOOST_DATA_TEST_CASE(u8string_view_with,
                     boost::unit_test::data::make(u8string_samples))
{
    using test_type = std::u8string_view;
    using test_encoder = dp::basic_encoder<test_type, test_output_stream<>>;

    DPLX_TEST_RESULT(test_encoder()(encodingBuffer, sample.content));

    BOOST_TEST(byte_span(encodingBuffer).first(sample.prefix_length)
                       == byte_span(encodingBuffer).first(sample.prefix_length),
               boost::test_tools::per_element{});

    BOOST_TEST(byte_span(encodingBuffer).subspan(sample.prefix_length)
                       == as_bytes(std::span(sample.content)),
               boost::test_tools::per_element{});
}

BOOST_DATA_TEST_CASE(u8string_with,
                     boost::unit_test::data::make(u8string_samples))
{
    using test_type = std::u8string;
    using test_encoder = dp::basic_encoder<test_type, test_output_stream<>>;

    test_type content(sample.content);
    DPLX_TEST_RESULT(test_encoder()(encodingBuffer, content));

    BOOST_TEST(byte_span(encodingBuffer).first(sample.prefix_length)
                       == byte_span(encodingBuffer).first(sample.prefix_length),
               boost::test_tools::per_element{});

    BOOST_TEST(byte_span(encodingBuffer).subspan(sample.prefix_length)
                       == as_bytes(std::span(sample.content)),
               boost::test_tools::per_element{});
}

constexpr string_sample string_samples[]
        = {{1, make_byte_array<8>({0b011'00000}), ""sv},
           {1,
            make_byte_array<8, int>(
                    {0b011'00000 | 11, 'h', 'e', 'l', 'l', 'o', ' ', 'w'}),
            "hello world"sv}};

BOOST_DATA_TEST_CASE(string_view_with,
                     boost::unit_test::data::make(string_samples))
{
    using test_type = std::string_view;
    using test_encoder = dp::basic_encoder<test_type, test_output_stream<>>;

    DPLX_TEST_RESULT(test_encoder()(encodingBuffer, sample.content));

    BOOST_TEST(byte_span(encodingBuffer).first(sample.prefix_length)
                       == byte_span(encodingBuffer).first(sample.prefix_length),
               boost::test_tools::per_element{});

    BOOST_TEST(byte_span(encodingBuffer).subspan(sample.prefix_length)
                       == as_bytes(std::span(sample.content)),
               boost::test_tools::per_element{});
}

BOOST_DATA_TEST_CASE(string_view_size_with,
                     boost::unit_test::data::make(string_samples))
{
    BOOST_TEST(dp::encoded_size_of(sample.content)
               == sample.prefix_length + sample.content.size());
}

BOOST_DATA_TEST_CASE(string_with, boost::unit_test::data::make(string_samples))
{
    using test_type = std::string;
    using test_encoder = dp::basic_encoder<test_type, test_output_stream<>>;

    test_type content(sample.content);
    DPLX_TEST_RESULT(test_encoder()(encodingBuffer, content));

    BOOST_TEST(byte_span(encodingBuffer).first(sample.prefix_length)
                       == byte_span(encodingBuffer).first(sample.prefix_length),
               boost::test_tools::per_element{});

    BOOST_TEST(byte_span(encodingBuffer).subspan(sample.prefix_length)
                       == as_bytes(std::span(sample.content)),
               boost::test_tools::per_element{});
}

BOOST_DATA_TEST_CASE(string_size_with,
                     boost::unit_test::data::make(string_samples))
{
    BOOST_TEST(dp::encoded_size_of(std::string{sample.content})
               == sample.prefix_length + sample.content.size());
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()

} // namespace dp_tests

max_stars_repo_name: deeplex/deeppack

max_issues_repo_name: deeplex/deeppack

max_forks_repo_name: deeplex/deeppack


text:
/// ---------------------------------------------------------------------------
/// @section LICENSE
///
/// Copyright (c) 2016 Georgia Tech Research Institute (GTRI)
///               All Rights Reserved
///
/// The above copyright notice and this permission notice shall be included in
/// all copies or substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
/// DEALINGS IN THE SOFTWARE.
/// ---------------------------------------------------------------------------
/// @file filename.ext
/// @author Kevin DeMarco <kevin.demarco@gtri.gatech.edu>
/// @author Eric Squires <eric.squires@gtri.gatech.edu>
/// @version 1.0
/// ---------------------------------------------------------------------------
/// @brief A brief description.
///
/// @section DESCRIPTION
/// A long description.
/// ---------------------------------------------------------------------------
#include <scrimmage/common/FileSearch.h>
#include <iostream>
#include <unordered_set>

#include <boost/filesystem.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>

namespace fs = ::boost::filesystem;

namespace scrimmage {

void FileSearch::clear() {cache_.clear();}

bool FileSearch::find_file(const std::string &search, std::string ext, std::string env_var, std::string &result)
{
    // Find the xml file.
    // Search order:
    // 1. search could be the full path
    // 2. search could be just the name of the plugin (e.g., QuadTest_plugin)
    //    a. Is the file located in the plugin path environment variable?

    // Determine if the passed in file exists (could be full path)
    std::list<std::string> filenames;
    if (!ext.empty() && ext[0] != '.') {
        ext = std::string(".") + ext;
    }
    std::string search_filename = search + ext;

    if ( !fs::exists( search ) ) {
        // files[search_filename] = list of full paths
        std::unordered_map<std::string, std::list<std::string>> files;
        find_files(env_var, ext, files);
        filenames = files[search_filename];
    } else {
        filenames.push_back(search);
    }

    if (filenames.empty()) {
        //std::cout << "Failed to find xml filename: " << search << std::endl;
        return false;
    }

    // Use the last XML file that was found
    result = filenames.back();

    if (filenames.size() > 1) {
        std::cout << "===============================================" << std::endl;
        std::cout << "WARNING: Multiple XML files with same name found" << std::endl;
        for (std::string &full_path : filenames) {
            std::cout << full_path << std::endl;
        }
        std::cout << "Using XML file at: " << result << std::endl;
        std::cout << "===============================================" << std::endl;
    }
    return true;
}

// Give an environment variable and a file extension:
// Find the absolute path to all files in environment variable paths
void FileSearch::find_files(std::string env_var, const std::string &ext,
                            std::unordered_map<std::string, std::list<std::string>> &out)
{
    auto cache_it = cache_.find(env_var);
    auto ext_it = cache_[env_var].find(ext);
    if (cache_it != cache_.end()) {
        if (ext_it != cache_it->second.end()) {
            out = ext_it->second;
            return;
        } else {
            cache_it->second[ext];
            ext_it = cache_it->second.find(ext);
        }
    } else {
        cache_[env_var][ext];
        ext_it = cache_[env_var].find(ext);
    }

    out.clear();

    // Get the environment variable
    const char* env_p = std::getenv(env_var.c_str());
    if (env_p == NULL) {
        std::cout << env_var << " environment variable not set" << std::endl;
        return;
    }

    std::string env_path = std::string(env_p);

    // Tokenize the path and loop through each directory
    boost::char_separator<char> sep(":");
    boost::tokenizer< boost::char_separator<char> > tokens(env_path, sep);
    std::unordered_set<std::string> dirs_checked;

    BOOST_FOREACH (const std::string& t, tokens) {
        // Search for all files in the current directory with
        // the extension
        fs::path root = t;

        if (dirs_checked.count(t) > 0) {
            // pass
        } else if (fs::exists(root) && fs::is_directory(root)) {
            dirs_checked.insert(t);

            fs::recursive_directory_iterator it(root);
            fs::recursive_directory_iterator endit;

            while(it != endit) {
                fs::path path = it->path();
                if(fs::is_regular_file(*it) && path.extension() == ext) {
                    std::string fname = path.filename().string();
                    std::string full_path = fs::absolute(path).string();
                    ext_it->second[fname].push_back(full_path);
                }
                ++it;
            }
        } else {
            std::cout << "Search path doesn't exist: " << t << std::endl;
        }
    }

    out = ext_it->second;
    return;
}

} // namespace scrimmage


text:
//  Boost string_algo library compare.hpp header file  -------------------------//

//  Copyright Pavol Droba 2002-2003. Use, modification and
//  distribution is subject to the Boost Software License, Version
//  1.0. (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org for updates, documentation, and revision history.

#ifndef BOOST_STRING_COMPARE_HPP
#define BOOST_STRING_COMPARE_HPP

#include <boost/algorithm/string/config.hpp>
#include <locale>

/*! \file
    Defines element comparison predicates. Many algorithms in this library can
    take an additional argument with a predicate used to compare elements.
    This makes it possible, for instance, to have case insensitive versions
    of the algorithms.
*/

namespace boost {
    namespace algorithm {

        //  is_equal functor  -----------------------------------------------//

        //! is_equal functor
        /*!
            Standard STL equal_to only handle comparison between arguments
            of the same type. This is a less restrictive version which wraps operator ==.
        */
        struct is_equal
        {
            //! Function operator
            /*!
                Compare two operands for equality
            */
            template< typename T1, typename T2 >
                bool operator ()( const T1& Arg1, const T2& Arg2 ) const
            {
                return Arg1==Arg2;
            }
        };

        //! case insensitive version of is_equal
        /*!
            Case insensitive comparison predicate. Comparison is done using
            specified locales.
        */
        struct is_iequal
        {
            //! Constructor
            /*!
                \param Loc locales used for comparison
            */
            is_iequal( const std::locale& Loc=std::locale() ) :
                m_Loc( Loc ) {}

            //! Function operator
            /*!
                Compare two operands. Case is ignored.
            */
            template< typename T1, typename T2 >
                bool operator ()( const T1& Arg1, const T2& Arg2 ) const
            {
                return std::toupper(Arg1,m_Loc)==std::toupper(Arg2,m_Loc);
            }

        private:
            std::locale m_Loc;
        };

    } // namespace algorithm

    // pull names to the boost namespace
    using algorithm::is_equal;
    using algorithm::is_iequal;

} // namespace boost

#endif  // BOOST_STRING_COMPARE_HPP

ext: hpp

max_stars_repo_name: Imperator-Knoedel/Sunset

max_issues_repo_name: Imperator-Knoedel/Sunset

max_forks_repo_name: Imperator-Knoedel/Sunset


text:
//
// Test BOOST_TEST_EQ( p, nullptr )
//
// Copyright 2017 Peter Dimov
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//

#include <boost/config.hpp>
#include <boost/core/lightweight_test.hpp>

int main()
{
#if !defined( BOOST_NO_CXX11_NULLPTR )

    int x = 0;
    int* p1 = 0;
    int* p2 = &x;

    BOOST_TEST_EQ( p1, nullptr );
    BOOST_TEST_NE( p2, nullptr );

    BOOST_TEST_EQ( nullptr, p1 );
    BOOST_TEST_NE( nullptr, p2 );

#endif

    return boost::report_errors();
}

max_stars_repo_name: Jackarain/tinyrpc

max_issues_repo_name: avplayer/cxxrpc

max_forks_repo_name: avplayer/cxxrpc


text:
/*
 * Copyright (c) 2012, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "load_resource.h"

#include <boost/filesystem.hpp>
#include <ros/package.h>
#include <ros/ros.h>

#include <QPixmapCache>
#include <QPainter>

namespace rviz
{

boost::filesystem::path getPath( QString url )
{
  boost::filesystem::path path;

  if ( url.indexOf("package://", 0, Qt::CaseInsensitive) == 0 )
  {
    QString package_name = url.section('/',2,2);
    QString file_name = url.section('/',3);
    path = ros::package::getPath(package_name.toStdString());
    path = path / file_name.toStdString();
  }
  else if ( url.indexOf("file://", 0, Qt::CaseInsensitive) == 0 )
  {
    path = url.section('/',2).toStdString();
  }
  else
  {
    ROS_ERROR( "Invalid or unsupported URL: '%s'", url.toStdString().c_str() );
  }

  return path;
}

QPixmap loadPixmap( QString url, bool fill_cache )
{
  QPixmap pixmap;

  // if it's in the cache, no need to locate
  if ( QPixmapCache::find( url, &pixmap ) )
  {
    return pixmap;
  }

  boost::filesystem::path path = getPath( url );

  // If something goes wrong here, we go on and store the empty pixmap,
  // so the error won't appear again anytime soon.
  if ( boost::filesystem::exists( path ) )
  {
    ROS_DEBUG_NAMED( "load_resource", "Loading '%s'", path.string().c_str() );
    if ( !pixmap.load( QString::fromStdString( path.string() ) ) )
    {
      ROS_ERROR( "Could not load pixmap '%s'", path.string().c_str() );
    }
  }

  if ( fill_cache )
  {
    QPixmapCache::insert( url, pixmap );
  }

  return pixmap;
}

QCursor getDefaultCursor( bool  /*fill_cache*/ )
{
  return QCursor(Qt::ArrowCursor);
}

QCursor makeIconCursor( QString url, bool fill_cache )
{
  QPixmap icon = loadPixmap( url, fill_cache );
  if (icon.width() == 0 || icon.height() == 0)
  {
    ROS_ERROR( "Could not load pixmap '%s' -- using default cursor instead.", url.toStdString().c_str() );
    return getDefaultCursor();
  }
  QString cache_key = url + ".cursor";
  return makeIconCursor( icon, cache_key, fill_cache );
}

QCursor makeIconCursor( QPixmap icon, QString cache_key, bool fill_cache )
{
  // if it's in the cache, no need to locate
  QPixmap cursor_img;
  if ( QPixmapCache::find( cache_key, &cursor_img ) )
  {
    return QCursor( cursor_img, 0, 0 );
  }

  QPixmap base_cursor = loadPixmap( "package://rviz/icons/cursor.svg", fill_cache );

  const int cursor_size = 32;

  cursor_img = QPixmap( cursor_size, cursor_size );
  cursor_img.fill( QColor(0,0,0,0) );

  // copy base cursor & icon into one image
  QPainter painter(&cursor_img);

  int draw_x = 12;
  int draw_y = 16;

  // if the icon is too large, move it to the left
  if( draw_x+icon.width() > cursor_size )
  {
    draw_x = cursor_size-icon.width();
  }
  if( draw_y+icon.height() > cursor_size )
  {
    draw_y = cursor_size-icon.height();
  }

  painter.drawPixmap( 0, 0, base_cursor );
  painter.drawPixmap( draw_x, draw_y, icon );

  if ( fill_cache )
  {
    QPixmapCache::insert( cache_key, cursor_img );
  }

  return QCursor( cursor_img, 1, 1 );
}

}


text: #include <boost/mpl/vector/aux_/preprocessed/no_ctps/vector50.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
/*=============================================================================
    Copyright (c) 2003 Joel de Guzman

    Use, modification and distribution is subject to the Boost Software
    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
    http://www.boost.org/LICENSE_1_0.txt)
==============================================================================*/
#if !defined(FUSION_ALGORITHM_FIND_IF_HPP)
#define FUSION_ALGORITHM_FIND_IF_HPP

#include <boost/spirit/fusion/algorithm/detail/find_if.ipp>
#include <boost/spirit/fusion/sequence/begin.hpp>
#include <boost/spirit/fusion/sequence/end.hpp>

namespace boost { namespace fusion
{
    namespace meta
    {
        template <typename Sequence, typename Pred>
        struct find_if
        {
            typedef typename
                detail::static_find_if<
                    typename meta::begin<Sequence>::type
                  , typename meta::end<Sequence>::type
                  , Pred
                >::type
            type;
        };
    }

    namespace function
    {
        struct find_if
        {
            template <typename Sequence, typename Pred>
            struct apply : meta::find_if<Sequence, Pred> {};

            template <typename Sequence, typename Pred>
            inline typename apply<Sequence const, Pred>::type
            operator()(Sequence const& seq, Pred) const
            {
                typedef
                    detail::static_find_if<
                        typename meta::begin<Sequence const>::type
                      , typename meta::end<Sequence const>::type
                      , Pred
                    >
                filter;

                return filter::call(fusion::begin(seq));
            }

            template <typename Sequence, typename Pred>
            inline typename apply<Sequence, Pred>::type
            operator()(Sequence& seq, Pred) const
            {
                typedef
                    detail::static_find_if<
                        typename meta::begin<Sequence>::type
                      , typename meta::end<Sequence>::type
                      , Pred
                    >
                filter;

                return filter::call(fusion::begin(seq));
            }
        };
    }

    function::find_if const find_if = function::find_if();
}}

#endif

max_stars_repo_name: macaurther/DOCUSA

max_issues_repo_name: macaurther/DOCUSA

max_forks_repo_name: dguenms/Dawn-of-Civilization