blob: 778f408e268f2a7e46ca6e01e1c4539eca3f13c4 [file] [log] [blame]
Darin Petkov6a5b3222010-07-13 14:55:28 -07001// 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/mock_http_fetcher.h"
11#include "update_engine/omaha_hash_calculator.h"
12#include "update_engine/omaha_request_action.h"
13#include "update_engine/test_utils.h"
14
15using std::string;
16using std::vector;
17
18namespace chromeos_update_engine {
19
20class OmahaRequestActionTest : 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 "
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
50class OmahaRequestActionTestProcessorDelegate : public ActionProcessorDelegate {
51 public:
52 OmahaRequestActionTestProcessorDelegate()
53 : loop_(NULL),
54 expected_success_(true) {}
55 virtual ~OmahaRequestActionTestProcessorDelegate() {
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() == OmahaRequestAction::StaticType())
67 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 OmahaResponse InputObjectType;
90 // On success, puts the output path on output
91 typedef NoneType OutputObjectType;
92};
93
94class 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 omaha_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 OmahaResponse omaha_response_;
115};
116
117// returns true iff an output response was obtained from the
118// OmahaRequestAction. 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 TestOmahaRequestAction(const OmahaRequestParams& params,
122 const string& http_response,
123 bool expected_success,
124 OmahaResponse* 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<OmahaRequestParams> feeder_action;
130 OmahaRequestAction action(fetcher); // takes ownership of fetcher
131 OmahaRequestActionTestProcessorDelegate 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.omaha_response_;
151 if (out_post_data)
152 *out_post_data = fetcher->post_data();
153 return collector_action.has_input_object_;
154}
155
156TEST(OmahaRequestActionTest, NoUpdateTest) {
157 OmahaRequestParams params("", // machine_id
158 "", // user_id
159 OmahaRequestParams::kOsPlatform,
160 OmahaRequestParams::kOsVersion,
161 "", // os_sp
162 "x86-generic",
163 OmahaRequestParams::kAppId,
164 "0.1.0.0",
165 "en-US",
166 "unittest",
167 ""); // url
168 OmahaResponse response;
169 ASSERT_TRUE(
170 TestOmahaRequestAction(params,
171 GetNoUpdateResponse(OmahaRequestParams::kAppId),
172 true,
173 &response,
174 NULL));
175 EXPECT_FALSE(response.update_exists);
176}
177
178TEST(OmahaRequestActionTest, ValidUpdateTest) {
179 OmahaRequestParams params("machine_id",
180 "user_id",
181 OmahaRequestParams::kOsPlatform,
182 OmahaRequestParams::kOsVersion,
183 "service_pack",
184 "arm-generic",
185 OmahaRequestParams::kAppId,
186 "0.1.0.0",
187 "en-US",
188 "unittest_track",
189 ""); // url
190 OmahaResponse response;
191 ASSERT_TRUE(
192 TestOmahaRequestAction(params,
193 GetUpdateResponse(OmahaRequestParams::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
214TEST(OmahaRequestActionTest, NoOutputPipeTest) {
215 OmahaRequestParams params("", // machine_id
216 "", // usr_id
217 OmahaRequestParams::kOsPlatform,
218 OmahaRequestParams::kOsVersion,
219 "", // os_sp
220 "", // os_board
221 OmahaRequestParams::kAppId,
222 "0.1.0.0",
223 "en-US",
224 "unittest",
225 ""); // url
226 const string http_response(GetNoUpdateResponse(OmahaRequestParams::kAppId));
227
228 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
229
230 ObjectFeederAction<OmahaRequestParams> feeder_action;
231 feeder_action.set_obj(params);
232 OmahaRequestAction action(new MockHttpFetcher(http_response.data(),
233 http_response.size()));
234 OmahaRequestActionTestProcessorDelegate 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
248TEST(OmahaRequestActionTest, InvalidXmlTest) {
249 OmahaRequestParams params("machine_id",
250 "user_id",
251 OmahaRequestParams::kOsPlatform,
252 OmahaRequestParams::kOsVersion,
253 "service_pack",
254 "x86-generic",
255 OmahaRequestParams::kAppId,
256 "0.1.0.0",
257 "en-US",
258 "unittest_track",
259 "http://url");
260 OmahaResponse response;
261 ASSERT_FALSE(
262 TestOmahaRequestAction(params,
263 "invalid xml>",
264 false,
265 &response,
266 NULL));
267 EXPECT_FALSE(response.update_exists);
268}
269
270TEST(OmahaRequestActionTest, MissingStatusTest) {
271 OmahaRequestParams params("machine_id",
272 "user_id",
273 OmahaRequestParams::kOsPlatform,
274 OmahaRequestParams::kOsVersion,
275 "service_pack",
276 "x86-generic",
277 OmahaRequestParams::kAppId,
278 "0.1.0.0",
279 "en-US",
280 "unittest_track",
281 "http://url");
282 OmahaResponse response;
283 ASSERT_FALSE(TestOmahaRequestAction(
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
295TEST(OmahaRequestActionTest, InvalidStatusTest) {
296 OmahaRequestParams params("machine_id",
297 "user_id",
298 OmahaRequestParams::kOsPlatform,
299 OmahaRequestParams::kOsVersion,
300 "service_pack",
301 "x86-generic",
302 OmahaRequestParams::kAppId,
303 "0.1.0.0",
304 "en-US",
305 "unittest_track",
306 "http://url");
307 OmahaResponse response;
308 ASSERT_FALSE(TestOmahaRequestAction(
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
320TEST(OmahaRequestActionTest, MissingNodesetTest) {
321 OmahaRequestParams params("machine_id",
322 "user_id",
323 OmahaRequestParams::kOsPlatform,
324 OmahaRequestParams::kOsVersion,
325 "service_pack",
326 "x86-generic",
327 OmahaRequestParams::kAppId,
328 "0.1.0.0",
329 "en-US",
330 "unittest_track",
331 "http://url");
332 OmahaResponse response;
333 ASSERT_FALSE(TestOmahaRequestAction(
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
345TEST(OmahaRequestActionTest, MissingFieldTest) {
346 OmahaRequestParams params("machine_id",
347 "user_id",
348 OmahaRequestParams::kOsPlatform,
349 OmahaRequestParams::kOsVersion,
350 "service_pack",
351 "x86-generic",
352 OmahaRequestParams::kAppId,
353 "0.1.0.0",
354 "en-US",
355 "unittest_track",
356 "http://url");
357 OmahaResponse response;
358 ASSERT_TRUE(TestOmahaRequestAction(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 OmahaRequestParams::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
386namespace {
387class 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
396gboolean 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
405TEST(OmahaRequestActionTest, TerminateTransferTest) {
406 OmahaRequestParams params("", // machine_id
407 "", // usr_id
408 OmahaRequestParams::kOsPlatform,
409 OmahaRequestParams::kOsVersion,
410 "", // os_sp
411 "", // os_board
412 OmahaRequestParams::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<OmahaRequestParams> feeder_action;
421 feeder_action.set_obj(params);
422 OmahaRequestAction 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
437TEST(OmahaRequestActionTest, XmlEncodeTest) {
438 EXPECT_EQ("ab", XmlEncode("ab"));
439 EXPECT_EQ("a&lt;b", XmlEncode("a<b"));
440 EXPECT_EQ("foo-&#x3A9;", XmlEncode("foo-\xce\xa9"));
441 EXPECT_EQ("&lt;&amp;&gt;", XmlEncode("<&>"));
442 EXPECT_EQ("&amp;lt;&amp;amp;&amp;gt;", XmlEncode("&lt;&amp;&gt;"));
443
444 vector<char> post_data;
445
446 // Make sure XML Encode is being called on the params
447 OmahaRequestParams params("testthemachine<id",
448 "testtheuser_id&lt;",
449 OmahaRequestParams::kOsPlatform,
450 OmahaRequestParams::kOsVersion,
451 "testtheservice_pack>",
452 "x86 generic",
453 OmahaRequestParams::kAppId,
454 "0.1.0.0",
455 "en-US",
456 "unittest_track",
457 "http://url");
458 OmahaResponse response;
459 ASSERT_FALSE(
460 TestOmahaRequestAction(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&lt;id"), string::npos);
468 EXPECT_EQ(post_str.find("testthemachine<id"), string::npos);
469 EXPECT_NE(post_str.find("testtheuser_id&amp;lt;"), string::npos);
470 EXPECT_EQ(post_str.find("testtheuser_id&lt;"), string::npos);
471 EXPECT_NE(post_str.find("testtheservice_pack&gt;"), string::npos);
472 EXPECT_EQ(post_str.find("testtheservice_pack>"), string::npos);
473 EXPECT_NE(post_str.find("x86 generic"), string::npos);
474}
475
476TEST(OmahaRequestActionTest, XmlDecodeTest) {
477 OmahaRequestParams params("machine_id",
478 "user_id",
479 OmahaRequestParams::kOsPlatform,
480 OmahaRequestParams::kOsVersion,
481 "service_pack",
482 "x86-generic",
483 OmahaRequestParams::kAppId,
484 "0.1.0.0",
485 "en-US",
486 "unittest_track",
487 "http://url");
488 OmahaResponse response;
489 ASSERT_TRUE(
490 TestOmahaRequestAction(params,
491 GetUpdateResponse(OmahaRequestParams::kAppId,
492 "1.2.3.4", // version
493 "testthe&lt;url", // more info
494 "true", // prompt
495 "testthe&amp;code", // 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&code");
505}
506
507TEST(OmahaRequestActionTest, ParseIntTest) {
508 OmahaRequestParams params("machine_id",
509 "user_id",
510 OmahaRequestParams::kOsPlatform,
511 OmahaRequestParams::kOsVersion,
512 "service_pack",
513 "the_board",
514 OmahaRequestParams::kAppId,
515 "0.1.0.0",
516 "en-US",
517 "unittest_track",
518 "http://url");
519 OmahaResponse response;
520 ASSERT_TRUE(
521 TestOmahaRequestAction(params,
522 GetUpdateResponse(OmahaRequestParams::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