summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorMaksim Denisov <denisov.maksim@huawei.com>2024-03-11 14:32:20 +0100
committerMaksim Denisov <denisov.maksim@huawei.com>2024-04-02 15:30:03 +0200
commit8a0b8d3b0fcde046810eba5373649616c88d44da (patch)
treea3c1998a04b4216ea2b696088108cc16642b08a8 /test
parent2fd9e21ac7e29e83e535cc33a0d5429d89613057 (diff)
downloadjustbuild-8a0b8d3b0fcde046810eba5373649616c88d44da.tar.gz
LargeObjectUtils: Randomize large files and directories for testing purposes
Diffstat (limited to 'test')
-rw-r--r--test/utils/TARGETS11
-rw-r--r--test/utils/large_objects/large_object_utils.cpp152
-rw-r--r--test/utils/large_objects/large_object_utils.hpp51
3 files changed, 214 insertions, 0 deletions
diff --git a/test/utils/TARGETS b/test/utils/TARGETS
index 8cf95774..df238ca5 100644
--- a/test/utils/TARGETS
+++ b/test/utils/TARGETS
@@ -50,6 +50,17 @@
]
, "stage": ["test", "utils"]
}
+, "large_object_utils":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["large_object_utils"]
+ , "hdrs": ["large_objects/large_object_utils.hpp"]
+ , "srcs": ["large_objects/large_object_utils.cpp"]
+ , "private-deps":
+ [ ["@", "src", "src/utils/cpp", "gsl"]
+ , ["@", "src", "src/buildtool/file_system", "file_system_manager"]
+ ]
+ , "stage": ["test", "utils"]
+ }
, "catch-main-remote-execution":
{ "type": ["@", "rules", "CC", "library"]
, "name": ["catch-main-remote-execution"]
diff --git a/test/utils/large_objects/large_object_utils.cpp b/test/utils/large_objects/large_object_utils.cpp
new file mode 100644
index 00000000..b7bcebdc
--- /dev/null
+++ b/test/utils/large_objects/large_object_utils.cpp
@@ -0,0 +1,152 @@
+// Copyright 2024 Huawei Cloud Computing Technology Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "test/utils/large_objects/large_object_utils.hpp"
+
+#include <cstddef>
+#include <fstream>
+#include <limits>
+#include <random>
+#include <string>
+
+#include "src/buildtool/file_system/file_system_manager.hpp"
+#include "src/utils/cpp/gsl.hpp"
+
+namespace {
+class Randomizer final {
+ public:
+ Randomizer(std::uint64_t min, std::uint64_t max) noexcept
+ : range_(std::random_device{}()), distribution_(min, max) {}
+
+ [[nodiscard]] inline auto Get() noexcept -> uint64_t {
+ return distribution_(range_);
+ }
+
+ private:
+ std::mt19937_64 range_;
+ std::uniform_int_distribution<std::mt19937_64::result_type> distribution_;
+};
+
+/// \brief Create a number of chunks of the predefined size.
+/// \tparam UChunkLength Length of each chunk.
+/// \tparam USize Number of chunks.
+template <size_t kChunkLength, size_t kPoolSize>
+class ChunkPool final {
+ public:
+ [[nodiscard]] static auto Instance() noexcept
+ -> ChunkPool<kChunkLength, kPoolSize> const& {
+ static ChunkPool<kChunkLength, kPoolSize> pool;
+ return pool;
+ }
+
+ [[nodiscard]] auto operator[](size_t index) const noexcept
+ -> std::string const& {
+ return gsl::at(pool_, static_cast<std::ptrdiff_t>(index));
+ }
+
+ private:
+ std::array<std::string, kPoolSize> pool_;
+
+ explicit ChunkPool() noexcept {
+ // Starts from 1 to exclude '\0' from randomization
+ Randomizer randomizer{1, std::numeric_limits<char>::max()};
+
+ for (size_t i = 0; i < pool_.size(); ++i) {
+ auto& chunk = gsl::at(pool_, static_cast<std::ptrdiff_t>(i));
+ chunk.resize(kChunkLength);
+ for (size_t j = 0; j < kChunkLength; ++j) {
+ chunk[j] = randomizer.Get();
+ }
+ }
+ }
+};
+} // namespace
+
+auto LargeObjectUtils::GenerateFile(std::filesystem::path const& path,
+ std::uintmax_t size) noexcept -> bool {
+ // Remove the file, if exists:
+ if (not FileSystemManager::RemoveFile(path)) {
+ return false;
+ }
+
+ static constexpr size_t kChunkLength = 128;
+ static constexpr size_t kPoolSize = 64;
+ using Pool = ChunkPool<kChunkLength, kPoolSize>;
+
+ // To create a random file, the initial chunk position and the shift are
+ // randomized:
+ Randomizer randomizer{std::numeric_limits<size_t>::min(),
+ std::numeric_limits<size_t>::max()};
+ const size_t pool_index = randomizer.Get() % kPoolSize;
+ const size_t pool_shift = randomizer.Get() % 10;
+ const size_t step_count = size / kChunkLength + 1;
+
+ try {
+ std::ofstream stream(path);
+ for (size_t i = 0; i < step_count && stream.good(); ++i) {
+ const size_t index = (pool_index + i * pool_shift) % kPoolSize;
+ if (i != step_count - 1) {
+ stream << Pool::Instance()[index];
+ }
+ else {
+ auto count = std::min(size - kChunkLength * i, kChunkLength);
+ stream << Pool::Instance()[index].substr(0, count);
+ }
+ }
+ if (not stream.good()) {
+ return false;
+ }
+ stream.close();
+ } catch (...) {
+ return false;
+ }
+ return true;
+}
+
+auto LargeObjectUtils::GenerateDirectory(std::filesystem::path const& path,
+ std::uintmax_t entries_count) noexcept
+ -> bool {
+ // Recreate the directory:
+ if (not FileSystemManager::RemoveDirectory(path) or
+ not FileSystemManager::CreateDirectory(path)) {
+ return false;
+ }
+
+ Randomizer randomizer{std::numeric_limits<size_t>::min(),
+ std::numeric_limits<size_t>::max()};
+
+ std::uintmax_t entries = 0;
+ while (entries < entries_count) {
+ // Randomize the number for a file:
+ auto const random_number = randomizer.Get();
+ auto const file_name =
+ std::string(kTreeEntryPrefix) + std::to_string(random_number);
+ std::filesystem::path const file_path = path / file_name;
+
+ // Check file uniqueness:
+ if (FileSystemManager::IsFile(file_path)) {
+ continue;
+ }
+
+ try {
+ std::ofstream stream(file_path);
+ stream << random_number;
+ stream.close();
+ } catch (...) {
+ return false;
+ }
+ ++entries;
+ }
+ return true;
+}
diff --git a/test/utils/large_objects/large_object_utils.hpp b/test/utils/large_objects/large_object_utils.hpp
new file mode 100644
index 00000000..96619518
--- /dev/null
+++ b/test/utils/large_objects/large_object_utils.hpp
@@ -0,0 +1,51 @@
+// Copyright 2024 Huawei Cloud Computing Technology Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef INCLUDED_SRC_TEST_UTILS_LARGE_OBJECTS_LARGE_OBJECT_UTILS_HPP
+#define INCLUDED_SRC_TEST_UTILS_LARGE_OBJECTS_LARGE_OBJECT_UTILS_HPP
+
+#include <cstdint>
+#include <filesystem>
+#include <string_view>
+
+/// \brief Provides an interface for randomizing large files and directories.
+class LargeObjectUtils {
+ public:
+ static constexpr std::string_view kTreeEntryPrefix =
+ "additional-large-prefix-to-make-tree-entry-larger";
+
+ /// \brief Generate a file of the specified size in the specified location.
+ /// If the file exists, it is overwritten. To reduce the number of
+ /// randomizations, a pool of pre-generated chunks is used.
+ /// \param path Output path.
+ /// \param size Size of the resulting file in bytes.
+ /// \return True if the file is generated properly.
+ [[nodiscard]] static auto GenerateFile(std::filesystem::path const& path,
+ std::uintmax_t size) noexcept
+ -> bool;
+
+ /// \brief Generate a directory in the specified location and fill it with a
+ /// number of randomized files. If the directory exists, it is overwritten.
+ /// The name of each file contains a random number and is prefixed with
+ /// kTreeEntryPrefix (to make tree entry larger for git). Each file contains
+ /// the same random number as in it's name.
+ /// \param path Output path.
+ /// \param entries_count Number of file entries in the directory.
+ /// \return True if the directory is generated properly.
+ [[nodiscard]] static auto GenerateDirectory(
+ std::filesystem::path const& path,
+ std::uintmax_t entries_count) noexcept -> bool;
+};
+
+#endif // INCLUDED_SRC_TEST_UTILS_LARGE_OBJECTS_LARGE_OBJECT_UTILS_HPP