blob: 4e11626dc97268a26bfbdce037122339011a816f [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>
6#include <vector>
7#include <glib.h>
8#include <gtest/gtest.h>
9#include "update_engine/action_pipe.h"
10#include "update_engine/download_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"
adlr@google.comc98a7ed2009-12-04 18:54:03 +000014#include "update_engine/utils.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000015
16namespace chromeos_update_engine {
17
18using std::string;
19using std::vector;
20
21class DownloadActionTest : public ::testing::Test { };
22
23namespace {
24class DownloadActionTestProcessorDelegate : public ActionProcessorDelegate {
25 public:
Darin Petkovc97435c2010-07-20 12:37:43 -070026 explicit DownloadActionTestProcessorDelegate(ActionExitCode expected_code)
27 : loop_(NULL),
28 processing_done_called_(false),
29 expected_code_(expected_code) {}
rspangler@google.com49fdf182009-10-10 00:57:34 +000030 virtual ~DownloadActionTestProcessorDelegate() {
31 EXPECT_TRUE(processing_done_called_);
32 }
Darin Petkovc1a8b422010-07-19 11:34:49 -070033 virtual void ProcessingDone(const ActionProcessor* processor,
34 ActionExitCode code) {
rspangler@google.com49fdf182009-10-10 00:57:34 +000035 ASSERT_TRUE(loop_);
36 g_main_loop_quit(loop_);
adlr@google.comc98a7ed2009-12-04 18:54:03 +000037 vector<char> found_data;
38 ASSERT_TRUE(utils::ReadFile(path_, &found_data));
rspangler@google.com49fdf182009-10-10 00:57:34 +000039 ASSERT_EQ(expected_data_.size(), found_data.size());
40 for (unsigned i = 0; i < expected_data_.size(); i++) {
41 EXPECT_EQ(expected_data_[i], found_data[i]);
42 }
43 processing_done_called_ = true;
44 }
45
adlr@google.comc98a7ed2009-12-04 18:54:03 +000046 virtual void ActionCompleted(ActionProcessor* processor,
47 AbstractAction* action,
Darin Petkovc1a8b422010-07-19 11:34:49 -070048 ActionExitCode code) {
Darin Petkovc97435c2010-07-20 12:37:43 -070049 const string type = action->Type();
50 if (type == DownloadAction::StaticType()) {
51 EXPECT_EQ(expected_code_, code);
52 } else {
53 EXPECT_EQ(kActionCodeSuccess, code);
54 }
rspangler@google.com49fdf182009-10-10 00:57:34 +000055 }
56
57 GMainLoop *loop_;
58 string path_;
59 vector<char> expected_data_;
60 bool processing_done_called_;
Darin Petkovc97435c2010-07-20 12:37:43 -070061 ActionExitCode expected_code_;
rspangler@google.com49fdf182009-10-10 00:57:34 +000062};
63
64struct EntryPointArgs {
65 const vector<char> *data;
66 GMainLoop *loop;
67 ActionProcessor *processor;
68};
69
70gboolean StartProcessorInRunLoop(gpointer data) {
71 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
72 processor->StartProcessing();
73 return FALSE;
74}
75
Darin Petkovc97435c2010-07-20 12:37:43 -070076void TestWithData(const vector<char>& data, bool hash_test) {
rspangler@google.com49fdf182009-10-10 00:57:34 +000077 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
78
79 // TODO(adlr): see if we need a different file for build bots
Andrew de los Reyesf9185172010-05-03 11:07:05 -070080 ScopedTempFile output_temp_file;
81 DirectFileWriter writer;
82
rspangler@google.com49fdf182009-10-10 00:57:34 +000083 // takes ownership of passed in HttpFetcher
Darin Petkovc97435c2010-07-20 12:37:43 -070084 string hash = hash_test ?
85 OmahaHashCalculator::OmahaHashOfString("random string") :
86 OmahaHashCalculator::OmahaHashOfData(data);
Andrew de los Reyesf9185172010-05-03 11:07:05 -070087 InstallPlan install_plan(true,
88 "",
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070089 0,
Darin Petkovc97435c2010-07-20 12:37:43 -070090 hash,
Andrew de los Reyesf9185172010-05-03 11:07:05 -070091 output_temp_file.GetPath(),
92 "");
adlr@google.comc98a7ed2009-12-04 18:54:03 +000093 ObjectFeederAction<InstallPlan> feeder_action;
94 feeder_action.set_obj(install_plan);
Andrew de los Reyesf9185172010-05-03 11:07:05 -070095 DownloadAction download_action(new MockHttpFetcher(&data[0],
96 data.size()));
97 download_action.SetTestFileWriter(&writer);
adlr@google.comc98a7ed2009-12-04 18:54:03 +000098 BondActions(&feeder_action, &download_action);
99
Darin Petkovc97435c2010-07-20 12:37:43 -0700100 DownloadActionTestProcessorDelegate delegate(
101 hash_test ? kActionCodeDownloadHashMismatchError : kActionCodeSuccess);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000102 delegate.loop_ = loop;
103 delegate.expected_data_ = data;
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700104 delegate.path_ = output_temp_file.GetPath();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000105 ActionProcessor processor;
106 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000107 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000108 processor.EnqueueAction(&download_action);
109
110 g_timeout_add(0, &StartProcessorInRunLoop, &processor);
111 g_main_loop_run(loop);
112 g_main_loop_unref(loop);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000113}
114} // namespace {}
115
116TEST(DownloadActionTest, SimpleTest) {
117 vector<char> small;
118 const char* foo = "foo";
119 small.insert(small.end(), foo, foo + strlen(foo));
Darin Petkovc97435c2010-07-20 12:37:43 -0700120 TestWithData(small, false);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000121}
122
123TEST(DownloadActionTest, LargeTest) {
124 vector<char> big(5 * kMockHttpFetcherChunkSize);
125 char c = '0';
126 for (unsigned int i = 0; i < big.size(); i++) {
127 big[i] = c;
128 if ('9' == c)
129 c = '0';
130 else
131 c++;
132 }
Darin Petkovc97435c2010-07-20 12:37:43 -0700133 TestWithData(big, false);
134}
135
136TEST(DownloadActionTest, BadHashTest) {
137 vector<char> small;
138 const char* foo = "foo";
139 small.insert(small.end(), foo, foo + strlen(foo));
140 TestWithData(small, true);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000141}
142
143namespace {
144class TerminateEarlyTestProcessorDelegate : public ActionProcessorDelegate {
145 public:
146 void ProcessingStopped(const ActionProcessor* processor) {
147 ASSERT_TRUE(loop_);
148 g_main_loop_quit(loop_);
149 }
150 GMainLoop *loop_;
151};
152
153gboolean TerminateEarlyTestStarter(gpointer data) {
154 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
155 processor->StartProcessing();
156 CHECK(processor->IsRunning());
157 processor->StopProcessing();
158 return FALSE;
159}
160
161} // namespace {}
162
163TEST(DownloadActionTest, TerminateEarlyTest) {
164 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
165
166 vector<char> data(kMockHttpFetcherChunkSize + kMockHttpFetcherChunkSize / 2);
167 memset(&data[0], 0, data.size());
168
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700169 ScopedTempFile temp_file;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000170 {
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700171 DirectFileWriter writer;
172
rspangler@google.com49fdf182009-10-10 00:57:34 +0000173 // takes ownership of passed in HttpFetcher
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000174 ObjectFeederAction<InstallPlan> feeder_action;
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700175 InstallPlan install_plan(true, "", 0, "", temp_file.GetPath(), "");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000176 feeder_action.set_obj(install_plan);
177 DownloadAction download_action(new MockHttpFetcher(&data[0], data.size()));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700178 download_action.SetTestFileWriter(&writer);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000179 TerminateEarlyTestProcessorDelegate delegate;
180 delegate.loop_ = loop;
181 ActionProcessor processor;
182 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000183 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000184 processor.EnqueueAction(&download_action);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000185 BondActions(&feeder_action, &download_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000186
187 g_timeout_add(0, &TerminateEarlyTestStarter, &processor);
188 g_main_loop_run(loop);
189 g_main_loop_unref(loop);
190 }
191
192 // 1 or 0 chunks should have come through
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700193 const off_t resulting_file_size(utils::FileSize(temp_file.GetPath()));
194 EXPECT_GE(resulting_file_size, 0);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000195 if (resulting_file_size != 0)
196 EXPECT_EQ(kMockHttpFetcherChunkSize, resulting_file_size);
197}
198
199class DownloadActionTestAction;
200
201template<>
202class ActionTraits<DownloadActionTestAction> {
203 public:
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000204 typedef InstallPlan OutputObjectType;
205 typedef InstallPlan InputObjectType;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000206};
207
208// This is a simple Action class for testing.
209struct DownloadActionTestAction : public Action<DownloadActionTestAction> {
210 DownloadActionTestAction() : did_run_(false) {}
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000211 typedef InstallPlan InputObjectType;
212 typedef InstallPlan OutputObjectType;
213 ActionPipe<InstallPlan>* in_pipe() { return in_pipe_.get(); }
214 ActionPipe<InstallPlan>* out_pipe() { return out_pipe_.get(); }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000215 ActionProcessor* processor() { return processor_; }
216 void PerformAction() {
217 did_run_ = true;
218 ASSERT_TRUE(HasInputObject());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000219 EXPECT_TRUE(expected_input_object_ == GetInputObject());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000220 ASSERT_TRUE(processor());
Darin Petkovc1a8b422010-07-19 11:34:49 -0700221 processor()->ActionComplete(this, kActionCodeSuccess);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000222 }
223 string Type() const { return "DownloadActionTestAction"; }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000224 InstallPlan expected_input_object_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000225 bool did_run_;
226};
227
228namespace {
229// This class is an ActionProcessorDelegate that simply terminates the
230// run loop when the ActionProcessor has completed processing. It's used
231// only by the test PassObjectOutTest.
232class PassObjectOutTestProcessorDelegate : public ActionProcessorDelegate {
233 public:
Darin Petkovc1a8b422010-07-19 11:34:49 -0700234 void ProcessingDone(const ActionProcessor* processor, ActionExitCode code) {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000235 ASSERT_TRUE(loop_);
236 g_main_loop_quit(loop_);
237 }
238 GMainLoop *loop_;
239};
240
241gboolean PassObjectOutTestStarter(gpointer data) {
242 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
243 processor->StartProcessing();
244 return FALSE;
245}
246}
247
248TEST(DownloadActionTest, PassObjectOutTest) {
249 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
250
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700251 DirectFileWriter writer;
252
rspangler@google.com49fdf182009-10-10 00:57:34 +0000253 // takes ownership of passed in HttpFetcher
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700254 InstallPlan install_plan(true,
255 "",
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700256 0,
Andrew de los Reyes1e338b82010-01-22 14:57:27 -0800257 OmahaHashCalculator::OmahaHashOfString("x"),
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700258 "/dev/null",
Andrew de los Reyes1e338b82010-01-22 14:57:27 -0800259 "/dev/null");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000260 ObjectFeederAction<InstallPlan> feeder_action;
261 feeder_action.set_obj(install_plan);
262 DownloadAction download_action(new MockHttpFetcher("x", 1));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700263 download_action.SetTestFileWriter(&writer);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000264
265 DownloadActionTestAction test_action;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000266 test_action.expected_input_object_ = install_plan;
267 BondActions(&feeder_action, &download_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000268 BondActions(&download_action, &test_action);
269
270 ActionProcessor processor;
271 PassObjectOutTestProcessorDelegate delegate;
272 delegate.loop_ = loop;
273 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000274 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000275 processor.EnqueueAction(&download_action);
276 processor.EnqueueAction(&test_action);
277
278 g_timeout_add(0, &PassObjectOutTestStarter, &processor);
279 g_main_loop_run(loop);
280 g_main_loop_unref(loop);
281
282 EXPECT_EQ(true, test_action.did_run_);
283}
284
285TEST(DownloadActionTest, BadOutFileTest) {
286 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
287
288 const string path("/fake/path/that/cant/be/created/because/of/missing/dirs");
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700289 DirectFileWriter writer;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000290
291 // takes ownership of passed in HttpFetcher
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700292 InstallPlan install_plan(true, "", 0, "", path, "");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000293 ObjectFeederAction<InstallPlan> feeder_action;
294 feeder_action.set_obj(install_plan);
295 DownloadAction download_action(new MockHttpFetcher("x", 1));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700296 download_action.SetTestFileWriter(&writer);
Darin Petkovc1a8b422010-07-19 11:34:49 -0700297
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000298 BondActions(&feeder_action, &download_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000299
300 ActionProcessor processor;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000301 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000302 processor.EnqueueAction(&download_action);
303 processor.StartProcessing();
304 ASSERT_FALSE(processor.IsRunning());
305
306 g_main_loop_unref(loop);
307}
308
309} // namespace chromeos_update_engine