blob: a444c4802ee08ab36829dd77133c30d8a870917e [file] [log] [blame]
[email protected]64bb4cb32012-01-05 19:17:161// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]6faa0e0d2009-04-28 06:50:362// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]43486252012-10-24 16:33:365#include "base/files/important_file_writer.h"
[email protected]6faa0e0d2009-04-28 06:50:366
[email protected]e33c9512014-05-12 02:24:137#include "base/bind.h"
[email protected]6faa0e0d2009-04-28 06:50:368#include "base/compiler_specific.h"
[email protected]57999812013-02-24 05:40:529#include "base/files/file_path.h"
[email protected]e3177dd52014-08-13 20:22:1410#include "base/files/file_util.h"
[email protected]ea1a3f62012-11-16 20:34:2311#include "base/files/scoped_temp_dir.h"
skyostil054861d2015-04-30 19:06:1512#include "base/location.h"
[email protected]6faa0e0d2009-04-28 06:50:3613#include "base/logging.h"
avi543540e2015-12-24 05:15:3214#include "base/macros.h"
dcheng093de9b2016-04-04 21:25:5115#include "base/memory/ptr_util.h"
[email protected]7ff48ca2013-02-06 16:56:1916#include "base/run_loop.h"
skyostil054861d2015-04-30 19:06:1517#include "base/single_thread_task_runner.h"
[email protected]34b99632011-01-01 01:01:0618#include "base/threading/thread.h"
gab6cce2f32016-05-11 19:53:4319#include "base/threading/thread_task_runner_handle.h"
[email protected]99084f62013-06-28 00:49:0720#include "base/time/time.h"
[email protected]6faa0e0d2009-04-28 06:50:3621#include "testing/gtest/include/gtest/gtest.h"
22
[email protected]43486252012-10-24 16:33:3623namespace base {
24
[email protected]6faa0e0d2009-04-28 06:50:3625namespace {
26
27std::string GetFileContent(const FilePath& path) {
28 std::string content;
[email protected]82f84b92013-08-30 18:23:5029 if (!ReadFileToString(path, &content)) {
[email protected]6faa0e0d2009-04-28 06:50:3630 NOTREACHED();
31 }
32 return content;
33}
34
[email protected]6c1164042009-05-08 14:41:0835class DataSerializer : public ImportantFileWriter::DataSerializer {
36 public:
37 explicit DataSerializer(const std::string& data) : data_(data) {
38 }
39
dcheng56488182014-10-21 10:54:5140 bool SerializeData(std::string* output) override {
[email protected]6c1164042009-05-08 14:41:0841 output->assign(data_);
42 return true;
43 }
44
45 private:
46 const std::string data_;
47};
48
Sam McNally8f50faa2017-05-19 05:08:0049class FailingDataSerializer : public ImportantFileWriter::DataSerializer {
50 public:
51 bool SerializeData(std::string* output) override { return false; }
52};
53
probergefc46ac12016-09-21 18:03:0054enum WriteCallbackObservationState {
55 NOT_CALLED,
56 CALLED_WITH_ERROR,
57 CALLED_WITH_SUCCESS,
[email protected]e33c9512014-05-12 02:24:1358};
59
probergec503d692016-09-28 19:51:0560class WriteCallbacksObserver {
probergefc46ac12016-09-21 18:03:0061 public:
probergec503d692016-09-28 19:51:0562 WriteCallbacksObserver() = default;
probergefc46ac12016-09-21 18:03:0063
probergec503d692016-09-28 19:51:0564 // Register OnBeforeWrite() and OnAfterWrite() to be called on the next write
65 // of |writer|.
66 void ObserveNextWriteCallbacks(ImportantFileWriter* writer);
probergefc46ac12016-09-21 18:03:0067
probergec503d692016-09-28 19:51:0568 // Returns the |WriteCallbackObservationState| which was observed, then resets
69 // it to |NOT_CALLED|.
probergefc46ac12016-09-21 18:03:0070 WriteCallbackObservationState GetAndResetObservationState();
71
72 private:
probergec503d692016-09-28 19:51:0573 void OnBeforeWrite() {
74 EXPECT_FALSE(before_write_called_);
75 before_write_called_ = true;
probergefc46ac12016-09-21 18:03:0076 }
77
probergec503d692016-09-28 19:51:0578 void OnAfterWrite(bool success) {
79 EXPECT_EQ(NOT_CALLED, after_write_observation_state_);
80 after_write_observation_state_ =
81 success ? CALLED_WITH_SUCCESS : CALLED_WITH_ERROR;
82 }
probergefc46ac12016-09-21 18:03:0083
probergec503d692016-09-28 19:51:0584 bool before_write_called_ = false;
85 WriteCallbackObservationState after_write_observation_state_ = NOT_CALLED;
86
87 DISALLOW_COPY_AND_ASSIGN(WriteCallbacksObserver);
probergefc46ac12016-09-21 18:03:0088};
89
probergec503d692016-09-28 19:51:0590void WriteCallbacksObserver::ObserveNextWriteCallbacks(
[email protected]e33c9512014-05-12 02:24:1391 ImportantFileWriter* writer) {
probergec503d692016-09-28 19:51:0592 writer->RegisterOnNextWriteCallbacks(
93 base::Bind(&WriteCallbacksObserver::OnBeforeWrite,
94 base::Unretained(this)),
95 base::Bind(&WriteCallbacksObserver::OnAfterWrite,
96 base::Unretained(this)));
[email protected]e33c9512014-05-12 02:24:1397}
98
probergefc46ac12016-09-21 18:03:0099WriteCallbackObservationState
probergec503d692016-09-28 19:51:05100WriteCallbacksObserver::GetAndResetObservationState() {
101 EXPECT_EQ(after_write_observation_state_ != NOT_CALLED, before_write_called_)
102 << "The before-write callback should always be called before the "
103 "after-write callback";
104
105 WriteCallbackObservationState state = after_write_observation_state_;
106 before_write_called_ = false;
107 after_write_observation_state_ = NOT_CALLED;
probergefc46ac12016-09-21 18:03:00108 return state;
[email protected]e33c9512014-05-12 02:24:13109}
110
[email protected]6faa0e0d2009-04-28 06:50:36111} // namespace
112
113class ImportantFileWriterTest : public testing::Test {
114 public:
[email protected]6658ca82010-05-20 18:20:29115 ImportantFileWriterTest() { }
dcheng8aef37612014-12-23 02:56:47116 void SetUp() override {
[email protected]6faa0e0d2009-04-28 06:50:36117 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
vabr411f4fc2016-09-08 09:26:27118 file_ = temp_dir_.GetPath().AppendASCII("test-file");
[email protected]6faa0e0d2009-04-28 06:50:36119 }
120
121 protected:
probergec503d692016-09-28 19:51:05122 WriteCallbacksObserver write_callback_observer_;
[email protected]6faa0e0d2009-04-28 06:50:36123 FilePath file_;
[email protected]6fad2632009-11-02 05:59:37124 MessageLoop loop_;
[email protected]6faa0e0d2009-04-28 06:50:36125
126 private:
[email protected]6faa0e0d2009-04-28 06:50:36127 ScopedTempDir temp_dir_;
128};
129
[email protected]6fad2632009-11-02 05:59:37130TEST_F(ImportantFileWriterTest, Basic) {
skyostil054861d2015-04-30 19:06:15131 ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
[email protected]7567484142013-07-11 17:36:07132 EXPECT_FALSE(PathExists(writer.path()));
probergefc46ac12016-09-21 18:03:00133 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
riceaec7c3997e2016-09-13 04:10:11134 writer.WriteNow(MakeUnique<std::string>("foo"));
[email protected]7ff48ca2013-02-06 16:56:19135 RunLoop().RunUntilIdle();
[email protected]6faa0e0d2009-04-28 06:50:36136
probergefc46ac12016-09-21 18:03:00137 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
[email protected]7567484142013-07-11 17:36:07138 ASSERT_TRUE(PathExists(writer.path()));
[email protected]6faa0e0d2009-04-28 06:50:36139 EXPECT_EQ("foo", GetFileContent(writer.path()));
140}
141
probergefc46ac12016-09-21 18:03:00142TEST_F(ImportantFileWriterTest, WriteWithObserver) {
skyostil054861d2015-04-30 19:06:15143 ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
[email protected]e33c9512014-05-12 02:24:13144 EXPECT_FALSE(PathExists(writer.path()));
probergefc46ac12016-09-21 18:03:00145 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
146
147 // Confirm that the observer is invoked.
probergec503d692016-09-28 19:51:05148 write_callback_observer_.ObserveNextWriteCallbacks(&writer);
riceaec7c3997e2016-09-13 04:10:11149 writer.WriteNow(MakeUnique<std::string>("foo"));
[email protected]e33c9512014-05-12 02:24:13150 RunLoop().RunUntilIdle();
151
probergefc46ac12016-09-21 18:03:00152 EXPECT_EQ(CALLED_WITH_SUCCESS,
153 write_callback_observer_.GetAndResetObservationState());
[email protected]e33c9512014-05-12 02:24:13154 ASSERT_TRUE(PathExists(writer.path()));
155 EXPECT_EQ("foo", GetFileContent(writer.path()));
156
157 // Confirm that re-installing the observer works for another write.
probergefc46ac12016-09-21 18:03:00158 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:05159 write_callback_observer_.ObserveNextWriteCallbacks(&writer);
riceaec7c3997e2016-09-13 04:10:11160 writer.WriteNow(MakeUnique<std::string>("bar"));
[email protected]e33c9512014-05-12 02:24:13161 RunLoop().RunUntilIdle();
162
probergefc46ac12016-09-21 18:03:00163 EXPECT_EQ(CALLED_WITH_SUCCESS,
164 write_callback_observer_.GetAndResetObservationState());
[email protected]e33c9512014-05-12 02:24:13165 ASSERT_TRUE(PathExists(writer.path()));
166 EXPECT_EQ("bar", GetFileContent(writer.path()));
167
168 // Confirm that writing again without re-installing the observer doesn't
169 // result in a notification.
probergefc46ac12016-09-21 18:03:00170 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
riceaec7c3997e2016-09-13 04:10:11171 writer.WriteNow(MakeUnique<std::string>("baz"));
[email protected]e33c9512014-05-12 02:24:13172 RunLoop().RunUntilIdle();
173
probergefc46ac12016-09-21 18:03:00174 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
[email protected]e33c9512014-05-12 02:24:13175 ASSERT_TRUE(PathExists(writer.path()));
176 EXPECT_EQ("baz", GetFileContent(writer.path()));
177}
178
probergefc46ac12016-09-21 18:03:00179TEST_F(ImportantFileWriterTest, FailedWriteWithObserver) {
180 // Use an invalid file path (relative paths are invalid) to get a
181 // FILE_ERROR_ACCESS_DENIED error when trying to write the file.
182 ImportantFileWriter writer(FilePath().AppendASCII("bad/../path"),
183 ThreadTaskRunnerHandle::Get());
184 EXPECT_FALSE(PathExists(writer.path()));
185 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
probergec503d692016-09-28 19:51:05186 write_callback_observer_.ObserveNextWriteCallbacks(&writer);
probergefc46ac12016-09-21 18:03:00187 writer.WriteNow(MakeUnique<std::string>("foo"));
188 RunLoop().RunUntilIdle();
189
190 // Confirm that the write observer was invoked with its boolean parameter set
191 // to false.
192 EXPECT_EQ(CALLED_WITH_ERROR,
193 write_callback_observer_.GetAndResetObservationState());
194 EXPECT_FALSE(PathExists(writer.path()));
195}
196
197TEST_F(ImportantFileWriterTest, CallbackRunsOnWriterThread) {
198 base::Thread file_writer_thread("ImportantFileWriter test thread");
199 file_writer_thread.Start();
200 ImportantFileWriter writer(file_, file_writer_thread.task_runner());
201 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
202
probergec503d692016-09-28 19:51:05203 // Block execution on |file_writer_thread| to verify that callbacks are
204 // executed on it.
205 base::WaitableEvent wait_helper(
206 base::WaitableEvent::ResetPolicy::MANUAL,
207 base::WaitableEvent::InitialState::NOT_SIGNALED);
208 file_writer_thread.task_runner()->PostTask(
tzik92b7a422017-04-11 15:00:44209 FROM_HERE, base::BindOnce(&base::WaitableEvent::Wait,
210 base::Unretained(&wait_helper)));
probergec503d692016-09-28 19:51:05211
212 write_callback_observer_.ObserveNextWriteCallbacks(&writer);
probergefc46ac12016-09-21 18:03:00213 writer.WriteNow(MakeUnique<std::string>("foo"));
214 RunLoop().RunUntilIdle();
215
probergec503d692016-09-28 19:51:05216 // Expect the callback to not have been executed before the
217 // |file_writer_thread| is unblocked.
probergefc46ac12016-09-21 18:03:00218 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
219
probergec503d692016-09-28 19:51:05220 wait_helper.Signal();
probergefc46ac12016-09-21 18:03:00221 file_writer_thread.FlushForTesting();
probergec503d692016-09-28 19:51:05222
probergefc46ac12016-09-21 18:03:00223 EXPECT_EQ(CALLED_WITH_SUCCESS,
224 write_callback_observer_.GetAndResetObservationState());
225 ASSERT_TRUE(PathExists(writer.path()));
226 EXPECT_EQ("foo", GetFileContent(writer.path()));
227}
228
[email protected]6faa0e0d2009-04-28 06:50:36229TEST_F(ImportantFileWriterTest, ScheduleWrite) {
Sam McNally8f50faa2017-05-19 05:08:00230 ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get(),
231 TimeDelta::FromMilliseconds(0));
[email protected]6c1164042009-05-08 14:41:08232 EXPECT_FALSE(writer.HasPendingWrite());
233 DataSerializer serializer("foo");
234 writer.ScheduleWrite(&serializer);
235 EXPECT_TRUE(writer.HasPendingWrite());
Sam McNally8f50faa2017-05-19 05:08:00236 RunLoop().RunUntilIdle();
[email protected]6c1164042009-05-08 14:41:08237 EXPECT_FALSE(writer.HasPendingWrite());
[email protected]7567484142013-07-11 17:36:07238 ASSERT_TRUE(PathExists(writer.path()));
[email protected]6c1164042009-05-08 14:41:08239 EXPECT_EQ("foo", GetFileContent(writer.path()));
240}
241
242TEST_F(ImportantFileWriterTest, DoScheduledWrite) {
skyostil054861d2015-04-30 19:06:15243 ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
[email protected]6c1164042009-05-08 14:41:08244 EXPECT_FALSE(writer.HasPendingWrite());
245 DataSerializer serializer("foo");
246 writer.ScheduleWrite(&serializer);
247 EXPECT_TRUE(writer.HasPendingWrite());
248 writer.DoScheduledWrite();
Sam McNally8f50faa2017-05-19 05:08:00249 RunLoop().RunUntilIdle();
[email protected]6c1164042009-05-08 14:41:08250 EXPECT_FALSE(writer.HasPendingWrite());
[email protected]7567484142013-07-11 17:36:07251 ASSERT_TRUE(PathExists(writer.path()));
[email protected]6faa0e0d2009-04-28 06:50:36252 EXPECT_EQ("foo", GetFileContent(writer.path()));
253}
254
[email protected]b9a8ee4d2012-11-08 04:29:12255TEST_F(ImportantFileWriterTest, BatchingWrites) {
Sam McNally8f50faa2017-05-19 05:08:00256 ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get(),
257 TimeDelta::FromMilliseconds(0));
[email protected]6c1164042009-05-08 14:41:08258 DataSerializer foo("foo"), bar("bar"), baz("baz");
259 writer.ScheduleWrite(&foo);
260 writer.ScheduleWrite(&bar);
261 writer.ScheduleWrite(&baz);
Sam McNally8f50faa2017-05-19 05:08:00262 RunLoop().RunUntilIdle();
[email protected]7567484142013-07-11 17:36:07263 ASSERT_TRUE(PathExists(writer.path()));
[email protected]6faa0e0d2009-04-28 06:50:36264 EXPECT_EQ("baz", GetFileContent(writer.path()));
265}
[email protected]43486252012-10-24 16:33:36266
Sam McNally8f50faa2017-05-19 05:08:00267TEST_F(ImportantFileWriterTest, ScheduleWrite_FailToSerialize) {
268 ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get(),
269 TimeDelta::FromMilliseconds(0));
270 EXPECT_FALSE(writer.HasPendingWrite());
271 FailingDataSerializer serializer;
272 writer.ScheduleWrite(&serializer);
273 EXPECT_TRUE(writer.HasPendingWrite());
274 RunLoop().RunUntilIdle();
275 EXPECT_FALSE(writer.HasPendingWrite());
276 EXPECT_FALSE(PathExists(writer.path()));
277}
278
279TEST_F(ImportantFileWriterTest, ScheduleWrite_WriteNow) {
280 ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get(),
281 TimeDelta::FromMilliseconds(0));
282 EXPECT_FALSE(writer.HasPendingWrite());
283 DataSerializer serializer("foo");
284 writer.ScheduleWrite(&serializer);
285 EXPECT_TRUE(writer.HasPendingWrite());
286 writer.WriteNow(MakeUnique<std::string>("bar"));
287 EXPECT_FALSE(writer.HasPendingWrite());
288
289 RunLoop().RunUntilIdle();
290 EXPECT_FALSE(writer.HasPendingWrite());
291 ASSERT_TRUE(PathExists(writer.path()));
292 EXPECT_EQ("bar", GetFileContent(writer.path()));
293}
294
295TEST_F(ImportantFileWriterTest, DoScheduledWrite_FailToSerialize) {
296 ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get(),
297 TimeDelta::FromMilliseconds(0));
298 EXPECT_FALSE(writer.HasPendingWrite());
299 FailingDataSerializer serializer;
300 writer.ScheduleWrite(&serializer);
301 EXPECT_TRUE(writer.HasPendingWrite());
302
303 writer.DoScheduledWrite();
304 EXPECT_FALSE(writer.HasPendingWrite());
305 EXPECT_FALSE(PathExists(writer.path()));
306
307 RunLoop().RunUntilIdle();
308 EXPECT_FALSE(writer.HasPendingWrite());
309 EXPECT_FALSE(PathExists(writer.path()));
310}
311
[email protected]43486252012-10-24 16:33:36312} // namespace base