OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009 The Chromium OS 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 <string> | |
6 #include <vector> | |
7 #include <glib.h> | |
8 #include <gtest/gtest.h> | |
9 #include "update_engine/action_pipe.h" | |
10 #include "update_engine/update_check_action.h" | |
11 #include "update_engine/mock_http_fetcher.h" | |
12 #include "update_engine/omaha_hash_calculator.h" | |
13 #include "update_engine/test_utils.h" | |
14 | |
15 using std::string; | |
16 using std::vector; | |
17 | |
18 namespace chromeos_update_engine { | |
19 | |
20 class UpdateCheckActionTest : public ::testing::Test { }; | |
21 | |
22 namespace { | |
23 string GetNoUpdateResponse(const string& app_id) { | |
24 return string( | |
25 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><gupdate " | |
26 "xmlns=\"http://www.google.com/update2/response\" protocol=\"2.0\"><app " | |
27 "appid=\"") + app_id + "\" status=\"ok\"><ping " | |
28 "status=\"ok\"/><updatecheck status=\"noupdate\"/></app></gupdate>"; | |
29 } | |
30 | |
31 string GetUpdateResponse(const string& app_id, | |
32 const string& display_version, | |
33 const string& more_info_url, | |
34 const string& prompt, | |
35 const string& codebase, | |
36 const string& hash, | |
37 const string& needsadmin, | |
38 const string& size) { | |
39 return string("<?xml version=\"1.0\" encoding=\"UTF-8\"?><gupdate " | |
40 "xmlns=\"http://www.google.com/update2/response\" " | |
41 "protocol=\"2.0\"><app " | |
42 "appid=\"") + app_id + "\" status=\"ok\"><ping " | |
43 "status=\"ok\"/><updatecheck DisplayVersion=\"" + display_version + "\" " | |
44 "MoreInfo=\"" + more_info_url + "\" Prompt=\"" + prompt + "\" " | |
45 "codebase=\"" + codebase + "\" " | |
46 "hash=\"" + hash + "\" needsadmin=\"" + needsadmin + "\" " | |
47 "size=\"" + size + "\" status=\"ok\"/></app></gupdate>"; | |
48 } | |
49 | |
50 class UpdateCheckActionTestProcessorDelegate : public ActionProcessorDelegate { | |
51 public: | |
52 UpdateCheckActionTestProcessorDelegate() | |
53 : loop_(NULL), | |
54 expected_success_(true) {} | |
55 virtual ~UpdateCheckActionTestProcessorDelegate() { | |
56 } | |
57 virtual void ProcessingDone(const ActionProcessor* processor, bool success) { | |
58 ASSERT_TRUE(loop_); | |
59 g_main_loop_quit(loop_); | |
60 } | |
61 | |
62 virtual void ActionCompleted(ActionProcessor* processor, | |
63 AbstractAction* action, | |
64 bool success) { | |
65 // make sure actions always succeed | |
66 if (action->Type() == UpdateCheckAction::StaticType()) | |
67 EXPECT_EQ(expected_success_, success); | |
68 else | |
69 EXPECT_TRUE(success); | |
70 } | |
71 GMainLoop *loop_; | |
72 bool expected_success_; | |
73 }; | |
74 | |
75 gboolean StartProcessorInRunLoop(gpointer data) { | |
76 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data); | |
77 processor->StartProcessing(); | |
78 return FALSE; | |
79 } | |
80 | |
81 } // namespace {} | |
82 | |
83 class OutputObjectCollectorAction; | |
84 | |
85 template<> | |
86 class ActionTraits<OutputObjectCollectorAction> { | |
87 public: | |
88 // Does not take an object for input | |
89 typedef UpdateCheckResponse InputObjectType; | |
90 // On success, puts the output path on output | |
91 typedef NoneType OutputObjectType; | |
92 }; | |
93 | |
94 class OutputObjectCollectorAction : public Action<OutputObjectCollectorAction> { | |
95 public: | |
96 OutputObjectCollectorAction() : has_input_object_(false) {} | |
97 void PerformAction() { | |
98 // copy input object | |
99 has_input_object_ = HasInputObject(); | |
100 if (has_input_object_) | |
101 update_check_response_ = GetInputObject(); | |
102 processor_->ActionComplete(this, true); | |
103 } | |
104 // Should never be called | |
105 void TerminateProcessing() { | |
106 CHECK(false); | |
107 } | |
108 // Debugging/logging | |
109 static std::string StaticType() { | |
110 return "OutputObjectCollectorAction"; | |
111 } | |
112 std::string Type() const { return StaticType(); } | |
113 bool has_input_object_; | |
114 UpdateCheckResponse update_check_response_; | |
115 }; | |
116 | |
117 // returns true iff an output response was obtained from the | |
118 // UpdateCheckAction. out_response may be NULL. | |
119 // out_post_data may be null; if non-null, the post-data received by the | |
120 // mock HttpFetcher is returned. | |
121 bool TestUpdateCheckAction(const UpdateCheckParams& params, | |
122 const string& http_response, | |
123 bool expected_success, | |
124 UpdateCheckResponse* out_response, | |
125 vector<char> *out_post_data) { | |
126 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE); | |
127 MockHttpFetcher *fetcher = new MockHttpFetcher(http_response.data(), | |
128 http_response.size()); | |
129 ObjectFeederAction<UpdateCheckParams> feeder_action; | |
130 UpdateCheckAction action(fetcher); // takes ownership of fetcher | |
131 UpdateCheckActionTestProcessorDelegate delegate; | |
132 delegate.loop_ = loop; | |
133 delegate.expected_success_ = expected_success; | |
134 ActionProcessor processor; | |
135 feeder_action.set_obj(params); | |
136 processor.set_delegate(&delegate); | |
137 processor.EnqueueAction(&feeder_action); | |
138 processor.EnqueueAction(&action); | |
139 | |
140 OutputObjectCollectorAction collector_action; | |
141 | |
142 BondActions(&feeder_action, &action); | |
143 BondActions(&action, &collector_action); | |
144 processor.EnqueueAction(&collector_action); | |
145 | |
146 g_timeout_add(0, &StartProcessorInRunLoop, &processor); | |
147 g_main_loop_run(loop); | |
148 g_main_loop_unref(loop); | |
149 if (collector_action.has_input_object_ && out_response) | |
150 *out_response = collector_action.update_check_response_; | |
151 if (out_post_data) | |
152 *out_post_data = fetcher->post_data(); | |
153 return collector_action.has_input_object_; | |
154 } | |
155 | |
156 TEST(UpdateCheckActionTest, NoUpdateTest) { | |
157 UpdateCheckParams params("", // machine_id | |
158 "", // user_id | |
159 UpdateCheckParams::kOsPlatform, | |
160 UpdateCheckParams::kOsVersion, | |
161 "", // os_sp | |
162 "x86-generic", | |
163 UpdateCheckParams::kAppId, | |
164 "0.1.0.0", | |
165 "en-US", | |
166 "unittest", | |
167 ""); // url | |
168 UpdateCheckResponse response; | |
169 ASSERT_TRUE( | |
170 TestUpdateCheckAction(params, | |
171 GetNoUpdateResponse(UpdateCheckParams::kAppId), | |
172 true, | |
173 &response, | |
174 NULL)); | |
175 EXPECT_FALSE(response.update_exists); | |
176 } | |
177 | |
178 TEST(UpdateCheckActionTest, ValidUpdateTest) { | |
179 UpdateCheckParams params("machine_id", | |
180 "user_id", | |
181 UpdateCheckParams::kOsPlatform, | |
182 UpdateCheckParams::kOsVersion, | |
183 "service_pack", | |
184 "arm-generic", | |
185 UpdateCheckParams::kAppId, | |
186 "0.1.0.0", | |
187 "en-US", | |
188 "unittest_track", | |
189 ""); // url | |
190 UpdateCheckResponse response; | |
191 ASSERT_TRUE( | |
192 TestUpdateCheckAction(params, | |
193 GetUpdateResponse(UpdateCheckParams::kAppId, | |
194 "1.2.3.4", // version | |
195 "http://more/info", | |
196 "true", // prompt | |
197 "http://code/base", // dl url | |
198 "HASH1234=", // checksum | |
199 "false", // needs admin | |
200 "123"), // size | |
201 true, | |
202 &response, | |
203 NULL)); | |
204 EXPECT_TRUE(response.update_exists); | |
205 EXPECT_EQ("1.2.3.4", response.display_version); | |
206 EXPECT_EQ("http://code/base", response.codebase); | |
207 EXPECT_EQ("http://more/info", response.more_info_url); | |
208 EXPECT_EQ("HASH1234=", response.hash); | |
209 EXPECT_EQ(123, response.size); | |
210 EXPECT_FALSE(response.needs_admin); | |
211 EXPECT_TRUE(response.prompt); | |
212 } | |
213 | |
214 TEST(UpdateCheckActionTest, NoOutputPipeTest) { | |
215 UpdateCheckParams params("", // machine_id | |
216 "", // usr_id | |
217 UpdateCheckParams::kOsPlatform, | |
218 UpdateCheckParams::kOsVersion, | |
219 "", // os_sp | |
220 "", // os_board | |
221 UpdateCheckParams::kAppId, | |
222 "0.1.0.0", | |
223 "en-US", | |
224 "unittest", | |
225 ""); // url | |
226 const string http_response(GetNoUpdateResponse(UpdateCheckParams::kAppId)); | |
227 | |
228 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE); | |
229 | |
230 ObjectFeederAction<UpdateCheckParams> feeder_action; | |
231 feeder_action.set_obj(params); | |
232 UpdateCheckAction action(new MockHttpFetcher(http_response.data(), | |
233 http_response.size())); | |
234 UpdateCheckActionTestProcessorDelegate delegate; | |
235 delegate.loop_ = loop; | |
236 ActionProcessor processor; | |
237 processor.set_delegate(&delegate); | |
238 processor.EnqueueAction(&feeder_action); | |
239 processor.EnqueueAction(&action); | |
240 BondActions(&feeder_action, &action); | |
241 | |
242 g_timeout_add(0, &StartProcessorInRunLoop, &processor); | |
243 g_main_loop_run(loop); | |
244 g_main_loop_unref(loop); | |
245 EXPECT_FALSE(processor.IsRunning()); | |
246 } | |
247 | |
248 TEST(UpdateCheckActionTest, InvalidXmlTest) { | |
249 UpdateCheckParams params("machine_id", | |
250 "user_id", | |
251 UpdateCheckParams::kOsPlatform, | |
252 UpdateCheckParams::kOsVersion, | |
253 "service_pack", | |
254 "x86-generic", | |
255 UpdateCheckParams::kAppId, | |
256 "0.1.0.0", | |
257 "en-US", | |
258 "unittest_track", | |
259 "http://url"); | |
260 UpdateCheckResponse response; | |
261 ASSERT_FALSE( | |
262 TestUpdateCheckAction(params, | |
263 "invalid xml>", | |
264 false, | |
265 &response, | |
266 NULL)); | |
267 EXPECT_FALSE(response.update_exists); | |
268 } | |
269 | |
270 TEST(UpdateCheckActionTest, MissingStatusTest) { | |
271 UpdateCheckParams params("machine_id", | |
272 "user_id", | |
273 UpdateCheckParams::kOsPlatform, | |
274 UpdateCheckParams::kOsVersion, | |
275 "service_pack", | |
276 "x86-generic", | |
277 UpdateCheckParams::kAppId, | |
278 "0.1.0.0", | |
279 "en-US", | |
280 "unittest_track", | |
281 "http://url"); | |
282 UpdateCheckResponse response; | |
283 ASSERT_FALSE(TestUpdateCheckAction( | |
284 params, | |
285 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><gupdate " | |
286 "xmlns=\"http://www.google.com/update2/response\" protocol=\"2.0\"><app " | |
287 "appid=\"foo\" status=\"ok\"><ping " | |
288 "status=\"ok\"/><updatecheck/></app></gupdate>", | |
289 false, | |
290 &response, | |
291 NULL)); | |
292 EXPECT_FALSE(response.update_exists); | |
293 } | |
294 | |
295 TEST(UpdateCheckActionTest, InvalidStatusTest) { | |
296 UpdateCheckParams params("machine_id", | |
297 "user_id", | |
298 UpdateCheckParams::kOsPlatform, | |
299 UpdateCheckParams::kOsVersion, | |
300 "service_pack", | |
301 "x86-generic", | |
302 UpdateCheckParams::kAppId, | |
303 "0.1.0.0", | |
304 "en-US", | |
305 "unittest_track", | |
306 "http://url"); | |
307 UpdateCheckResponse response; | |
308 ASSERT_FALSE(TestUpdateCheckAction( | |
309 params, | |
310 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><gupdate " | |
311 "xmlns=\"http://www.google.com/update2/response\" protocol=\"2.0\"><app " | |
312 "appid=\"foo\" status=\"ok\"><ping " | |
313 "status=\"ok\"/><updatecheck status=\"foo\"/></app></gupdate>", | |
314 false, | |
315 &response, | |
316 NULL)); | |
317 EXPECT_FALSE(response.update_exists); | |
318 } | |
319 | |
320 TEST(UpdateCheckActionTest, MissingNodesetTest) { | |
321 UpdateCheckParams params("machine_id", | |
322 "user_id", | |
323 UpdateCheckParams::kOsPlatform, | |
324 UpdateCheckParams::kOsVersion, | |
325 "service_pack", | |
326 "x86-generic", | |
327 UpdateCheckParams::kAppId, | |
328 "0.1.0.0", | |
329 "en-US", | |
330 "unittest_track", | |
331 "http://url"); | |
332 UpdateCheckResponse response; | |
333 ASSERT_FALSE(TestUpdateCheckAction( | |
334 params, | |
335 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><gupdate " | |
336 "xmlns=\"http://www.google.com/update2/response\" protocol=\"2.0\"><app " | |
337 "appid=\"foo\" status=\"ok\"><ping " | |
338 "status=\"ok\"/></app></gupdate>", | |
339 false, | |
340 &response, | |
341 NULL)); | |
342 EXPECT_FALSE(response.update_exists); | |
343 } | |
344 | |
345 TEST(UpdateCheckActionTest, MissingFieldTest) { | |
346 UpdateCheckParams params("machine_id", | |
347 "user_id", | |
348 UpdateCheckParams::kOsPlatform, | |
349 UpdateCheckParams::kOsVersion, | |
350 "service_pack", | |
351 "x86-generic", | |
352 UpdateCheckParams::kAppId, | |
353 "0.1.0.0", | |
354 "en-US", | |
355 "unittest_track", | |
356 "http://url"); | |
357 UpdateCheckResponse response; | |
358 ASSERT_TRUE(TestUpdateCheckAction(params, | |
359 string("<?xml version=\"1.0\" " | |
360 "encoding=\"UTF-8\"?><gupdate " | |
361 "xmlns=\"http://www.google.com/" | |
362 "update2/response\" " | |
363 "protocol=\"2.0\"><app appid=\"") + | |
364 UpdateCheckParams::kAppId | |
365 + "\" status=\"ok\"><ping " | |
366 "status=\"ok\"/><updatecheck " | |
367 "DisplayVersion=\"1.2.3.4\" " | |
368 "Prompt=\"false\" " | |
369 "codebase=\"http://code/base\" " | |
370 "hash=\"HASH1234=\" needsadmin=\"true\" " | |
371 "size=\"123\" " | |
372 "status=\"ok\"/></app></gupdate>", | |
373 true, | |
374 &response, | |
375 NULL)); | |
376 EXPECT_TRUE(response.update_exists); | |
377 EXPECT_EQ("1.2.3.4", response.display_version); | |
378 EXPECT_EQ("http://code/base", response.codebase); | |
379 EXPECT_EQ("", response.more_info_url); | |
380 EXPECT_EQ("HASH1234=", response.hash); | |
381 EXPECT_EQ(123, response.size); | |
382 EXPECT_TRUE(response.needs_admin); | |
383 EXPECT_FALSE(response.prompt); | |
384 } | |
385 | |
386 namespace { | |
387 class TerminateEarlyTestProcessorDelegate : public ActionProcessorDelegate { | |
388 public: | |
389 void ProcessingStopped(const ActionProcessor* processor) { | |
390 ASSERT_TRUE(loop_); | |
391 g_main_loop_quit(loop_); | |
392 } | |
393 GMainLoop *loop_; | |
394 }; | |
395 | |
396 gboolean TerminateTransferTestStarter(gpointer data) { | |
397 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data); | |
398 processor->StartProcessing(); | |
399 CHECK(processor->IsRunning()); | |
400 processor->StopProcessing(); | |
401 return FALSE; | |
402 } | |
403 } // namespace {} | |
404 | |
405 TEST(UpdateCheckActionTest, TerminateTransferTest) { | |
406 UpdateCheckParams params("", // machine_id | |
407 "", // usr_id | |
408 UpdateCheckParams::kOsPlatform, | |
409 UpdateCheckParams::kOsVersion, | |
410 "", // os_sp | |
411 "", // os_board | |
412 UpdateCheckParams::kAppId, | |
413 "0.1.0.0", | |
414 "en-US", | |
415 "unittest", | |
416 "http://url"); | |
417 string http_response("doesn't matter"); | |
418 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE); | |
419 | |
420 ObjectFeederAction<UpdateCheckParams> feeder_action; | |
421 feeder_action.set_obj(params); | |
422 UpdateCheckAction action(new MockHttpFetcher(http_response.data(), | |
423 http_response.size())); | |
424 TerminateEarlyTestProcessorDelegate delegate; | |
425 delegate.loop_ = loop; | |
426 ActionProcessor processor; | |
427 processor.set_delegate(&delegate); | |
428 processor.EnqueueAction(&feeder_action); | |
429 processor.EnqueueAction(&action); | |
430 BondActions(&feeder_action, &action); | |
431 | |
432 g_timeout_add(0, &TerminateTransferTestStarter, &processor); | |
433 g_main_loop_run(loop); | |
434 g_main_loop_unref(loop); | |
435 } | |
436 | |
437 TEST(UpdateCheckActionTest, XmlEncodeTest) { | |
438 EXPECT_EQ("ab", XmlEncode("ab")); | |
439 EXPECT_EQ("a<b", XmlEncode("a<b")); | |
440 EXPECT_EQ("foo-Ω", XmlEncode("foo-\xce\xa9")); | |
441 EXPECT_EQ("<&>", XmlEncode("<&>")); | |
442 EXPECT_EQ("&lt;&amp;&gt;", XmlEncode("<&>")); | |
443 | |
444 vector<char> post_data; | |
445 | |
446 // Make sure XML Encode is being called on the params | |
447 UpdateCheckParams params("testthemachine<id", | |
448 "testtheuser_id<", | |
449 UpdateCheckParams::kOsPlatform, | |
450 UpdateCheckParams::kOsVersion, | |
451 "testtheservice_pack>", | |
452 "x86 generic", | |
453 UpdateCheckParams::kAppId, | |
454 "0.1.0.0", | |
455 "en-US", | |
456 "unittest_track", | |
457 "http://url"); | |
458 UpdateCheckResponse response; | |
459 ASSERT_FALSE( | |
460 TestUpdateCheckAction(params, | |
461 "invalid xml>", | |
462 false, | |
463 &response, | |
464 &post_data)); | |
465 // convert post_data to string | |
466 string post_str(&post_data[0], post_data.size()); | |
467 EXPECT_NE(post_str.find("testthemachine<id"), string::npos); | |
468 EXPECT_EQ(post_str.find("testthemachine<id"), string::npos); | |
469 EXPECT_NE(post_str.find("testtheuser_id&lt;"), string::npos); | |
470 EXPECT_EQ(post_str.find("testtheuser_id<"), string::npos); | |
471 EXPECT_NE(post_str.find("testtheservice_pack>"), string::npos); | |
472 EXPECT_EQ(post_str.find("testtheservice_pack>"), string::npos); | |
473 EXPECT_NE(post_str.find("x86 generic"), string::npos); | |
474 } | |
475 | |
476 TEST(UpdateCheckActionTest, XmlDecodeTest) { | |
477 UpdateCheckParams params("machine_id", | |
478 "user_id", | |
479 UpdateCheckParams::kOsPlatform, | |
480 UpdateCheckParams::kOsVersion, | |
481 "service_pack", | |
482 "x86-generic", | |
483 UpdateCheckParams::kAppId, | |
484 "0.1.0.0", | |
485 "en-US", | |
486 "unittest_track", | |
487 "http://url"); | |
488 UpdateCheckResponse response; | |
489 ASSERT_TRUE( | |
490 TestUpdateCheckAction(params, | |
491 GetUpdateResponse(UpdateCheckParams::kAppId, | |
492 "1.2.3.4", // version | |
493 "testthe<url", // more info | |
494 "true", // prompt | |
495 "testthe&codebase", // dl url | |
496 "HASH1234=", // checksum | |
497 "false", // needs admin | |
498 "123"), // size | |
499 true, | |
500 &response, | |
501 NULL)); | |
502 | |
503 EXPECT_EQ(response.more_info_url, "testthe<url"); | |
504 EXPECT_EQ(response.codebase, "testthe&codebase"); | |
505 } | |
506 | |
507 TEST(UpdateCheckActionTest, ParseIntTest) { | |
508 UpdateCheckParams params("machine_id", | |
509 "user_id", | |
510 UpdateCheckParams::kOsPlatform, | |
511 UpdateCheckParams::kOsVersion, | |
512 "service_pack", | |
513 "the_board", | |
514 UpdateCheckParams::kAppId, | |
515 "0.1.0.0", | |
516 "en-US", | |
517 "unittest_track", | |
518 "http://url"); | |
519 UpdateCheckResponse response; | |
520 ASSERT_TRUE( | |
521 TestUpdateCheckAction(params, | |
522 GetUpdateResponse(UpdateCheckParams::kAppId, | |
523 "1.2.3.4", // version | |
524 "theurl", // more info | |
525 "true", // prompt | |
526 "thecodebase", // dl url | |
527 "HASH1234=", // checksum | |
528 "false", // needs admin | |
529 // overflows int32: | |
530 "123123123123123"), // size | |
531 true, | |
532 &response, | |
533 NULL)); | |
534 | |
535 EXPECT_EQ(response.size, 123123123123123ll); | |
536 } | |
537 | |
538 } // namespace chromeos_update_engine | |
OLD | NEW |