1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/files/important_file_writer.h"
6
7 #include "base/bind.h"
8 #include "base/compiler_specific.h"
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/run_loop.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/threading/thread.h"
19 #include "base/threading/thread_task_runner_handle.h"
20 #include "base/time/time.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace base {
24
25 namespace {
26
GetFileContent(const FilePath & path)27 std::string GetFileContent(const FilePath& path) {
28 std::string content;
29 if (!ReadFileToString(path, &content)) {
30 NOTREACHED();
31 }
32 return content;
33 }
34
35 class DataSerializer : public ImportantFileWriter::DataSerializer {
36 public:
DataSerializer(const std::string & data)37 explicit DataSerializer(const std::string& data) : data_(data) {
38 }
39
SerializeData(std::string * output)40 bool SerializeData(std::string* output) override {
41 output->assign(data_);
42 return true;
43 }
44
45 private:
46 const std::string data_;
47 };
48
49 class SuccessfulWriteObserver {
50 public:
SuccessfulWriteObserver()51 SuccessfulWriteObserver() : successful_write_observed_(false) {}
52
53 // Register on_successful_write() to be called on the next successful write
54 // of |writer|.
55 void ObserveNextSuccessfulWrite(ImportantFileWriter* writer);
56
57 // Returns true if a successful write was observed via on_successful_write()
58 // and resets the observation state to false regardless.
59 bool GetAndResetObservationState();
60
61 private:
on_successful_write()62 void on_successful_write() {
63 EXPECT_FALSE(successful_write_observed_);
64 successful_write_observed_ = true;
65 }
66
67 bool successful_write_observed_;
68
69 DISALLOW_COPY_AND_ASSIGN(SuccessfulWriteObserver);
70 };
71
ObserveNextSuccessfulWrite(ImportantFileWriter * writer)72 void SuccessfulWriteObserver::ObserveNextSuccessfulWrite(
73 ImportantFileWriter* writer) {
74 writer->RegisterOnNextSuccessfulWriteCallback(base::Bind(
75 &SuccessfulWriteObserver::on_successful_write, base::Unretained(this)));
76 }
77
GetAndResetObservationState()78 bool SuccessfulWriteObserver::GetAndResetObservationState() {
79 bool was_successful_write_observed = successful_write_observed_;
80 successful_write_observed_ = false;
81 return was_successful_write_observed;
82 }
83
84 } // namespace
85
86 class ImportantFileWriterTest : public testing::Test {
87 public:
ImportantFileWriterTest()88 ImportantFileWriterTest() { }
SetUp()89 void SetUp() override {
90 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
91 file_ = temp_dir_.path().AppendASCII("test-file");
92 }
93
94 protected:
95 SuccessfulWriteObserver successful_write_observer_;
96 FilePath file_;
97 MessageLoop loop_;
98
99 private:
100 ScopedTempDir temp_dir_;
101 };
102
TEST_F(ImportantFileWriterTest,Basic)103 TEST_F(ImportantFileWriterTest, Basic) {
104 ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
105 EXPECT_FALSE(PathExists(writer.path()));
106 EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
107 writer.WriteNow(WrapUnique(new std::string("foo")));
108 RunLoop().RunUntilIdle();
109
110 EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
111 ASSERT_TRUE(PathExists(writer.path()));
112 EXPECT_EQ("foo", GetFileContent(writer.path()));
113 }
114
TEST_F(ImportantFileWriterTest,BasicWithSuccessfulWriteObserver)115 TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) {
116 ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
117 EXPECT_FALSE(PathExists(writer.path()));
118 EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
119 successful_write_observer_.ObserveNextSuccessfulWrite(&writer);
120 writer.WriteNow(WrapUnique(new std::string("foo")));
121 RunLoop().RunUntilIdle();
122
123 // Confirm that the observer is invoked.
124 EXPECT_TRUE(successful_write_observer_.GetAndResetObservationState());
125 ASSERT_TRUE(PathExists(writer.path()));
126 EXPECT_EQ("foo", GetFileContent(writer.path()));
127
128 // Confirm that re-installing the observer works for another write.
129 EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
130 successful_write_observer_.ObserveNextSuccessfulWrite(&writer);
131 writer.WriteNow(WrapUnique(new std::string("bar")));
132 RunLoop().RunUntilIdle();
133
134 EXPECT_TRUE(successful_write_observer_.GetAndResetObservationState());
135 ASSERT_TRUE(PathExists(writer.path()));
136 EXPECT_EQ("bar", GetFileContent(writer.path()));
137
138 // Confirm that writing again without re-installing the observer doesn't
139 // result in a notification.
140 EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
141 writer.WriteNow(WrapUnique(new std::string("baz")));
142 RunLoop().RunUntilIdle();
143
144 EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
145 ASSERT_TRUE(PathExists(writer.path()));
146 EXPECT_EQ("baz", GetFileContent(writer.path()));
147 }
148
TEST_F(ImportantFileWriterTest,ScheduleWrite)149 TEST_F(ImportantFileWriterTest, ScheduleWrite) {
150 ImportantFileWriter writer(file_,
151 ThreadTaskRunnerHandle::Get(),
152 TimeDelta::FromMilliseconds(25));
153 EXPECT_FALSE(writer.HasPendingWrite());
154 DataSerializer serializer("foo");
155 writer.ScheduleWrite(&serializer);
156 EXPECT_TRUE(writer.HasPendingWrite());
157 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
158 FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
159 TimeDelta::FromMilliseconds(100));
160 RunLoop().Run();
161 EXPECT_FALSE(writer.HasPendingWrite());
162 ASSERT_TRUE(PathExists(writer.path()));
163 EXPECT_EQ("foo", GetFileContent(writer.path()));
164 }
165
TEST_F(ImportantFileWriterTest,DoScheduledWrite)166 TEST_F(ImportantFileWriterTest, DoScheduledWrite) {
167 ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
168 EXPECT_FALSE(writer.HasPendingWrite());
169 DataSerializer serializer("foo");
170 writer.ScheduleWrite(&serializer);
171 EXPECT_TRUE(writer.HasPendingWrite());
172 writer.DoScheduledWrite();
173 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
174 FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
175 TimeDelta::FromMilliseconds(100));
176 RunLoop().Run();
177 EXPECT_FALSE(writer.HasPendingWrite());
178 ASSERT_TRUE(PathExists(writer.path()));
179 EXPECT_EQ("foo", GetFileContent(writer.path()));
180 }
181
TEST_F(ImportantFileWriterTest,BatchingWrites)182 TEST_F(ImportantFileWriterTest, BatchingWrites) {
183 ImportantFileWriter writer(file_,
184 ThreadTaskRunnerHandle::Get(),
185 TimeDelta::FromMilliseconds(25));
186 DataSerializer foo("foo"), bar("bar"), baz("baz");
187 writer.ScheduleWrite(&foo);
188 writer.ScheduleWrite(&bar);
189 writer.ScheduleWrite(&baz);
190 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
191 FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
192 TimeDelta::FromMilliseconds(100));
193 RunLoop().Run();
194 ASSERT_TRUE(PathExists(writer.path()));
195 EXPECT_EQ("baz", GetFileContent(writer.path()));
196 }
197
198 } // namespace base
199