blob: 4276dc9d1d3b85987dfa111a16c1a65e58c830c6 [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 }
31 virtual void ProcessingDone(const ActionProcessor* processor) {
32 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
68void TestWithData(const vector<char>& data, bool compress) {
69 vector<char> use_data;
70 if (compress) {
71 use_data = GzipCompressData(data);
72 } else {
73 use_data = data;
74 }
75
76 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
77
78 // TODO(adlr): see if we need a different file for build bots
79 const string path("/tmp/DownloadActionTest");
80 // takes ownership of passed in HttpFetcher
adlr@google.comc98a7ed2009-12-04 18:54:03 +000081 InstallPlan install_plan(compress, "",
82 OmahaHashCalculator::OmahaHashOfData(use_data),
83 compress ? "" : path, compress ? path : "");
84 ObjectFeederAction<InstallPlan> feeder_action;
85 feeder_action.set_obj(install_plan);
86 DownloadAction download_action(new MockHttpFetcher(&use_data[0],
87 use_data.size()));
88 BondActions(&feeder_action, &download_action);
89
rspangler@google.com49fdf182009-10-10 00:57:34 +000090 DownloadActionTestProcessorDelegate delegate;
91 delegate.loop_ = loop;
92 delegate.expected_data_ = data;
93 delegate.path_ = path;
94 ActionProcessor processor;
95 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +000096 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +000097 processor.EnqueueAction(&download_action);
98
99 g_timeout_add(0, &StartProcessorInRunLoop, &processor);
100 g_main_loop_run(loop);
101 g_main_loop_unref(loop);
102
103 // remove temp file; don't care if there are errors here
104 unlink(path.c_str());
105}
106} // namespace {}
107
108TEST(DownloadActionTest, SimpleTest) {
109 vector<char> small;
110 const char* foo = "foo";
111 small.insert(small.end(), foo, foo + strlen(foo));
112 TestWithData(small, false);
113 TestWithData(small, true);
114}
115
116TEST(DownloadActionTest, LargeTest) {
117 vector<char> big(5 * kMockHttpFetcherChunkSize);
118 char c = '0';
119 for (unsigned int i = 0; i < big.size(); i++) {
120 big[i] = c;
121 if ('9' == c)
122 c = '0';
123 else
124 c++;
125 }
126 TestWithData(big, false);
127 TestWithData(big, true);
128}
129
130namespace {
131class TerminateEarlyTestProcessorDelegate : public ActionProcessorDelegate {
132 public:
133 void ProcessingStopped(const ActionProcessor* processor) {
134 ASSERT_TRUE(loop_);
135 g_main_loop_quit(loop_);
136 }
137 GMainLoop *loop_;
138};
139
140gboolean TerminateEarlyTestStarter(gpointer data) {
141 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
142 processor->StartProcessing();
143 CHECK(processor->IsRunning());
144 processor->StopProcessing();
145 return FALSE;
146}
147
148} // namespace {}
149
150TEST(DownloadActionTest, TerminateEarlyTest) {
151 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
152
153 vector<char> data(kMockHttpFetcherChunkSize + kMockHttpFetcherChunkSize / 2);
154 memset(&data[0], 0, data.size());
155
156 const string path("/tmp/DownloadActionTest");
157 {
158 // takes ownership of passed in HttpFetcher
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000159 ObjectFeederAction<InstallPlan> feeder_action;
160 InstallPlan install_plan(false, "", "", path, "");
161 feeder_action.set_obj(install_plan);
162 DownloadAction download_action(new MockHttpFetcher(&data[0], data.size()));
rspangler@google.com49fdf182009-10-10 00:57:34 +0000163 TerminateEarlyTestProcessorDelegate delegate;
164 delegate.loop_ = loop;
165 ActionProcessor processor;
166 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000167 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000168 processor.EnqueueAction(&download_action);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000169 BondActions(&feeder_action, &download_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000170
171 g_timeout_add(0, &TerminateEarlyTestStarter, &processor);
172 g_main_loop_run(loop);
173 g_main_loop_unref(loop);
174 }
175
176 // 1 or 0 chunks should have come through
177 const off_t resulting_file_size(FileSize(path));
178 if (resulting_file_size != 0)
179 EXPECT_EQ(kMockHttpFetcherChunkSize, resulting_file_size);
180}
181
182class DownloadActionTestAction;
183
184template<>
185class ActionTraits<DownloadActionTestAction> {
186 public:
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000187 typedef InstallPlan OutputObjectType;
188 typedef InstallPlan InputObjectType;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000189};
190
191// This is a simple Action class for testing.
192struct DownloadActionTestAction : public Action<DownloadActionTestAction> {
193 DownloadActionTestAction() : did_run_(false) {}
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000194 typedef InstallPlan InputObjectType;
195 typedef InstallPlan OutputObjectType;
196 ActionPipe<InstallPlan>* in_pipe() { return in_pipe_.get(); }
197 ActionPipe<InstallPlan>* out_pipe() { return out_pipe_.get(); }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000198 ActionProcessor* processor() { return processor_; }
199 void PerformAction() {
200 did_run_ = true;
201 ASSERT_TRUE(HasInputObject());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000202 EXPECT_TRUE(expected_input_object_ == GetInputObject());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000203 ASSERT_TRUE(processor());
204 processor()->ActionComplete(this, true);
205 }
206 string Type() const { return "DownloadActionTestAction"; }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000207 InstallPlan expected_input_object_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000208 bool did_run_;
209};
210
211namespace {
212// This class is an ActionProcessorDelegate that simply terminates the
213// run loop when the ActionProcessor has completed processing. It's used
214// only by the test PassObjectOutTest.
215class PassObjectOutTestProcessorDelegate : public ActionProcessorDelegate {
216 public:
217 void ProcessingDone(const ActionProcessor* processor) {
218 ASSERT_TRUE(loop_);
219 g_main_loop_quit(loop_);
220 }
221 GMainLoop *loop_;
222};
223
224gboolean PassObjectOutTestStarter(gpointer data) {
225 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
226 processor->StartProcessing();
227 return FALSE;
228}
229}
230
231TEST(DownloadActionTest, PassObjectOutTest) {
232 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
233
234 const string path("/tmp/DownloadActionTest");
235
236 // takes ownership of passed in HttpFetcher
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000237 InstallPlan install_plan(false, "",
238 OmahaHashCalculator::OmahaHashOfString("x"), path,
239 "");
240 ObjectFeederAction<InstallPlan> feeder_action;
241 feeder_action.set_obj(install_plan);
242 DownloadAction download_action(new MockHttpFetcher("x", 1));
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");
268
269 // takes ownership of passed in HttpFetcher
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000270 InstallPlan install_plan(false, "", "", path, "");
271 ObjectFeederAction<InstallPlan> feeder_action;
272 feeder_action.set_obj(install_plan);
273 DownloadAction download_action(new MockHttpFetcher("x", 1));
274 BondActions(&feeder_action, &download_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000275
276 ActionProcessor processor;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000277 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000278 processor.EnqueueAction(&download_action);
279 processor.StartProcessing();
280 ASSERT_FALSE(processor.IsRunning());
281
282 g_main_loop_unref(loop);
283}
284
285} // namespace chromeos_update_engine