blob: c55f0cc037f2e8ade017cbdd4d089b3a03517135 [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"
[email protected]6faa0e0d2009-04-28 06:50:3612#include "base/logging.h"
[email protected]495cad92013-07-18 08:12:4013#include "base/message_loop/message_loop.h"
[email protected]7ff48ca2013-02-06 16:56:1914#include "base/run_loop.h"
[email protected]34b99632011-01-01 01:01:0615#include "base/threading/thread.h"
[email protected]99084f62013-06-28 00:49:0716#include "base/time/time.h"
[email protected]6faa0e0d2009-04-28 06:50:3617#include "testing/gtest/include/gtest/gtest.h"
18
[email protected]43486252012-10-24 16:33:3619namespace base {
20
[email protected]6faa0e0d2009-04-28 06:50:3621namespace {
22
23std::string GetFileContent(const FilePath& path) {
24 std::string content;
[email protected]82f84b92013-08-30 18:23:5025 if (!ReadFileToString(path, &content)) {
[email protected]6faa0e0d2009-04-28 06:50:3626 NOTREACHED();
27 }
28 return content;
29}
30
[email protected]6c1164042009-05-08 14:41:0831class DataSerializer : public ImportantFileWriter::DataSerializer {
32 public:
33 explicit DataSerializer(const std::string& data) : data_(data) {
34 }
35
[email protected]d5b69d92013-02-07 07:20:5536 virtual bool SerializeData(std::string* output) OVERRIDE {
[email protected]6c1164042009-05-08 14:41:0837 output->assign(data_);
38 return true;
39 }
40
41 private:
42 const std::string data_;
43};
44
[email protected]e33c9512014-05-12 02:24:1345class SuccessfulWriteObserver {
46 public:
47 SuccessfulWriteObserver() : successful_write_observed_(false) {}
48
49 // Register on_successful_write() to be called on the next successful write
50 // of |writer|.
51 void ObserveNextSuccessfulWrite(ImportantFileWriter* writer);
52
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();
56
57 private:
58 void on_successful_write() {
59 EXPECT_FALSE(successful_write_observed_);
60 successful_write_observed_ = true;
61 }
62
63 bool successful_write_observed_;
64
65 DISALLOW_COPY_AND_ASSIGN(SuccessfulWriteObserver);
66};
67
68void SuccessfulWriteObserver::ObserveNextSuccessfulWrite(
69 ImportantFileWriter* writer) {
70 writer->RegisterOnNextSuccessfulWriteCallback(base::Bind(
71 &SuccessfulWriteObserver::on_successful_write, base::Unretained(this)));
72}
73
74bool SuccessfulWriteObserver::GetAndResetObservationState() {
75 bool was_successful_write_observed = successful_write_observed_;
76 successful_write_observed_ = false;
77 return was_successful_write_observed;
78}
79
[email protected]6faa0e0d2009-04-28 06:50:3680} // namespace
81
82class ImportantFileWriterTest : public testing::Test {
83 public:
[email protected]6658ca82010-05-20 18:20:2984 ImportantFileWriterTest() { }
[email protected]6faa0e0d2009-04-28 06:50:3685 virtual void SetUp() {
86 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
87 file_ = temp_dir_.path().AppendASCII("test-file");
88 }
89
90 protected:
[email protected]e33c9512014-05-12 02:24:1391 SuccessfulWriteObserver successful_write_observer_;
[email protected]6faa0e0d2009-04-28 06:50:3692 FilePath file_;
[email protected]6fad2632009-11-02 05:59:3793 MessageLoop loop_;
[email protected]6faa0e0d2009-04-28 06:50:3694
95 private:
[email protected]6faa0e0d2009-04-28 06:50:3696 ScopedTempDir temp_dir_;
97};
98
[email protected]6fad2632009-11-02 05:59:3799TEST_F(ImportantFileWriterTest, Basic) {
[email protected]cadac622013-06-11 16:46:36100 ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
[email protected]7567484142013-07-11 17:36:07101 EXPECT_FALSE(PathExists(writer.path()));
[email protected]e33c9512014-05-12 02:24:13102 EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
[email protected]6faa0e0d2009-04-28 06:50:36103 writer.WriteNow("foo");
[email protected]7ff48ca2013-02-06 16:56:19104 RunLoop().RunUntilIdle();
[email protected]6faa0e0d2009-04-28 06:50:36105
[email protected]e33c9512014-05-12 02:24:13106 EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
[email protected]7567484142013-07-11 17:36:07107 ASSERT_TRUE(PathExists(writer.path()));
[email protected]6faa0e0d2009-04-28 06:50:36108 EXPECT_EQ("foo", GetFileContent(writer.path()));
109}
110
[email protected]e33c9512014-05-12 02:24:13111TEST_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();
118
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()));
123
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();
129
130 EXPECT_TRUE(successful_write_observer_.GetAndResetObservationState());
131 ASSERT_TRUE(PathExists(writer.path()));
132 EXPECT_EQ("bar", GetFileContent(writer.path()));
133
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();
139
140 EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
141 ASSERT_TRUE(PathExists(writer.path()));
142 EXPECT_EQ("baz", GetFileContent(writer.path()));
143}
144
[email protected]6faa0e0d2009-04-28 06:50:36145TEST_F(ImportantFileWriterTest, ScheduleWrite) {
[email protected]cadac622013-06-11 16:46:36146 ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
[email protected]43486252012-10-24 16:33:36147 writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
[email protected]6c1164042009-05-08 14:41:08148 EXPECT_FALSE(writer.HasPendingWrite());
149 DataSerializer serializer("foo");
150 writer.ScheduleWrite(&serializer);
151 EXPECT_TRUE(writer.HasPendingWrite());
[email protected]02798a982012-01-27 00:45:33152 MessageLoop::current()->PostDelayedTask(
153 FROM_HERE,
[email protected]a085953f2013-02-04 23:40:00154 MessageLoop::QuitWhenIdleClosure(),
[email protected]43486252012-10-24 16:33:36155 TimeDelta::FromMilliseconds(100));
[email protected]6faa0e0d2009-04-28 06:50:36156 MessageLoop::current()->Run();
[email protected]6c1164042009-05-08 14:41:08157 EXPECT_FALSE(writer.HasPendingWrite());
[email protected]7567484142013-07-11 17:36:07158 ASSERT_TRUE(PathExists(writer.path()));
[email protected]6c1164042009-05-08 14:41:08159 EXPECT_EQ("foo", GetFileContent(writer.path()));
160}
161
162TEST_F(ImportantFileWriterTest, DoScheduledWrite) {
[email protected]cadac622013-06-11 16:46:36163 ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
[email protected]6c1164042009-05-08 14:41:08164 EXPECT_FALSE(writer.HasPendingWrite());
165 DataSerializer serializer("foo");
166 writer.ScheduleWrite(&serializer);
167 EXPECT_TRUE(writer.HasPendingWrite());
168 writer.DoScheduledWrite();
[email protected]02798a982012-01-27 00:45:33169 MessageLoop::current()->PostDelayedTask(
170 FROM_HERE,
[email protected]a085953f2013-02-04 23:40:00171 MessageLoop::QuitWhenIdleClosure(),
[email protected]43486252012-10-24 16:33:36172 TimeDelta::FromMilliseconds(100));
[email protected]6fad2632009-11-02 05:59:37173 MessageLoop::current()->Run();
[email protected]6c1164042009-05-08 14:41:08174 EXPECT_FALSE(writer.HasPendingWrite());
[email protected]7567484142013-07-11 17:36:07175 ASSERT_TRUE(PathExists(writer.path()));
[email protected]6faa0e0d2009-04-28 06:50:36176 EXPECT_EQ("foo", GetFileContent(writer.path()));
177}
178
[email protected]b9a8ee4d2012-11-08 04:29:12179TEST_F(ImportantFileWriterTest, BatchingWrites) {
[email protected]cadac622013-06-11 16:46:36180 ImportantFileWriter writer(file_, MessageLoopProxy::current().get());
[email protected]43486252012-10-24 16:33:36181 writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
[email protected]6c1164042009-05-08 14:41:08182 DataSerializer foo("foo"), bar("bar"), baz("baz");
183 writer.ScheduleWrite(&foo);
184 writer.ScheduleWrite(&bar);
185 writer.ScheduleWrite(&baz);
[email protected]02798a982012-01-27 00:45:33186 MessageLoop::current()->PostDelayedTask(
187 FROM_HERE,
[email protected]a085953f2013-02-04 23:40:00188 MessageLoop::QuitWhenIdleClosure(),
[email protected]43486252012-10-24 16:33:36189 TimeDelta::FromMilliseconds(100));
[email protected]6faa0e0d2009-04-28 06:50:36190 MessageLoop::current()->Run();
[email protected]7567484142013-07-11 17:36:07191 ASSERT_TRUE(PathExists(writer.path()));
[email protected]6faa0e0d2009-04-28 06:50:36192 EXPECT_EQ("baz", GetFileContent(writer.path()));
193}
[email protected]43486252012-10-24 16:33:36194
195} // namespace base