Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(163)

Side by Side Diff: base/files/important_file_writer_unittest.cc

Issue 2372663003: Allow ImportantFileWriter to take in a pre-write callback. (Closed)
Patch Set: Add a WaitableEvent to fix a race condition in CallbackRunsOnWriterThread Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/files/important_file_writer.cc ('k') | components/prefs/json_pref_store.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/files/important_file_writer.h" 5 #include "base/files/important_file_writer.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/compiler_specific.h" 8 #include "base/compiler_specific.h"
9 #include "base/files/file_path.h" 9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h" 10 #include "base/files/file_util.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 private: 45 private:
46 const std::string data_; 46 const std::string data_;
47 }; 47 };
48 48
49 enum WriteCallbackObservationState { 49 enum WriteCallbackObservationState {
50 NOT_CALLED, 50 NOT_CALLED,
51 CALLED_WITH_ERROR, 51 CALLED_WITH_ERROR,
52 CALLED_WITH_SUCCESS, 52 CALLED_WITH_SUCCESS,
53 }; 53 };
54 54
55 class WriteCallbackObserver { 55 class WriteCallbacksObserver {
56 public: 56 public:
57 WriteCallbackObserver() : observation_state_(NOT_CALLED) {} 57 WriteCallbacksObserver() = default;
58 58
59 // Register OnWrite() to be called on the next write of |writer|. 59 // Register OnBeforeWrite() and OnAfterWrite() to be called on the next write
60 void ObserveNextWriteCallback(ImportantFileWriter* writer); 60 // of |writer|.
61 void ObserveNextWriteCallbacks(ImportantFileWriter* writer);
61 62
62 // Returns true if a write was observed via OnWrite() 63 // Returns the |WriteCallbackObservationState| which was observed, then resets
63 // and resets the observation state to false regardless. 64 // it to |NOT_CALLED|.
64 WriteCallbackObservationState GetAndResetObservationState(); 65 WriteCallbackObservationState GetAndResetObservationState();
65 66
66 private: 67 private:
67 void OnWrite(bool success) { 68 void OnBeforeWrite() {
68 EXPECT_EQ(NOT_CALLED, observation_state_); 69 EXPECT_FALSE(before_write_called_);
69 observation_state_ = success ? CALLED_WITH_SUCCESS : CALLED_WITH_ERROR; 70 before_write_called_ = true;
70 } 71 }
71 72
72 WriteCallbackObservationState observation_state_; 73 void OnAfterWrite(bool success) {
74 EXPECT_EQ(NOT_CALLED, after_write_observation_state_);
75 after_write_observation_state_ =
76 success ? CALLED_WITH_SUCCESS : CALLED_WITH_ERROR;
77 }
73 78
74 DISALLOW_COPY_AND_ASSIGN(WriteCallbackObserver); 79 bool before_write_called_ = false;
80 WriteCallbackObservationState after_write_observation_state_ = NOT_CALLED;
81
82 DISALLOW_COPY_AND_ASSIGN(WriteCallbacksObserver);
75 }; 83 };
76 84
77 void WriteCallbackObserver::ObserveNextWriteCallback( 85 void WriteCallbacksObserver::ObserveNextWriteCallbacks(
78 ImportantFileWriter* writer) { 86 ImportantFileWriter* writer) {
79 writer->RegisterOnNextWriteCallback( 87 writer->RegisterOnNextWriteCallbacks(
80 base::Bind(&WriteCallbackObserver::OnWrite, base::Unretained(this))); 88 base::Bind(&WriteCallbacksObserver::OnBeforeWrite,
89 base::Unretained(this)),
90 base::Bind(&WriteCallbacksObserver::OnAfterWrite,
91 base::Unretained(this)));
81 } 92 }
82 93
83 WriteCallbackObservationState 94 WriteCallbackObservationState
84 WriteCallbackObserver::GetAndResetObservationState() { 95 WriteCallbacksObserver::GetAndResetObservationState() {
85 WriteCallbackObservationState state = observation_state_; 96 EXPECT_EQ(after_write_observation_state_ != NOT_CALLED, before_write_called_)
86 observation_state_ = NOT_CALLED; 97 << "The before-write callback should always be called before the "
98 "after-write callback";
99
100 WriteCallbackObservationState state = after_write_observation_state_;
101 before_write_called_ = false;
102 after_write_observation_state_ = NOT_CALLED;
87 return state; 103 return state;
88 } 104 }
89 105
90 } // namespace 106 } // namespace
91 107
92 class ImportantFileWriterTest : public testing::Test { 108 class ImportantFileWriterTest : public testing::Test {
93 public: 109 public:
94 ImportantFileWriterTest() { } 110 ImportantFileWriterTest() { }
95 void SetUp() override { 111 void SetUp() override {
96 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 112 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
97 file_ = temp_dir_.GetPath().AppendASCII("test-file"); 113 file_ = temp_dir_.GetPath().AppendASCII("test-file");
98 } 114 }
99 115
100 protected: 116 protected:
101 WriteCallbackObserver write_callback_observer_; 117 WriteCallbacksObserver write_callback_observer_;
102 FilePath file_; 118 FilePath file_;
103 MessageLoop loop_; 119 MessageLoop loop_;
104 120
105 private: 121 private:
106 ScopedTempDir temp_dir_; 122 ScopedTempDir temp_dir_;
107 }; 123 };
108 124
109 TEST_F(ImportantFileWriterTest, Basic) { 125 TEST_F(ImportantFileWriterTest, Basic) {
110 ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get()); 126 ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
111 EXPECT_FALSE(PathExists(writer.path())); 127 EXPECT_FALSE(PathExists(writer.path()));
112 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); 128 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
113 writer.WriteNow(MakeUnique<std::string>("foo")); 129 writer.WriteNow(MakeUnique<std::string>("foo"));
114 RunLoop().RunUntilIdle(); 130 RunLoop().RunUntilIdle();
115 131
116 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); 132 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
117 ASSERT_TRUE(PathExists(writer.path())); 133 ASSERT_TRUE(PathExists(writer.path()));
118 EXPECT_EQ("foo", GetFileContent(writer.path())); 134 EXPECT_EQ("foo", GetFileContent(writer.path()));
119 } 135 }
120 136
121 TEST_F(ImportantFileWriterTest, WriteWithObserver) { 137 TEST_F(ImportantFileWriterTest, WriteWithObserver) {
122 ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get()); 138 ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
123 EXPECT_FALSE(PathExists(writer.path())); 139 EXPECT_FALSE(PathExists(writer.path()));
124 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); 140 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
125 141
126 // Confirm that the observer is invoked. 142 // Confirm that the observer is invoked.
127 write_callback_observer_.ObserveNextWriteCallback(&writer); 143 write_callback_observer_.ObserveNextWriteCallbacks(&writer);
128 writer.WriteNow(MakeUnique<std::string>("foo")); 144 writer.WriteNow(MakeUnique<std::string>("foo"));
129 RunLoop().RunUntilIdle(); 145 RunLoop().RunUntilIdle();
130 146
131 EXPECT_EQ(CALLED_WITH_SUCCESS, 147 EXPECT_EQ(CALLED_WITH_SUCCESS,
132 write_callback_observer_.GetAndResetObservationState()); 148 write_callback_observer_.GetAndResetObservationState());
133 ASSERT_TRUE(PathExists(writer.path())); 149 ASSERT_TRUE(PathExists(writer.path()));
134 EXPECT_EQ("foo", GetFileContent(writer.path())); 150 EXPECT_EQ("foo", GetFileContent(writer.path()));
135 151
136 // Confirm that re-installing the observer works for another write. 152 // Confirm that re-installing the observer works for another write.
137 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); 153 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
138 write_callback_observer_.ObserveNextWriteCallback(&writer); 154 write_callback_observer_.ObserveNextWriteCallbacks(&writer);
139 writer.WriteNow(MakeUnique<std::string>("bar")); 155 writer.WriteNow(MakeUnique<std::string>("bar"));
140 RunLoop().RunUntilIdle(); 156 RunLoop().RunUntilIdle();
141 157
142 EXPECT_EQ(CALLED_WITH_SUCCESS, 158 EXPECT_EQ(CALLED_WITH_SUCCESS,
143 write_callback_observer_.GetAndResetObservationState()); 159 write_callback_observer_.GetAndResetObservationState());
144 ASSERT_TRUE(PathExists(writer.path())); 160 ASSERT_TRUE(PathExists(writer.path()));
145 EXPECT_EQ("bar", GetFileContent(writer.path())); 161 EXPECT_EQ("bar", GetFileContent(writer.path()));
146 162
147 // Confirm that writing again without re-installing the observer doesn't 163 // Confirm that writing again without re-installing the observer doesn't
148 // result in a notification. 164 // result in a notification.
149 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); 165 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
150 writer.WriteNow(MakeUnique<std::string>("baz")); 166 writer.WriteNow(MakeUnique<std::string>("baz"));
151 RunLoop().RunUntilIdle(); 167 RunLoop().RunUntilIdle();
152 168
153 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); 169 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
154 ASSERT_TRUE(PathExists(writer.path())); 170 ASSERT_TRUE(PathExists(writer.path()));
155 EXPECT_EQ("baz", GetFileContent(writer.path())); 171 EXPECT_EQ("baz", GetFileContent(writer.path()));
156 } 172 }
157 173
158 TEST_F(ImportantFileWriterTest, FailedWriteWithObserver) { 174 TEST_F(ImportantFileWriterTest, FailedWriteWithObserver) {
159 // Use an invalid file path (relative paths are invalid) to get a 175 // Use an invalid file path (relative paths are invalid) to get a
160 // FILE_ERROR_ACCESS_DENIED error when trying to write the file. 176 // FILE_ERROR_ACCESS_DENIED error when trying to write the file.
161 ImportantFileWriter writer(FilePath().AppendASCII("bad/../path"), 177 ImportantFileWriter writer(FilePath().AppendASCII("bad/../path"),
162 ThreadTaskRunnerHandle::Get()); 178 ThreadTaskRunnerHandle::Get());
163 EXPECT_FALSE(PathExists(writer.path())); 179 EXPECT_FALSE(PathExists(writer.path()));
164 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); 180 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
165 write_callback_observer_.ObserveNextWriteCallback(&writer); 181 write_callback_observer_.ObserveNextWriteCallbacks(&writer);
166 writer.WriteNow(MakeUnique<std::string>("foo")); 182 writer.WriteNow(MakeUnique<std::string>("foo"));
167 RunLoop().RunUntilIdle(); 183 RunLoop().RunUntilIdle();
168 184
169 // Confirm that the write observer was invoked with its boolean parameter set 185 // Confirm that the write observer was invoked with its boolean parameter set
170 // to false. 186 // to false.
171 EXPECT_EQ(CALLED_WITH_ERROR, 187 EXPECT_EQ(CALLED_WITH_ERROR,
172 write_callback_observer_.GetAndResetObservationState()); 188 write_callback_observer_.GetAndResetObservationState());
173 EXPECT_FALSE(PathExists(writer.path())); 189 EXPECT_FALSE(PathExists(writer.path()));
174 } 190 }
175 191
176 TEST_F(ImportantFileWriterTest, CallbackRunsOnWriterThread) { 192 TEST_F(ImportantFileWriterTest, CallbackRunsOnWriterThread) {
177 base::Thread file_writer_thread("ImportantFileWriter test thread"); 193 base::Thread file_writer_thread("ImportantFileWriter test thread");
178 file_writer_thread.Start(); 194 file_writer_thread.Start();
179 ImportantFileWriter writer(file_, file_writer_thread.task_runner()); 195 ImportantFileWriter writer(file_, file_writer_thread.task_runner());
180 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); 196 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
181 197
182 write_callback_observer_.ObserveNextWriteCallback(&writer); 198 // Block execution on |file_writer_thread| to verify that callbacks are
199 // executed on it.
200 base::WaitableEvent wait_helper(
201 base::WaitableEvent::ResetPolicy::MANUAL,
202 base::WaitableEvent::InitialState::NOT_SIGNALED);
203 file_writer_thread.task_runner()->PostTask(
204 FROM_HERE,
205 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&wait_helper)));
206
207 write_callback_observer_.ObserveNextWriteCallbacks(&writer);
183 writer.WriteNow(MakeUnique<std::string>("foo")); 208 writer.WriteNow(MakeUnique<std::string>("foo"));
184 RunLoop().RunUntilIdle(); 209 RunLoop().RunUntilIdle();
185 210
186 // Expect the callback to not have been executed before the write. 211 // Expect the callback to not have been executed before the
212 // |file_writer_thread| is unblocked.
187 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState()); 213 EXPECT_EQ(NOT_CALLED, write_callback_observer_.GetAndResetObservationState());
188 214
189 // Make sure tasks posted by WriteNow() have ran before continuing. 215 wait_helper.Signal();
190 file_writer_thread.FlushForTesting(); 216 file_writer_thread.FlushForTesting();
217
191 EXPECT_EQ(CALLED_WITH_SUCCESS, 218 EXPECT_EQ(CALLED_WITH_SUCCESS,
192 write_callback_observer_.GetAndResetObservationState()); 219 write_callback_observer_.GetAndResetObservationState());
193 ASSERT_TRUE(PathExists(writer.path())); 220 ASSERT_TRUE(PathExists(writer.path()));
194 EXPECT_EQ("foo", GetFileContent(writer.path())); 221 EXPECT_EQ("foo", GetFileContent(writer.path()));
195 } 222 }
196 223
197 TEST_F(ImportantFileWriterTest, ScheduleWrite) { 224 TEST_F(ImportantFileWriterTest, ScheduleWrite) {
198 ImportantFileWriter writer(file_, 225 ImportantFileWriter writer(file_,
199 ThreadTaskRunnerHandle::Get(), 226 ThreadTaskRunnerHandle::Get(),
200 TimeDelta::FromMilliseconds(25)); 227 TimeDelta::FromMilliseconds(25));
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 writer.ScheduleWrite(&baz); 264 writer.ScheduleWrite(&baz);
238 ThreadTaskRunnerHandle::Get()->PostDelayedTask( 265 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
239 FROM_HERE, MessageLoop::QuitWhenIdleClosure(), 266 FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
240 TimeDelta::FromMilliseconds(100)); 267 TimeDelta::FromMilliseconds(100));
241 RunLoop().Run(); 268 RunLoop().Run();
242 ASSERT_TRUE(PathExists(writer.path())); 269 ASSERT_TRUE(PathExists(writer.path()));
243 EXPECT_EQ("baz", GetFileContent(writer.path())); 270 EXPECT_EQ("baz", GetFileContent(writer.path()));
244 } 271 }
245 272
246 } // namespace base 273 } // namespace base
OLDNEW
« no previous file with comments | « base/files/important_file_writer.cc ('k') | components/prefs/json_pref_store.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698