OLD | NEW |
---|---|
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 <windows.h> | 5 #include "chrome/installer/util/work_item_list.h" |
6 | 6 |
7 #include "base/base_paths.h" | 7 #include <algorithm> |
8 #include "base/files/file_util.h" | 8 #include <memory> |
9 #include <vector> | |
10 | |
11 #include "base/files/file_path.h" | |
9 #include "base/files/scoped_temp_dir.h" | 12 #include "base/files/scoped_temp_dir.h" |
10 #include "base/memory/scoped_ptr.h" | 13 #include "base/macros.h" |
11 #include "base/strings/string_util.h" | |
12 #include "base/test/test_reg_util_win.h" | |
13 #include "base/win/registry.h" | |
14 #include "chrome/installer/util/conditional_work_item_list.h" | 14 #include "chrome/installer/util/conditional_work_item_list.h" |
15 #include "chrome/installer/util/work_item.h" | 15 #include "chrome/installer/util/work_item.h" |
16 #include "chrome/installer/util/work_item_list.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | 16 #include "testing/gtest/include/gtest/gtest.h" |
18 | 17 |
19 using base::win::RegKey; | |
20 | |
21 namespace { | 18 namespace { |
22 | 19 |
23 const wchar_t kTestRoot[] = L"ListList"; | 20 class DummyWorkItem : public WorkItem { |
24 const wchar_t kDataStr[] = L"data_111"; | 21 public: |
25 const wchar_t kName[] = L"name"; | 22 DummyWorkItem(bool do_return_value, |
26 | 23 std::vector<WorkItem*>* do_list, |
27 class WorkItemListTest : public testing::Test { | 24 std::vector<WorkItem*>* rollback_list) |
28 protected: | 25 : do_return_value_(do_return_value), |
29 void SetUp() override { | 26 do_list_(do_list), |
30 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 27 rollback_list_(rollback_list) {} |
31 registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER); | 28 |
32 } | 29 bool Do() override { |
33 | 30 do_list_->push_back(this); |
34 void TearDown() override { logging::CloseLogFile(); } | 31 return do_return_value_; |
35 | 32 } |
36 base::ScopedTempDir temp_dir_; | 33 |
37 registry_util::RegistryOverrideManager registry_override_manager_; | 34 void Rollback() override { rollback_list_->push_back(this); } |
35 | |
36 private: | |
37 // Value returned by Do(). | |
38 const bool do_return_value_; | |
39 | |
40 // List to which this WorkItem is added when Do() runs. | |
41 std::vector<WorkItem*>* const do_list_; | |
42 | |
43 // List to which this WorkItem is added when RollbackImpl() runs. | |
44 std::vector<WorkItem*>* const rollback_list_; | |
45 | |
46 DISALLOW_COPY_AND_ASSIGN(DummyWorkItem); | |
38 }; | 47 }; |
39 | 48 |
49 std::vector<WorkItem*> ReverseVector(const std::vector<WorkItem*>& in) { | |
50 std::vector<WorkItem*> out(in.size()); | |
grt (UTC plus 2)
2016/04/12 19:47:06
how about:
return std::vector<WorkItem*>(in.rbeg
fdoray
2016/04/13 15:07:09
n/a
| |
51 std::reverse_copy(in.begin(), in.end(), out.begin()); | |
52 return out; | |
53 } | |
54 | |
40 } // namespace | 55 } // namespace |
41 | 56 |
42 // Execute a WorkItem list successfully and then rollback. | 57 // Execute a WorkItem list successfully and then rollback. |
43 TEST_F(WorkItemListTest, ExecutionSuccess) { | 58 TEST(WorkItemListTest, ExecutionSuccess) { |
44 scoped_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList()); | 59 std::unique_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList()); |
grt (UTC plus 2)
2016/04/12 19:47:06
this seems like a perfect use of GoogleMock. i thi
fdoray
2016/04/13 15:07:09
Done.
| |
45 scoped_ptr<WorkItem> work_item; | 60 |
46 | 61 std::vector<WorkItem*> do_list; |
47 base::FilePath top_dir_to_create(temp_dir_.path()); | 62 std::vector<WorkItem*> rollback_list; |
48 top_dir_to_create = top_dir_to_create.AppendASCII("a"); | 63 std::vector<WorkItem*> expected_do_list; |
49 base::FilePath dir_to_create(top_dir_to_create); | 64 |
50 dir_to_create = dir_to_create.AppendASCII("b"); | 65 // Work items that succeed. |
51 ASSERT_FALSE(base::PathExists(dir_to_create)); | 66 for (int i = 0; i < 3; ++i) { |
52 | 67 std::unique_ptr<WorkItem> work_item( |
53 work_item.reset(reinterpret_cast<WorkItem*>( | 68 new DummyWorkItem(true, &do_list, &rollback_list)); |
54 WorkItem::CreateCreateDirWorkItem(dir_to_create))); | 69 expected_do_list.push_back(work_item.get()); |
70 work_item_list->AddWorkItem(work_item.release()); | |
71 } | |
72 | |
73 EXPECT_TRUE(work_item_list->Do()); | |
74 EXPECT_EQ(expected_do_list, do_list); | |
75 | |
76 work_item_list->Rollback(); | |
77 | |
78 EXPECT_EQ(ReverseVector(expected_do_list), rollback_list); | |
79 } | |
80 | |
81 // Execute a WorkItem list. Fail in the middle. Rollback what has been done. | |
82 TEST(WorkItemListTest, ExecutionFailAndRollback) { | |
83 std::unique_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList()); | |
84 | |
85 std::vector<WorkItem*> do_list; | |
86 std::vector<WorkItem*> rollback_list; | |
87 std::vector<WorkItem*> expected_do_list; | |
88 | |
89 // Work items that succeed. | |
90 for (int i = 0; i < 3; ++i) { | |
91 std::unique_ptr<WorkItem> work_item( | |
92 new DummyWorkItem(true, &do_list, &rollback_list)); | |
93 expected_do_list.push_back(work_item.get()); | |
94 work_item_list->AddWorkItem(work_item.release()); | |
95 } | |
96 | |
97 // Work item that fails. | |
98 std::unique_ptr<WorkItem> work_item( | |
99 new DummyWorkItem(false, &do_list, &rollback_list)); | |
100 expected_do_list.push_back(work_item.get()); | |
55 work_item_list->AddWorkItem(work_item.release()); | 101 work_item_list->AddWorkItem(work_item.release()); |
56 | 102 |
57 std::wstring key_to_create(kTestRoot); | 103 // More work items that fail. |
58 key_to_create.push_back(base::FilePath::kSeparators[0]); | 104 for (int i = 0; i < 3; ++i) { |
59 key_to_create.append(L"ExecutionSuccess"); | 105 work_item_list->AddWorkItem( |
60 | 106 new DummyWorkItem(false, &do_list, &rollback_list)); |
61 work_item.reset( | 107 } |
62 reinterpret_cast<WorkItem*>(WorkItem::CreateCreateRegKeyWorkItem( | 108 |
63 HKEY_CURRENT_USER, key_to_create, WorkItem::kWow64Default))); | 109 EXPECT_FALSE(work_item_list->Do()); |
64 work_item_list->AddWorkItem(work_item.release()); | 110 EXPECT_EQ(expected_do_list, do_list); |
65 | |
66 std::wstring name(kName); | |
67 std::wstring data(kDataStr); | |
68 work_item.reset(reinterpret_cast<WorkItem*>( | |
69 WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, | |
70 key_to_create, | |
71 WorkItem::kWow64Default, | |
72 name, | |
73 data, | |
74 false))); | |
75 work_item_list->AddWorkItem(work_item.release()); | |
76 | |
77 EXPECT_TRUE(work_item_list->Do()); | |
78 | |
79 // Verify all WorkItems have been executed. | |
80 RegKey key; | |
81 EXPECT_EQ(ERROR_SUCCESS, | |
82 key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ)); | |
83 std::wstring read_out; | |
84 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(name.c_str(), &read_out)); | |
85 EXPECT_EQ(0, read_out.compare(kDataStr)); | |
86 key.Close(); | |
87 EXPECT_TRUE(base::PathExists(dir_to_create)); | |
88 | 111 |
89 work_item_list->Rollback(); | 112 work_item_list->Rollback(); |
90 | 113 EXPECT_EQ(ReverseVector(expected_do_list), rollback_list); |
91 // Verify everything is rolled back. | 114 } |
92 // The value must have been deleted first in roll back otherwise the key | 115 |
93 // can not be deleted. | 116 TEST(WorkItemListTest, ConditionalExecutionSuccess) { |
94 EXPECT_NE(ERROR_SUCCESS, | 117 base::ScopedTempDir temp_dir; |
95 key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ)); | 118 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
96 EXPECT_FALSE(base::PathExists(top_dir_to_create)); | 119 |
97 } | 120 std::unique_ptr<WorkItemList> conditional_work_item_list( |
98 | |
99 // Execute a WorkItem list. Fail in the middle. Rollback what has been done. | |
100 TEST_F(WorkItemListTest, ExecutionFailAndRollback) { | |
101 scoped_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList()); | |
102 scoped_ptr<WorkItem> work_item; | |
103 | |
104 base::FilePath top_dir_to_create(temp_dir_.path()); | |
105 top_dir_to_create = top_dir_to_create.AppendASCII("a"); | |
106 base::FilePath dir_to_create(top_dir_to_create); | |
107 dir_to_create = dir_to_create.AppendASCII("b"); | |
108 ASSERT_FALSE(base::PathExists(dir_to_create)); | |
109 | |
110 work_item.reset(reinterpret_cast<WorkItem*>( | |
111 WorkItem::CreateCreateDirWorkItem(dir_to_create))); | |
112 work_item_list->AddWorkItem(work_item.release()); | |
113 | |
114 std::wstring key_to_create(kTestRoot); | |
115 key_to_create.push_back(base::FilePath::kSeparators[0]); | |
116 key_to_create.append(L"ExecutionFail"); | |
117 | |
118 work_item.reset( | |
119 reinterpret_cast<WorkItem*>(WorkItem::CreateCreateRegKeyWorkItem( | |
120 HKEY_CURRENT_USER, key_to_create, WorkItem::kWow64Default))); | |
121 work_item_list->AddWorkItem(work_item.release()); | |
122 | |
123 std::wstring not_created_key(kTestRoot); | |
124 not_created_key.push_back(base::FilePath::kSeparators[0]); | |
125 not_created_key.append(L"NotCreated"); | |
126 std::wstring name(kName); | |
127 std::wstring data(kDataStr); | |
128 work_item.reset(reinterpret_cast<WorkItem*>( | |
129 WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, | |
130 not_created_key, | |
131 WorkItem::kWow64Default, | |
132 name, | |
133 data, | |
134 false))); | |
135 work_item_list->AddWorkItem(work_item.release()); | |
136 | |
137 // This one will not be executed because we will fail early. | |
138 work_item.reset( | |
139 reinterpret_cast<WorkItem*>(WorkItem::CreateCreateRegKeyWorkItem( | |
140 HKEY_CURRENT_USER, not_created_key, WorkItem::kWow64Default))); | |
141 work_item_list->AddWorkItem(work_item.release()); | |
142 | |
143 EXPECT_FALSE(work_item_list->Do()); | |
144 | |
145 // Verify the first 2 WorkItems have been executed. | |
146 RegKey key; | |
147 EXPECT_EQ(ERROR_SUCCESS, | |
148 key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ)); | |
149 key.Close(); | |
150 EXPECT_TRUE(base::PathExists(dir_to_create)); | |
151 // The last one should not be there. | |
152 EXPECT_NE(ERROR_SUCCESS, | |
153 key.Open(HKEY_CURRENT_USER, not_created_key.c_str(), KEY_READ)); | |
154 | |
155 work_item_list->Rollback(); | |
156 | |
157 // Verify everything is rolled back. | |
158 EXPECT_NE(ERROR_SUCCESS, | |
159 key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ)); | |
160 EXPECT_FALSE(base::PathExists(top_dir_to_create)); | |
161 } | |
162 | |
163 TEST_F(WorkItemListTest, ConditionalExecutionSuccess) { | |
164 scoped_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList()); | |
165 scoped_ptr<WorkItem> work_item; | |
166 | |
167 base::FilePath top_dir_to_create(temp_dir_.path()); | |
168 top_dir_to_create = top_dir_to_create.AppendASCII("a"); | |
169 base::FilePath dir_to_create(top_dir_to_create); | |
170 dir_to_create = dir_to_create.AppendASCII("b"); | |
171 ASSERT_FALSE(base::PathExists(dir_to_create)); | |
172 | |
173 work_item.reset(reinterpret_cast<WorkItem*>( | |
174 WorkItem::CreateCreateDirWorkItem(dir_to_create))); | |
175 work_item_list->AddWorkItem(work_item.release()); | |
176 | |
177 scoped_ptr<WorkItemList> conditional_work_item_list( | |
178 WorkItem::CreateConditionalWorkItemList( | 121 WorkItem::CreateConditionalWorkItemList( |
179 new ConditionRunIfFileExists(dir_to_create))); | 122 new ConditionRunIfFileExists(temp_dir.path()))); |
180 | 123 |
181 std::wstring key_to_create(kTestRoot); | 124 std::vector<WorkItem*> do_list; |
182 key_to_create.push_back(base::FilePath::kSeparators[0]); | 125 std::vector<WorkItem*> rollback_list; |
183 key_to_create.append(L"ExecutionSuccess"); | 126 std::vector<WorkItem*> expected_do_list; |
184 work_item.reset( | 127 |
185 reinterpret_cast<WorkItem*>(WorkItem::CreateCreateRegKeyWorkItem( | 128 // Work items that succeed. |
186 HKEY_CURRENT_USER, key_to_create, WorkItem::kWow64Default))); | 129 for (int i = 0; i < 3; ++i) { |
130 std::unique_ptr<WorkItem> work_item( | |
131 new DummyWorkItem(true, &do_list, &rollback_list)); | |
132 expected_do_list.push_back(work_item.get()); | |
133 conditional_work_item_list->AddWorkItem(work_item.release()); | |
134 } | |
135 | |
136 EXPECT_TRUE(conditional_work_item_list->Do()); | |
137 EXPECT_EQ(expected_do_list, do_list); | |
138 | |
139 conditional_work_item_list->Rollback(); | |
140 EXPECT_EQ(ReverseVector(expected_do_list), rollback_list); | |
141 } | |
142 | |
143 TEST(WorkItemListTest, ConditionalExecutionFailAndRollback) { | |
144 base::ScopedTempDir temp_dir; | |
145 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | |
146 | |
147 std::unique_ptr<WorkItemList> conditional_work_item_list( | |
148 WorkItem::CreateConditionalWorkItemList( | |
149 new ConditionRunIfFileExists(temp_dir.path()))); | |
150 | |
151 std::vector<WorkItem*> do_list; | |
152 std::vector<WorkItem*> rollback_list; | |
153 std::vector<WorkItem*> expected_do_list; | |
154 | |
155 // Work items that succeed. | |
156 for (int i = 0; i < 3; ++i) { | |
157 std::unique_ptr<WorkItem> work_item( | |
158 new DummyWorkItem(true, &do_list, &rollback_list)); | |
159 expected_do_list.push_back(work_item.get()); | |
160 conditional_work_item_list->AddWorkItem(work_item.release()); | |
161 } | |
162 | |
163 // Work item that fails. | |
164 std::unique_ptr<WorkItem> work_item( | |
165 new DummyWorkItem(false, &do_list, &rollback_list)); | |
166 expected_do_list.push_back(work_item.get()); | |
187 conditional_work_item_list->AddWorkItem(work_item.release()); | 167 conditional_work_item_list->AddWorkItem(work_item.release()); |
188 | 168 |
189 std::wstring name(kName); | 169 // More work items that fail. |
190 std::wstring data(kDataStr); | 170 for (int i = 0; i < 3; ++i) { |
191 work_item.reset(reinterpret_cast<WorkItem*>( | 171 conditional_work_item_list->AddWorkItem( |
192 WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, | 172 new DummyWorkItem(false, &do_list, &rollback_list)); |
193 key_to_create, | 173 } |
194 WorkItem::kWow64Default, | 174 |
195 name, | 175 EXPECT_FALSE(conditional_work_item_list->Do()); |
196 data, | 176 EXPECT_EQ(expected_do_list, do_list); |
197 false))); | 177 |
198 conditional_work_item_list->AddWorkItem(work_item.release()); | 178 conditional_work_item_list->Rollback(); |
199 | 179 EXPECT_EQ(ReverseVector(expected_do_list), rollback_list); |
200 work_item_list->AddWorkItem(conditional_work_item_list.release()); | 180 } |
201 | 181 |
202 EXPECT_TRUE(work_item_list->Do()); | 182 TEST(WorkItemListTest, ConditionalExecutionConditionFailure) { |
203 | 183 base::ScopedTempDir temp_dir; |
204 // Verify all WorkItems have been executed. | 184 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
205 RegKey key; | 185 |
206 EXPECT_EQ(ERROR_SUCCESS, | 186 std::unique_ptr<WorkItemList> conditional_work_item_list( |
207 key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ)); | 187 WorkItem::CreateConditionalWorkItemList(new ConditionRunIfFileExists( |
208 std::wstring read_out; | 188 temp_dir.path().Append(FILE_PATH_LITERAL("DoesNotExist"))))); |
209 EXPECT_EQ(ERROR_SUCCESS, key.ReadValue(name.c_str(), &read_out)); | 189 |
210 EXPECT_EQ(0, read_out.compare(kDataStr)); | 190 std::vector<WorkItem*> do_list; |
211 key.Close(); | 191 std::vector<WorkItem*> rollback_list; |
212 EXPECT_TRUE(base::PathExists(dir_to_create)); | 192 |
213 | 193 // Work items that shouldn't run because the condition isn't met. |
214 work_item_list->Rollback(); | 194 for (int i = 0; i < 3; ++i) { |
215 | 195 conditional_work_item_list->AddWorkItem( |
216 // Verify everything is rolled back. | 196 new DummyWorkItem(true, &do_list, &rollback_list)); |
217 // The value must have been deleted first in roll back otherwise the key | 197 } |
218 // can not be deleted. | 198 |
219 EXPECT_NE(ERROR_SUCCESS, | 199 EXPECT_TRUE(conditional_work_item_list->Do()); |
220 key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ)); | 200 EXPECT_TRUE(do_list.empty()); |
221 EXPECT_FALSE(base::PathExists(top_dir_to_create)); | 201 |
222 } | 202 conditional_work_item_list->Rollback(); |
223 | 203 EXPECT_TRUE(rollback_list.empty()); |
224 TEST_F(WorkItemListTest, ConditionalExecutionConditionFailure) { | 204 } |
225 scoped_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList()); | |
226 scoped_ptr<WorkItem> work_item; | |
227 | |
228 base::FilePath top_dir_to_create(temp_dir_.path()); | |
229 top_dir_to_create = top_dir_to_create.AppendASCII("a"); | |
230 base::FilePath dir_to_create(top_dir_to_create); | |
231 dir_to_create = dir_to_create.AppendASCII("b"); | |
232 ASSERT_FALSE(base::PathExists(dir_to_create)); | |
233 | |
234 work_item.reset(reinterpret_cast<WorkItem*>( | |
235 WorkItem::CreateCreateDirWorkItem(dir_to_create))); | |
236 work_item_list->AddWorkItem(work_item.release()); | |
237 | |
238 scoped_ptr<WorkItemList> conditional_work_item_list( | |
239 WorkItem::CreateConditionalWorkItemList( | |
240 new ConditionRunIfFileExists(dir_to_create.AppendASCII("c")))); | |
241 | |
242 std::wstring key_to_create(kTestRoot); | |
243 key_to_create.push_back(base::FilePath::kSeparators[0]); | |
244 key_to_create.append(L"ExecutionSuccess"); | |
245 work_item.reset( | |
246 reinterpret_cast<WorkItem*>(WorkItem::CreateCreateRegKeyWorkItem( | |
247 HKEY_CURRENT_USER, key_to_create, WorkItem::kWow64Default))); | |
248 conditional_work_item_list->AddWorkItem(work_item.release()); | |
249 | |
250 std::wstring name(kName); | |
251 std::wstring data(kDataStr); | |
252 work_item.reset(reinterpret_cast<WorkItem*>( | |
253 WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, | |
254 key_to_create, | |
255 WorkItem::kWow64Default, | |
256 name, | |
257 data, | |
258 false))); | |
259 conditional_work_item_list->AddWorkItem(work_item.release()); | |
260 | |
261 work_item_list->AddWorkItem(conditional_work_item_list.release()); | |
262 | |
263 EXPECT_TRUE(work_item_list->Do()); | |
264 | |
265 // Verify that the WorkItems added as part of the conditional list have NOT | |
266 // been executed. | |
267 RegKey key; | |
268 EXPECT_NE(ERROR_SUCCESS, | |
269 key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ)); | |
270 std::wstring read_out; | |
271 EXPECT_NE(ERROR_SUCCESS, key.ReadValue(name.c_str(), &read_out)); | |
272 key.Close(); | |
273 | |
274 // Verify that the other work item was executed. | |
275 EXPECT_TRUE(base::PathExists(dir_to_create)); | |
276 | |
277 work_item_list->Rollback(); | |
278 | |
279 // Verify everything is rolled back. | |
280 // The value must have been deleted first in roll back otherwise the key | |
281 // can not be deleted. | |
282 EXPECT_NE(ERROR_SUCCESS, | |
283 key.Open(HKEY_CURRENT_USER, key_to_create.c_str(), KEY_READ)); | |
284 EXPECT_FALSE(base::PathExists(top_dir_to_create)); | |
285 } | |
OLD | NEW |