1 /*
2 * Copyright 2022 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "fcp/client/cache/temp_files.h"
18
19 #include <filesystem>
20 #include <fstream>
21 #include <functional>
22 #include <string>
23 #include <utility>
24
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 #include "absl/status/statusor.h"
28 #include "fcp/client/test_helpers.h"
29 #include "fcp/testing/testing.h"
30
31 namespace fcp {
32 namespace client {
33 namespace cache {
34 namespace {
35
CountFilesInDir(const std::filesystem::path & dir)36 int CountFilesInDir(const std::filesystem::path& dir) {
37 int num_files = 0;
38 for ([[maybe_unused]] auto const& unused :
39 std::filesystem::directory_iterator{dir}) {
40 num_files++;
41 }
42 return num_files;
43 }
44
45 class TempFilesTest : public testing::Test {
46 protected:
SetUp()47 void SetUp() override {
48 root_dir_ = testing::TempDir();
49 std::filesystem::path root_dir(root_dir_);
50 temp_file_dir_ =
51 root_dir / TempFiles::kParentDir / TempFiles::kTempFilesDir;
52 }
TearDown()53 void TearDown() override {
54 std::filesystem::remove_all(std::filesystem::path(root_dir_));
55 }
56
57 testing::StrictMock<MockLogManager> log_manager_;
58 std::string root_dir_;
59 std::filesystem::path temp_file_dir_;
60 };
61
TEST_F(TempFilesTest,FailToCreateParentDirectory)62 TEST_F(TempFilesTest, FailToCreateParentDirectory) {
63 ASSERT_THAT(TempFiles::Create("/proc/0", &log_manager_), IsCode(INTERNAL));
64 }
65
TEST_F(TempFilesTest,InvalidRelativePath)66 TEST_F(TempFilesTest, InvalidRelativePath) {
67 ASSERT_THAT(TempFiles::Create("relative/cache", &log_manager_),
68 IsCode(INVALID_ARGUMENT));
69 }
70
TEST_F(TempFilesTest,SuccessfulInitialization)71 TEST_F(TempFilesTest, SuccessfulInitialization) {
72 ASSERT_OK(TempFiles::Create(root_dir_, &log_manager_));
73 }
74
TEST_F(TempFilesTest,CreateTempFile)75 TEST_F(TempFilesTest, CreateTempFile) {
76 auto temp_files = TempFiles::Create(root_dir_, &log_manager_);
77 ASSERT_OK(temp_files);
78 auto temp_file = (*temp_files)->CreateTempFile("stefan", ".cool");
79 ASSERT_OK(temp_file);
80 }
81
TEST_F(TempFilesTest,CreateSomeTempFilesThenDeleteInDtor)82 TEST_F(TempFilesTest, CreateSomeTempFilesThenDeleteInDtor) {
83 auto temp_files = TempFiles::Create(root_dir_, &log_manager_);
84 ASSERT_OK(temp_files);
85 int num_temp_files = 4;
86 for (int i = 0; i < num_temp_files; i++) {
87 ASSERT_OK((*temp_files)->CreateTempFile("stefan", ".cool"));
88 }
89 ASSERT_EQ(num_temp_files, CountFilesInDir(temp_file_dir_));
90
91 temp_files->reset(); // deleting temp_files should empty the directory.
92
93 ASSERT_EQ(0, CountFilesInDir(temp_file_dir_));
94 }
95
TEST_F(TempFilesTest,CreatingTempFilesDeletesExistingFiles)96 TEST_F(TempFilesTest, CreatingTempFilesDeletesExistingFiles) {
97 std::filesystem::path root_dir(root_dir_);
98
99 ASSERT_TRUE(std::filesystem::create_directories(temp_file_dir_));
100
101 int num_existing_temp_files = 10;
102 for (int i = 0; i < num_existing_temp_files; i++) {
103 std::filesystem::path temp_file_path =
104 temp_file_dir_ / absl::StrCat("temp", i);
105 std::ofstream{temp_file_path};
106 }
107 ASSERT_EQ(num_existing_temp_files, CountFilesInDir(temp_file_dir_));
108
109 auto temp_files = TempFiles::Create(root_dir_, &log_manager_);
110 ASSERT_OK(temp_files);
111 ASSERT_EQ(0, CountFilesInDir(temp_file_dir_));
112 }
113
TEST_F(TempFilesTest,FailToDeleteTempFilesLogs)114 TEST_F(TempFilesTest, FailToDeleteTempFilesLogs) {
115 // Create a temp file in the temp dir
116 auto temp_files = TempFiles::Create(root_dir_, &log_manager_);
117 ASSERT_OK(temp_files);
118 ASSERT_OK((*temp_files)->CreateTempFile("stefan", ".cool"));
119 ASSERT_OK((*temp_files)->CreateTempFile("stefan", ".cool"));
120 ASSERT_OK((*temp_files)->CreateTempFile("stefan", ".cool"));
121 ASSERT_EQ(3, CountFilesInDir(temp_file_dir_));
122
123 // Delete the temp file dir and root dir, which should cause the dtor to fail
124 // because we deleted the directories out from underneath it.
125 std::filesystem::remove_all(std::filesystem::path(root_dir_));
126
127 EXPECT_CALL(log_manager_,
128 LogDiag(ProdDiagCode::TEMP_FILES_NATIVE_FAILED_TO_DELETE));
129 temp_files->reset();
130 }
131
132 } // namespace
133 } // namespace cache
134 } // namespace client
135 } // namespace fcp
136