blob: 63535843f624773a3ed0740736e8addc35735109 [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:
26 DownloadActionTestProcessorDelegate()
27 : loop_(NULL), processing_done_called_(false) {}
28 virtual ~DownloadActionTestProcessorDelegate() {
29 EXPECT_TRUE(processing_done_called_);
30 }
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -080031 virtual void ProcessingDone(const ActionProcessor* processor, bool success) {
rspangler@google.com49fdf182009-10-10 00:57:34 +000032 ASSERT_TRUE(loop_);
33 g_main_loop_quit(loop_);
adlr@google.comc98a7ed2009-12-04 18:54:03 +000034 vector<char> found_data;
35 ASSERT_TRUE(utils::ReadFile(path_, &found_data));
rspangler@google.com49fdf182009-10-10 00:57:34 +000036 ASSERT_EQ(expected_data_.size(), found_data.size());
37 for (unsigned i = 0; i < expected_data_.size(); i++) {
38 EXPECT_EQ(expected_data_[i], found_data[i]);
39 }
40 processing_done_called_ = true;
41 }
42
adlr@google.comc98a7ed2009-12-04 18:54:03 +000043 virtual void ActionCompleted(ActionProcessor* processor,
44 AbstractAction* action,
rspangler@google.com49fdf182009-10-10 00:57:34 +000045 bool success) {
46 // make sure actions always succeed
47 EXPECT_TRUE(success);
48 }
49
50 GMainLoop *loop_;
51 string path_;
52 vector<char> expected_data_;
53 bool processing_done_called_;
54};
55
56struct EntryPointArgs {
57 const vector<char> *data;
58 GMainLoop *loop;
59 ActionProcessor *processor;
60};
61
62gboolean StartProcessorInRunLoop(gpointer data) {
63 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
64 processor->StartProcessing();
65 return FALSE;
66}
67
Andrew de los Reyesf9185172010-05-03 11:07:05 -070068void TestWithData(const vector<char>& data) {
rspangler@google.com49fdf182009-10-10 00:57:34 +000069 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
70
71 // TODO(adlr): see if we need a different file for build bots
Andrew de los Reyesf9185172010-05-03 11:07:05 -070072 ScopedTempFile output_temp_file;
73 DirectFileWriter writer;
74
rspangler@google.com49fdf182009-10-10 00:57:34 +000075 // takes ownership of passed in HttpFetcher
Andrew de los Reyesf9185172010-05-03 11:07:05 -070076 InstallPlan install_plan(true,
77 "",
78 OmahaHashCalculator::OmahaHashOfData(data),
79 output_temp_file.GetPath(),
80 "");
adlr@google.comc98a7ed2009-12-04 18:54:03 +000081 ObjectFeederAction<InstallPlan> feeder_action;
82 feeder_action.set_obj(install_plan);
Andrew de los Reyesf9185172010-05-03 11:07:05 -070083 DownloadAction download_action(new MockHttpFetcher(&data[0],
84 data.size()));
85 download_action.SetTestFileWriter(&writer);
adlr@google.comc98a7ed2009-12-04 18:54:03 +000086 BondActions(&feeder_action, &download_action);
87
rspangler@google.com49fdf182009-10-10 00:57:34 +000088 DownloadActionTestProcessorDelegate delegate;
89 delegate.loop_ = loop;
90 delegate.expected_data_ = data;
Andrew de los Reyesf9185172010-05-03 11:07:05 -070091 delegate.path_ = output_temp_file.GetPath();
rspangler@google.com49fdf182009-10-10 00:57:34 +000092 ActionProcessor processor;
93 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +000094 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +000095 processor.EnqueueAction(&download_action);
96
97 g_timeout_add(0, &StartProcessorInRunLoop, &processor);
98 g_main_loop_run(loop);
99 g_main_loop_unref(loop);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000100}
101} // namespace {}
102
103TEST(DownloadActionTest, SimpleTest) {
104 vector<char> small;
105 const char* foo = "foo";
106 small.insert(small.end(), foo, foo + strlen(foo));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700107 TestWithData(small);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000108}
109
110TEST(DownloadActionTest, LargeTest) {
111 vector<char> big(5 * kMockHttpFetcherChunkSize);
112 char c = '0';
113 for (unsigned int i = 0; i < big.size(); i++) {
114 big[i] = c;
115 if ('9' == c)
116 c = '0';
117 else
118 c++;
119 }
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700120 TestWithData(big);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000121}
122
123namespace {
124class TerminateEarlyTestProcessorDelegate : public ActionProcessorDelegate {
125 public:
126 void ProcessingStopped(const ActionProcessor* processor) {
127 ASSERT_TRUE(loop_);
128 g_main_loop_quit(loop_);
129 }
130 GMainLoop *loop_;
131};
132
133gboolean TerminateEarlyTestStarter(gpointer data) {
134 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
135 processor->StartProcessing();
136 CHECK(processor->IsRunning());
137 processor->StopProcessing();
138 return FALSE;
139}
140
141} // namespace {}
142
143TEST(DownloadActionTest, TerminateEarlyTest) {
144 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
145
146 vector<char> data(kMockHttpFetcherChunkSize + kMockHttpFetcherChunkSize / 2);
147 memset(&data[0], 0, data.size());
148
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700149 ScopedTempFile temp_file;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000150 {
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700151 DirectFileWriter writer;
152
rspangler@google.com49fdf182009-10-10 00:57:34 +0000153 // takes ownership of passed in HttpFetcher
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000154 ObjectFeederAction<InstallPlan> feeder_action;
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700155 InstallPlan install_plan(true, "", "", temp_file.GetPath(), "");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000156 feeder_action.set_obj(install_plan);
157 DownloadAction download_action(new MockHttpFetcher(&data[0], data.size()));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700158 download_action.SetTestFileWriter(&writer);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000159 TerminateEarlyTestProcessorDelegate delegate;
160 delegate.loop_ = loop;
161 ActionProcessor processor;
162 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000163 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000164 processor.EnqueueAction(&download_action);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000165 BondActions(&feeder_action, &download_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000166
167 g_timeout_add(0, &TerminateEarlyTestStarter, &processor);
168 g_main_loop_run(loop);
169 g_main_loop_unref(loop);
170 }
171
172 // 1 or 0 chunks should have come through
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700173 const off_t resulting_file_size(utils::FileSize(temp_file.GetPath()));
174 EXPECT_GE(resulting_file_size, 0);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000175 if (resulting_file_size != 0)
176 EXPECT_EQ(kMockHttpFetcherChunkSize, resulting_file_size);
177}
178
179class DownloadActionTestAction;
180
181template<>
182class ActionTraits<DownloadActionTestAction> {
183 public:
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000184 typedef InstallPlan OutputObjectType;
185 typedef InstallPlan InputObjectType;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000186};
187
188// This is a simple Action class for testing.
189struct DownloadActionTestAction : public Action<DownloadActionTestAction> {
190 DownloadActionTestAction() : did_run_(false) {}
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000191 typedef InstallPlan InputObjectType;
192 typedef InstallPlan OutputObjectType;
193 ActionPipe<InstallPlan>* in_pipe() { return in_pipe_.get(); }
194 ActionPipe<InstallPlan>* out_pipe() { return out_pipe_.get(); }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000195 ActionProcessor* processor() { return processor_; }
196 void PerformAction() {
197 did_run_ = true;
198 ASSERT_TRUE(HasInputObject());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000199 EXPECT_TRUE(expected_input_object_ == GetInputObject());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000200 ASSERT_TRUE(processor());
201 processor()->ActionComplete(this, true);
202 }
203 string Type() const { return "DownloadActionTestAction"; }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000204 InstallPlan expected_input_object_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000205 bool did_run_;
206};
207
208namespace {
209// This class is an ActionProcessorDelegate that simply terminates the
210// run loop when the ActionProcessor has completed processing. It's used
211// only by the test PassObjectOutTest.
212class PassObjectOutTestProcessorDelegate : public ActionProcessorDelegate {
213 public:
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800214 void ProcessingDone(const ActionProcessor* processor, bool success) {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000215 ASSERT_TRUE(loop_);
216 g_main_loop_quit(loop_);
217 }
218 GMainLoop *loop_;
219};
220
221gboolean PassObjectOutTestStarter(gpointer data) {
222 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
223 processor->StartProcessing();
224 return FALSE;
225}
226}
227
228TEST(DownloadActionTest, PassObjectOutTest) {
229 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
230
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700231 DirectFileWriter writer;
232
rspangler@google.com49fdf182009-10-10 00:57:34 +0000233 // takes ownership of passed in HttpFetcher
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700234 InstallPlan install_plan(true,
235 "",
Andrew de los Reyes1e338b82010-01-22 14:57:27 -0800236 OmahaHashCalculator::OmahaHashOfString("x"),
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700237 "/dev/null",
Andrew de los Reyes1e338b82010-01-22 14:57:27 -0800238 "/dev/null");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000239 ObjectFeederAction<InstallPlan> feeder_action;
240 feeder_action.set_obj(install_plan);
241 DownloadAction download_action(new MockHttpFetcher("x", 1));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700242 download_action.SetTestFileWriter(&writer);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000243
244 DownloadActionTestAction test_action;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000245 test_action.expected_input_object_ = install_plan;
246 BondActions(&feeder_action, &download_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000247 BondActions(&download_action, &test_action);
248
249 ActionProcessor processor;
250 PassObjectOutTestProcessorDelegate delegate;
251 delegate.loop_ = loop;
252 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000253 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000254 processor.EnqueueAction(&download_action);
255 processor.EnqueueAction(&test_action);
256
257 g_timeout_add(0, &PassObjectOutTestStarter, &processor);
258 g_main_loop_run(loop);
259 g_main_loop_unref(loop);
260
261 EXPECT_EQ(true, test_action.did_run_);
262}
263
264TEST(DownloadActionTest, BadOutFileTest) {
265 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
266
267 const string path("/fake/path/that/cant/be/created/because/of/missing/dirs");
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700268 DirectFileWriter writer;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000269
270 // takes ownership of passed in HttpFetcher
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700271 InstallPlan install_plan(true, "", "", path, "");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000272 ObjectFeederAction<InstallPlan> feeder_action;
273 feeder_action.set_obj(install_plan);
274 DownloadAction download_action(new MockHttpFetcher("x", 1));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700275 download_action.SetTestFileWriter(&writer);
276
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000277 BondActions(&feeder_action, &download_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000278
279 ActionProcessor processor;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000280 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000281 processor.EnqueueAction(&download_action);
282 processor.StartProcessing();
283 ASSERT_FALSE(processor.IsRunning());
284
285 g_main_loop_unref(loop);
286}
287
288} // namespace chromeos_update_engine