important_file_writer_unittest.cc revision 0c4f26a46430b8c503c65f5cae1d2b6876d53e30
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
23namespace base {
24
25namespace {
26
27std::string GetFileContent(const FilePath& path) {
28  std::string content;
29  if (!ReadFileToString(path, &content)) {
30    NOTREACHED();
31  }
32  return content;
33}
34
35class DataSerializer : public ImportantFileWriter::DataSerializer {
36 public:
37  explicit DataSerializer(const std::string& data) : data_(data) {
38  }
39
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
49class SuccessfulWriteObserver {
50 public:
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:
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
72void SuccessfulWriteObserver::ObserveNextSuccessfulWrite(
73    ImportantFileWriter* writer) {
74  writer->RegisterOnNextSuccessfulWriteCallback(base::Bind(
75      &SuccessfulWriteObserver::on_successful_write, base::Unretained(this)));
76}
77
78bool 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
86class ImportantFileWriterTest : public testing::Test {
87 public:
88  ImportantFileWriterTest() { }
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
103TEST_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
115TEST_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
149TEST_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
166TEST_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
182TEST_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