blob: c57e2cd0646fb4bfd730ec126907adc4ce3e9212 [file] [log] [blame]
rspangler@google.com49fdf182009-10-10 00:57:34 +00001// 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>
adlr@google.comc98a7ed2009-12-04 18:54:03 +00006#include <vector>
rspangler@google.com49fdf182009-10-10 00:57:34 +00007#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
rspangler@google.com49fdf182009-10-10 00:57:34 +000015using std::string;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000016using std::vector;
17
18namespace chromeos_update_engine {
rspangler@google.com49fdf182009-10-10 00:57:34 +000019
20class UpdateCheckActionTest : public ::testing::Test { };
21
22namespace {
23string 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
31string 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 "
adlr@google.comc98a7ed2009-12-04 18:54:03 +000040 "xmlns=\"http://www.google.com/update2/response\" "
41 "protocol=\"2.0\"><app "
42 "appid=\"") + app_id + "\" status=\"ok\"><ping "
rspangler@google.com49fdf182009-10-10 00:57:34 +000043 "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
50class UpdateCheckActionTestProcessorDelegate : public ActionProcessorDelegate {
51 public:
52 UpdateCheckActionTestProcessorDelegate()
53 : loop_(NULL),
54 expected_success_(true) {}
55 virtual ~UpdateCheckActionTestProcessorDelegate() {
56 }
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -080057 virtual void ProcessingDone(const ActionProcessor* processor, bool success) {
rspangler@google.com49fdf182009-10-10 00:57:34 +000058 ASSERT_TRUE(loop_);
59 g_main_loop_quit(loop_);
60 }
61
adlr@google.comc98a7ed2009-12-04 18:54:03 +000062 virtual void ActionCompleted(ActionProcessor* processor,
63 AbstractAction* action,
rspangler@google.com49fdf182009-10-10 00:57:34 +000064 bool success) {
65 // make sure actions always succeed
adlr@google.comc98a7ed2009-12-04 18:54:03 +000066 if (action->Type() == UpdateCheckAction::StaticType())
rspangler@google.com49fdf182009-10-10 00:57:34 +000067 EXPECT_EQ(expected_success_, success);
68 else
69 EXPECT_TRUE(success);
70 }
71 GMainLoop *loop_;
72 bool expected_success_;
73};
74
75gboolean StartProcessorInRunLoop(gpointer data) {
76 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
77 processor->StartProcessing();
78 return FALSE;
79}
80
81} // namespace {}
82
83class OutputObjectCollectorAction;
84
85template<>
86class 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
94class OutputObjectCollectorAction : public Action<OutputObjectCollectorAction> {
95 public:
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070096 OutputObjectCollectorAction() : has_input_object_(false) {}
rspangler@google.com49fdf182009-10-10 00:57:34 +000097 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
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000109 static std::string StaticType() {
110 return "OutputObjectCollectorAction";
111 }
112 std::string Type() const { return StaticType(); }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000113 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.
121bool 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());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000129 ObjectFeederAction<UpdateCheckParams> feeder_action;
130 UpdateCheckAction action(fetcher); // takes ownership of fetcher
rspangler@google.com49fdf182009-10-10 00:57:34 +0000131 UpdateCheckActionTestProcessorDelegate delegate;
132 delegate.loop_ = loop;
133 delegate.expected_success_ = expected_success;
134 ActionProcessor processor;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000135 feeder_action.set_obj(params);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000136 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000137 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000138 processor.EnqueueAction(&action);
139
140 OutputObjectCollectorAction collector_action;
141
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000142 BondActions(&feeder_action, &action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000143 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
156TEST(UpdateCheckActionTest, NoUpdateTest) {
157 UpdateCheckParams params("", // machine_id
158 "", // user_id
159 UpdateCheckParams::kOsPlatform,
160 UpdateCheckParams::kOsVersion,
161 "", // os_sp
162 UpdateCheckParams::kAppId,
163 "0.1.0.0",
164 "en-US",
165 "unittest");
166 UpdateCheckResponse response;
167 ASSERT_TRUE(
168 TestUpdateCheckAction(params,
169 GetNoUpdateResponse(UpdateCheckParams::kAppId),
170 true,
171 &response,
172 NULL));
173 EXPECT_FALSE(response.update_exists);
174}
175
176TEST(UpdateCheckActionTest, ValidUpdateTest) {
177 UpdateCheckParams params("machine_id",
178 "user_id",
179 UpdateCheckParams::kOsPlatform,
180 UpdateCheckParams::kOsVersion,
181 "service_pack",
182 UpdateCheckParams::kAppId,
183 "0.1.0.0",
184 "en-US",
185 "unittest_track");
186 UpdateCheckResponse response;
187 ASSERT_TRUE(
188 TestUpdateCheckAction(params,
189 GetUpdateResponse(UpdateCheckParams::kAppId,
190 "1.2.3.4", // version
191 "http://more/info",
192 "true", // prompt
193 "http://code/base", // dl url
194 "HASH1234=", // checksum
195 "false", // needs admin
196 "123"), // size
197 true,
198 &response,
199 NULL));
200 EXPECT_TRUE(response.update_exists);
201 EXPECT_EQ("1.2.3.4", response.display_version);
202 EXPECT_EQ("http://code/base", response.codebase);
203 EXPECT_EQ("http://more/info", response.more_info_url);
204 EXPECT_EQ("HASH1234=", response.hash);
205 EXPECT_EQ(123, response.size);
206 EXPECT_FALSE(response.needs_admin);
207 EXPECT_TRUE(response.prompt);
208}
209
210TEST(UpdateCheckActionTest, NoOutputPipeTest) {
211 UpdateCheckParams params("", // machine_id
212 "", // usr_id
213 UpdateCheckParams::kOsPlatform,
214 UpdateCheckParams::kOsVersion,
215 "", // os_sp
216 UpdateCheckParams::kAppId,
217 "0.1.0.0",
218 "en-US",
219 "unittest");
220 const string http_response(GetNoUpdateResponse(UpdateCheckParams::kAppId));
221
222 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
223
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000224 ObjectFeederAction<UpdateCheckParams> feeder_action;
225 feeder_action.set_obj(params);
226 UpdateCheckAction action(new MockHttpFetcher(http_response.data(),
rspangler@google.com49fdf182009-10-10 00:57:34 +0000227 http_response.size()));
228 UpdateCheckActionTestProcessorDelegate delegate;
229 delegate.loop_ = loop;
230 ActionProcessor processor;
231 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000232 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000233 processor.EnqueueAction(&action);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000234 BondActions(&feeder_action, &action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000235
236 g_timeout_add(0, &StartProcessorInRunLoop, &processor);
237 g_main_loop_run(loop);
238 g_main_loop_unref(loop);
239 EXPECT_FALSE(processor.IsRunning());
240}
241
242TEST(UpdateCheckActionTest, InvalidXmlTest) {
243 UpdateCheckParams params("machine_id",
244 "user_id",
245 UpdateCheckParams::kOsPlatform,
246 UpdateCheckParams::kOsVersion,
247 "service_pack",
248 UpdateCheckParams::kAppId,
249 "0.1.0.0",
250 "en-US",
251 "unittest_track");
252 UpdateCheckResponse response;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700253 ASSERT_FALSE(
rspangler@google.com49fdf182009-10-10 00:57:34 +0000254 TestUpdateCheckAction(params,
255 "invalid xml>",
256 false,
257 &response,
258 NULL));
259 EXPECT_FALSE(response.update_exists);
260}
261
262TEST(UpdateCheckActionTest, MissingStatusTest) {
263 UpdateCheckParams params("machine_id",
264 "user_id",
265 UpdateCheckParams::kOsPlatform,
266 UpdateCheckParams::kOsVersion,
267 "service_pack",
268 UpdateCheckParams::kAppId,
269 "0.1.0.0",
270 "en-US",
271 "unittest_track");
272 UpdateCheckResponse response;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700273 ASSERT_FALSE(TestUpdateCheckAction(
rspangler@google.com49fdf182009-10-10 00:57:34 +0000274 params,
275 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><gupdate "
276 "xmlns=\"http://www.google.com/update2/response\" protocol=\"2.0\"><app "
277 "appid=\"foo\" status=\"ok\"><ping "
278 "status=\"ok\"/><updatecheck/></app></gupdate>",
279 false,
280 &response,
281 NULL));
282 EXPECT_FALSE(response.update_exists);
283}
284
285TEST(UpdateCheckActionTest, InvalidStatusTest) {
286 UpdateCheckParams params("machine_id",
287 "user_id",
288 UpdateCheckParams::kOsPlatform,
289 UpdateCheckParams::kOsVersion,
290 "service_pack",
291 UpdateCheckParams::kAppId,
292 "0.1.0.0",
293 "en-US",
294 "unittest_track");
295 UpdateCheckResponse response;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700296 ASSERT_FALSE(TestUpdateCheckAction(
rspangler@google.com49fdf182009-10-10 00:57:34 +0000297 params,
298 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><gupdate "
299 "xmlns=\"http://www.google.com/update2/response\" protocol=\"2.0\"><app "
300 "appid=\"foo\" status=\"ok\"><ping "
301 "status=\"ok\"/><updatecheck status=\"foo\"/></app></gupdate>",
302 false,
303 &response,
304 NULL));
305 EXPECT_FALSE(response.update_exists);
306}
307
308TEST(UpdateCheckActionTest, MissingNodesetTest) {
309 UpdateCheckParams params("machine_id",
310 "user_id",
311 UpdateCheckParams::kOsPlatform,
312 UpdateCheckParams::kOsVersion,
313 "service_pack",
314 UpdateCheckParams::kAppId,
315 "0.1.0.0",
316 "en-US",
317 "unittest_track");
318 UpdateCheckResponse response;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700319 ASSERT_FALSE(TestUpdateCheckAction(
rspangler@google.com49fdf182009-10-10 00:57:34 +0000320 params,
321 "<?xml version=\"1.0\" encoding=\"UTF-8\"?><gupdate "
322 "xmlns=\"http://www.google.com/update2/response\" protocol=\"2.0\"><app "
323 "appid=\"foo\" status=\"ok\"><ping "
324 "status=\"ok\"/></app></gupdate>",
325 false,
326 &response,
327 NULL));
328 EXPECT_FALSE(response.update_exists);
329}
330
331TEST(UpdateCheckActionTest, MissingFieldTest) {
332 UpdateCheckParams params("machine_id",
333 "user_id",
334 UpdateCheckParams::kOsPlatform,
335 UpdateCheckParams::kOsVersion,
336 "service_pack",
337 UpdateCheckParams::kAppId,
338 "0.1.0.0",
339 "en-US",
340 "unittest_track");
341 UpdateCheckResponse response;
342 ASSERT_TRUE(TestUpdateCheckAction(params,
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000343 string("<?xml version=\"1.0\" "
344 "encoding=\"UTF-8\"?><gupdate "
345 "xmlns=\"http://www.google.com/"
346 "update2/response\" "
347 "protocol=\"2.0\"><app appid=\"") +
348 UpdateCheckParams::kAppId
349 + "\" status=\"ok\"><ping "
350 "status=\"ok\"/><updatecheck "
351 "DisplayVersion=\"1.2.3.4\" "
352 "Prompt=\"false\" "
353 "codebase=\"http://code/base\" "
354 "hash=\"HASH1234=\" needsadmin=\"true\" "
355 "size=\"123\" "
356 "status=\"ok\"/></app></gupdate>",
357 true,
358 &response,
359 NULL));
rspangler@google.com49fdf182009-10-10 00:57:34 +0000360 EXPECT_TRUE(response.update_exists);
361 EXPECT_EQ("1.2.3.4", response.display_version);
362 EXPECT_EQ("http://code/base", response.codebase);
363 EXPECT_EQ("", response.more_info_url);
364 EXPECT_EQ("HASH1234=", response.hash);
365 EXPECT_EQ(123, response.size);
366 EXPECT_TRUE(response.needs_admin);
367 EXPECT_FALSE(response.prompt);
368}
369
370namespace {
371class TerminateEarlyTestProcessorDelegate : public ActionProcessorDelegate {
372 public:
373 void ProcessingStopped(const ActionProcessor* processor) {
374 ASSERT_TRUE(loop_);
375 g_main_loop_quit(loop_);
376 }
377 GMainLoop *loop_;
378};
379
380gboolean TerminateTransferTestStarter(gpointer data) {
381 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
382 processor->StartProcessing();
383 CHECK(processor->IsRunning());
384 processor->StopProcessing();
385 return FALSE;
386}
387} // namespace {}
388
389TEST(UpdateCheckActionTest, TerminateTransferTest) {
390 UpdateCheckParams params("", // machine_id
391 "", // usr_id
392 UpdateCheckParams::kOsPlatform,
393 UpdateCheckParams::kOsVersion,
394 "", // os_sp
395 UpdateCheckParams::kAppId,
396 "0.1.0.0",
397 "en-US",
398 "unittest");
399 string http_response("doesn't matter");
400 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
401
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000402 ObjectFeederAction<UpdateCheckParams> feeder_action;
403 feeder_action.set_obj(params);
404 UpdateCheckAction action(new MockHttpFetcher(http_response.data(),
rspangler@google.com49fdf182009-10-10 00:57:34 +0000405 http_response.size()));
406 TerminateEarlyTestProcessorDelegate delegate;
407 delegate.loop_ = loop;
408 ActionProcessor processor;
409 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000410 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000411 processor.EnqueueAction(&action);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000412 BondActions(&feeder_action, &action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000413
414 g_timeout_add(0, &TerminateTransferTestStarter, &processor);
415 g_main_loop_run(loop);
416 g_main_loop_unref(loop);
417}
418
419TEST(UpdateCheckActionTest, XmlEncodeTest) {
420 EXPECT_EQ("ab", XmlEncode("ab"));
421 EXPECT_EQ("a&lt;b", XmlEncode("a<b"));
422 EXPECT_EQ("foo-&#x3A9;", XmlEncode("foo-\xce\xa9"));
423 EXPECT_EQ("&lt;&amp;&gt;", XmlEncode("<&>"));
424 EXPECT_EQ("&amp;lt;&amp;amp;&amp;gt;", XmlEncode("&lt;&amp;&gt;"));
425
426 vector<char> post_data;
427
428 // Make sure XML Encode is being called on the params
429 UpdateCheckParams params("testthemachine<id",
430 "testtheuser_id&lt;",
431 UpdateCheckParams::kOsPlatform,
432 UpdateCheckParams::kOsVersion,
433 "testtheservice_pack>",
434 UpdateCheckParams::kAppId,
435 "0.1.0.0",
436 "en-US",
437 "unittest_track");
438 UpdateCheckResponse response;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700439 ASSERT_FALSE(
rspangler@google.com49fdf182009-10-10 00:57:34 +0000440 TestUpdateCheckAction(params,
441 "invalid xml>",
442 false,
443 &response,
444 &post_data));
445 // convert post_data to string
446 string post_str(&post_data[0], post_data.size());
447 EXPECT_NE(post_str.find("testthemachine&lt;id"), string::npos);
448 EXPECT_EQ(post_str.find("testthemachine<id"), string::npos);
449 EXPECT_NE(post_str.find("testtheuser_id&amp;lt;"), string::npos);
450 EXPECT_EQ(post_str.find("testtheuser_id&lt;"), string::npos);
451 EXPECT_NE(post_str.find("testtheservice_pack&gt;"), string::npos);
452 EXPECT_EQ(post_str.find("testtheservice_pack>"), string::npos);
453}
454
455TEST(UpdateCheckActionTest, XmlDecodeTest) {
456 UpdateCheckParams params("machine_id",
457 "user_id",
458 UpdateCheckParams::kOsPlatform,
459 UpdateCheckParams::kOsVersion,
460 "service_pack",
461 UpdateCheckParams::kAppId,
462 "0.1.0.0",
463 "en-US",
464 "unittest_track");
465 UpdateCheckResponse response;
466 ASSERT_TRUE(
467 TestUpdateCheckAction(params,
468 GetUpdateResponse(UpdateCheckParams::kAppId,
469 "1.2.3.4", // version
470 "testthe&lt;url", // more info
471 "true", // prompt
472 "testthe&amp;codebase", // dl url
473 "HASH1234=", // checksum
474 "false", // needs admin
475 "123"), // size
476 true,
477 &response,
478 NULL));
479
480 EXPECT_EQ(response.more_info_url, "testthe<url");
481 EXPECT_EQ(response.codebase, "testthe&codebase");
482}
483
484TEST(UpdateCheckActionTest, ParseIntTest) {
485 UpdateCheckParams params("machine_id",
486 "user_id",
487 UpdateCheckParams::kOsPlatform,
488 UpdateCheckParams::kOsVersion,
489 "service_pack",
490 UpdateCheckParams::kAppId,
491 "0.1.0.0",
492 "en-US",
493 "unittest_track");
494 UpdateCheckResponse response;
495 ASSERT_TRUE(
496 TestUpdateCheckAction(params,
497 GetUpdateResponse(UpdateCheckParams::kAppId,
498 "1.2.3.4", // version
499 "theurl", // more info
500 "true", // prompt
501 "thecodebase", // dl url
502 "HASH1234=", // checksum
503 "false", // needs admin
504 // overflows int32:
505 "123123123123123"), // size
506 true,
507 &response,
508 NULL));
509
510 EXPECT_EQ(response.size, 123123123123123ll);
511}
512
513} // namespace chromeos_update_engine