//------------------------------------------------------------------------------ // File: ScanDirTests.cc // Author: Elvin Sindrilaru - CERN //------------------------------------------------------------------------------ /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2019 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ #include "gmock/gmock.h" #include "gtest/gtest.h" #define IN_TEST_HARNESS #include "fst/ScanDir.hh" #undef IN_TEST_HARNESS #include "fst/Load.hh" #include "common/Constants.hh" #include "unit_tests/fst/TmpDirTree.hh" //------------------------------------------------------------------------------ // Helper method to convert current timestamp to string microseconds // representation //------------------------------------------------------------------------------ std::string GetTimestampSec(eos::common::SteadyClock& clock) { using namespace std::chrono; uint64_t now_us = duration_cast (clock.getTime().time_since_epoch()).count(); return std::to_string(now_us); } //------------------------------------------------------------------------------ // MockLoad class //------------------------------------------------------------------------------ class MockLoad: public eos::fst::Load { public: MOCK_METHOD2(GetDiskRate, double(const char*, const char*)); }; TEST(ScanDir, RescanTiming) { using namespace std::chrono; std::string path {"/"}; eos::common::FileSystem::fsid_t fsid = 1; // Scanner completely disabled eos::fst::ScanDir sd(path.c_str(), fsid, nullptr, false, 0, 50, true); auto& clock = sd.GetClock(); std::string sinit_ts = GetTimestampSec(clock); ASSERT_FALSE(sd.DoRescan("")); clock.advance(seconds(65)); ASSERT_FALSE(sd.DoRescan(sinit_ts)); // Configure the scan interval to 60 seconds sd.SetConfig("scaninterval", 60); // First time the file should be scanned ASSERT_TRUE(sd.DoRescan("")); // Update initial timestamp sinit_ts = GetTimestampSec(clock); ASSERT_FALSE(sd.DoRescan(sinit_ts)); clock.advance(seconds(59)); ASSERT_FALSE(sd.DoRescan(sinit_ts)); clock.advance(seconds(2)); ASSERT_TRUE(sd.DoRescan(sinit_ts)); } TEST(ScanDir, TimestampSmeared) { using namespace std::chrono; std::string path {"/"}; eos::common::FileSystem::fsid_t fsid = 1; eos::fst::ScanDir sd(path.c_str(), fsid, nullptr, false, 0, 50, true); int interval = 300; sd.SetConfig(eos::common::SCAN_ENTRY_INTERVAL_NAME, interval); auto& clock = sd.GetClock(); clock.advance(seconds(5000)); for (int count = 0; count < 100; ++count) { uint64_t ts_sec = duration_cast (clock.getTime().time_since_epoch()).count(); auto sts = sd.GetTimestampSmearedSec(); ASSERT_TRUE(std::stoull(sts) >= ts_sec - interval); ASSERT_TRUE(std::stoull(sts) <= ts_sec + interval); clock.advance(seconds(1000)); } } TEST(ScanDir, AdjustScanRate) { using namespace std::chrono; using ::testing::_; using ::testing::Return; // Mock load class to return first a value for the disk rate below the // threshold and then only values above the threshold to trigger the // adjustment of the scan_rate but not lower then 5 MB/s MockLoad load; EXPECT_CALL(load, GetDiskRate(_, _) ).WillOnce(Return(500.0)).WillRepeatedly(Return(800.0)); std::string path {"/"}; eos::common::FileSystem::fsid_t fsid = 1; off_t offset = 0; int rate = 75; // MB/s eos::fst::ScanDir sd(path.c_str(), fsid, &load, false, 0, rate, true); const auto open_ts = std::chrono::system_clock::now(); int old_rate = rate; sd.EnforceAndAdjustScanRate(offset, open_ts, rate); ASSERT_EQ(rate, old_rate); while (rate > 5) { old_rate = rate; sd.EnforceAndAdjustScanRate(offset, open_ts, rate); ASSERT_EQ(rate, (int)(old_rate * 0.9)); } ASSERT_LE(rate, 5); } TEST_F(TmpDirTree, ScanDirSetConfig) { MockLoad load; eos::common::FileSystem::fsid_t fsid = 1; eos::fst::ScanDir sd(TMP_DIR_ROOT.c_str(), fsid, &load, false, 0, 100, true); ASSERT_EQ(TMP_DIR_ROOT, "/tmp/fstest"); ASSERT_EQ(sd.mDirPath, TMP_DIR_ROOT); ASSERT_EQ(sd.mDiskIntervalSec, eos::fst::DEFAULT_DISK_INTERVAL); #ifdef _NOOFS sd.SetConfig(eos::common::SCAN_DISK_INTERVAL_NAME, 3000); ASSERT_EQ(sd.mDiskIntervalSec, 3000); // This toggle logic is to ensure that CAS functions correctly sd.SetConfig(eos::common::SCAN_DISK_INTERVAL_NAME, eos::fst::DEFAULT_DISK_INTERVAL); ASSERT_EQ(sd.mDiskIntervalSec, eos::fst::DEFAULT_DISK_INTERVAL); sd.SetConfig(eos::common::SCAN_DISK_INTERVAL_NAME, 2500); ASSERT_EQ(sd.mDiskIntervalSec, 2500); #endif }