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.
5 #include "base/files/important_file_writer.h"
8 #include "base/compiler_specific.h"
9 #include "base/file_util.h"
10 #include "base/files/file_path.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/run_loop.h"
15 #include "base/threading/thread.h"
16 #include "base/time/time.h"
17 #include "testing/gtest/include/gtest/gtest.h"
23 std::string
GetFileContent(const FilePath
& path
) {
25 if (!ReadFileToString(path
, &content
)) {
31 class DataSerializer
: public ImportantFileWriter::DataSerializer
{
33 explicit DataSerializer(const std::string
& data
) : data_(data
) {
36 virtual bool SerializeData(std::string
* output
) OVERRIDE
{
37 output
->assign(data_
);
42 const std::string data_
;
45 class SuccessfulWriteObserver
{
47 SuccessfulWriteObserver() : successful_write_observed_(false) {}
49 // Register on_successful_write() to be called on the next successful write
51 void ObserveNextSuccessfulWrite(ImportantFileWriter
* writer
);
53 // Returns true if a successful write was observed via on_successful_write()
54 // and resets the observation state to false regardless.
55 bool GetAndResetObservationState();
58 void on_successful_write() {
59 EXPECT_FALSE(successful_write_observed_
);
60 successful_write_observed_
= true;
63 bool successful_write_observed_
;
65 DISALLOW_COPY_AND_ASSIGN(SuccessfulWriteObserver
);
68 void SuccessfulWriteObserver::ObserveNextSuccessfulWrite(
69 ImportantFileWriter
* writer
) {
70 writer
->RegisterOnNextSuccessfulWriteCallback(base::Bind(
71 &SuccessfulWriteObserver::on_successful_write
, base::Unretained(this)));
74 bool SuccessfulWriteObserver::GetAndResetObservationState() {
75 bool was_successful_write_observed
= successful_write_observed_
;
76 successful_write_observed_
= false;
77 return was_successful_write_observed
;
82 class ImportantFileWriterTest
: public testing::Test
{
84 ImportantFileWriterTest() { }
85 virtual void SetUp() {
86 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
87 file_
= temp_dir_
.path().AppendASCII("test-file");
91 SuccessfulWriteObserver successful_write_observer_
;
96 ScopedTempDir temp_dir_
;
99 TEST_F(ImportantFileWriterTest
, Basic
) {
100 ImportantFileWriter
writer(file_
, MessageLoopProxy::current().get());
101 EXPECT_FALSE(PathExists(writer
.path()));
102 EXPECT_FALSE(successful_write_observer_
.GetAndResetObservationState());
103 writer
.WriteNow("foo");
104 RunLoop().RunUntilIdle();
106 EXPECT_FALSE(successful_write_observer_
.GetAndResetObservationState());
107 ASSERT_TRUE(PathExists(writer
.path()));
108 EXPECT_EQ("foo", GetFileContent(writer
.path()));
111 TEST_F(ImportantFileWriterTest
, BasicWithSuccessfulWriteObserver
) {
112 ImportantFileWriter
writer(file_
, MessageLoopProxy::current().get());
113 EXPECT_FALSE(PathExists(writer
.path()));
114 EXPECT_FALSE(successful_write_observer_
.GetAndResetObservationState());
115 successful_write_observer_
.ObserveNextSuccessfulWrite(&writer
);
116 writer
.WriteNow("foo");
117 RunLoop().RunUntilIdle();
119 // Confirm that the observer is invoked.
120 EXPECT_TRUE(successful_write_observer_
.GetAndResetObservationState());
121 ASSERT_TRUE(PathExists(writer
.path()));
122 EXPECT_EQ("foo", GetFileContent(writer
.path()));
124 // Confirm that re-installing the observer works for another write.
125 EXPECT_FALSE(successful_write_observer_
.GetAndResetObservationState());
126 successful_write_observer_
.ObserveNextSuccessfulWrite(&writer
);
127 writer
.WriteNow("bar");
128 RunLoop().RunUntilIdle();
130 EXPECT_TRUE(successful_write_observer_
.GetAndResetObservationState());
131 ASSERT_TRUE(PathExists(writer
.path()));
132 EXPECT_EQ("bar", GetFileContent(writer
.path()));
134 // Confirm that writing again without re-installing the observer doesn't
135 // result in a notification.
136 EXPECT_FALSE(successful_write_observer_
.GetAndResetObservationState());
137 writer
.WriteNow("baz");
138 RunLoop().RunUntilIdle();
140 EXPECT_FALSE(successful_write_observer_
.GetAndResetObservationState());
141 ASSERT_TRUE(PathExists(writer
.path()));
142 EXPECT_EQ("baz", GetFileContent(writer
.path()));
145 TEST_F(ImportantFileWriterTest
, ScheduleWrite
) {
146 ImportantFileWriter
writer(file_
, MessageLoopProxy::current().get());
147 writer
.set_commit_interval(TimeDelta::FromMilliseconds(25));
148 EXPECT_FALSE(writer
.HasPendingWrite());
149 DataSerializer
serializer("foo");
150 writer
.ScheduleWrite(&serializer
);
151 EXPECT_TRUE(writer
.HasPendingWrite());
152 MessageLoop::current()->PostDelayedTask(
154 MessageLoop::QuitWhenIdleClosure(),
155 TimeDelta::FromMilliseconds(100));
156 MessageLoop::current()->Run();
157 EXPECT_FALSE(writer
.HasPendingWrite());
158 ASSERT_TRUE(PathExists(writer
.path()));
159 EXPECT_EQ("foo", GetFileContent(writer
.path()));
162 TEST_F(ImportantFileWriterTest
, DoScheduledWrite
) {
163 ImportantFileWriter
writer(file_
, MessageLoopProxy::current().get());
164 EXPECT_FALSE(writer
.HasPendingWrite());
165 DataSerializer
serializer("foo");
166 writer
.ScheduleWrite(&serializer
);
167 EXPECT_TRUE(writer
.HasPendingWrite());
168 writer
.DoScheduledWrite();
169 MessageLoop::current()->PostDelayedTask(
171 MessageLoop::QuitWhenIdleClosure(),
172 TimeDelta::FromMilliseconds(100));
173 MessageLoop::current()->Run();
174 EXPECT_FALSE(writer
.HasPendingWrite());
175 ASSERT_TRUE(PathExists(writer
.path()));
176 EXPECT_EQ("foo", GetFileContent(writer
.path()));
179 TEST_F(ImportantFileWriterTest
, BatchingWrites
) {
180 ImportantFileWriter
writer(file_
, MessageLoopProxy::current().get());
181 writer
.set_commit_interval(TimeDelta::FromMilliseconds(25));
182 DataSerializer
foo("foo"), bar("bar"), baz("baz");
183 writer
.ScheduleWrite(&foo
);
184 writer
.ScheduleWrite(&bar
);
185 writer
.ScheduleWrite(&baz
);
186 MessageLoop::current()->PostDelayedTask(
188 MessageLoop::QuitWhenIdleClosure(),
189 TimeDelta::FromMilliseconds(100));
190 MessageLoop::current()->Run();
191 ASSERT_TRUE(PathExists(writer
.path()));
192 EXPECT_EQ("baz", GetFileContent(writer
.path()));