blob: 3b04eaedbee64042b4ebebbff66d23890eee8921 [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 "",
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070078 0,
Andrew de los Reyesf9185172010-05-03 11:07:05 -070079 OmahaHashCalculator::OmahaHashOfData(data),
80 output_temp_file.GetPath(),
81 "");
adlr@google.comc98a7ed2009-12-04 18:54:03 +000082 ObjectFeederAction<InstallPlan> feeder_action;
83 feeder_action.set_obj(install_plan);
Andrew de los Reyesf9185172010-05-03 11:07:05 -070084 DownloadAction download_action(new MockHttpFetcher(&data[0],
85 data.size()));
86 download_action.SetTestFileWriter(&writer);
adlr@google.comc98a7ed2009-12-04 18:54:03 +000087 BondActions(&feeder_action, &download_action);
88
rspangler@google.com49fdf182009-10-10 00:57:34 +000089 DownloadActionTestProcessorDelegate delegate;
90 delegate.loop_ = loop;
91 delegate.expected_data_ = data;
Andrew de los Reyesf9185172010-05-03 11:07:05 -070092 delegate.path_ = output_temp_file.GetPath();
rspangler@google.com49fdf182009-10-10 00:57:34 +000093 ActionProcessor processor;
94 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +000095 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +000096 processor.EnqueueAction(&download_action);
97
98 g_timeout_add(0, &StartProcessorInRunLoop, &processor);
99 g_main_loop_run(loop);
100 g_main_loop_unref(loop);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000101}
102} // namespace {}
103
104TEST(DownloadActionTest, SimpleTest) {
105 vector<char> small;
106 const char* foo = "foo";
107 small.insert(small.end(), foo, foo + strlen(foo));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700108 TestWithData(small);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000109}
110
111TEST(DownloadActionTest, LargeTest) {
112 vector<char> big(5 * kMockHttpFetcherChunkSize);
113 char c = '0';
114 for (unsigned int i = 0; i < big.size(); i++) {
115 big[i] = c;
116 if ('9' == c)
117 c = '0';
118 else
119 c++;
120 }
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700121 TestWithData(big);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000122}
123
124namespace {
125class TerminateEarlyTestProcessorDelegate : public ActionProcessorDelegate {
126 public:
127 void ProcessingStopped(const ActionProcessor* processor) {
128 ASSERT_TRUE(loop_);
129 g_main_loop_quit(loop_);
130 }
131 GMainLoop *loop_;
132};
133
134gboolean TerminateEarlyTestStarter(gpointer data) {
135 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
136 processor->StartProcessing();
137 CHECK(processor->IsRunning());
138 processor->StopProcessing();
139 return FALSE;
140}
141
142} // namespace {}
143
144TEST(DownloadActionTest, TerminateEarlyTest) {
145 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
146
147 vector<char> data(kMockHttpFetcherChunkSize + kMockHttpFetcherChunkSize / 2);
148 memset(&data[0], 0, data.size());
149
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700150 ScopedTempFile temp_file;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000151 {
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700152 DirectFileWriter writer;
153
rspangler@google.com49fdf182009-10-10 00:57:34 +0000154 // takes ownership of passed in HttpFetcher
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000155 ObjectFeederAction<InstallPlan> feeder_action;
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700156 InstallPlan install_plan(true, "", 0, "", temp_file.GetPath(), "");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000157 feeder_action.set_obj(install_plan);
158 DownloadAction download_action(new MockHttpFetcher(&data[0], data.size()));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700159 download_action.SetTestFileWriter(&writer);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000160 TerminateEarlyTestProcessorDelegate delegate;
161 delegate.loop_ = loop;
162 ActionProcessor processor;
163 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000164 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000165 processor.EnqueueAction(&download_action);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000166 BondActions(&feeder_action, &download_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000167
168 g_timeout_add(0, &TerminateEarlyTestStarter, &processor);
169 g_main_loop_run(loop);
170 g_main_loop_unref(loop);
171 }
172
173 // 1 or 0 chunks should have come through
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700174 const off_t resulting_file_size(utils::FileSize(temp_file.GetPath()));
175 EXPECT_GE(resulting_file_size, 0);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000176 if (resulting_file_size != 0)
177 EXPECT_EQ(kMockHttpFetcherChunkSize, resulting_file_size);
178}
179
180class DownloadActionTestAction;
181
182template<>
183class ActionTraits<DownloadActionTestAction> {
184 public:
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000185 typedef InstallPlan OutputObjectType;
186 typedef InstallPlan InputObjectType;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000187};
188
189// This is a simple Action class for testing.
190struct DownloadActionTestAction : public Action<DownloadActionTestAction> {
191 DownloadActionTestAction() : did_run_(false) {}
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000192 typedef InstallPlan InputObjectType;
193 typedef InstallPlan OutputObjectType;
194 ActionPipe<InstallPlan>* in_pipe() { return in_pipe_.get(); }
195 ActionPipe<InstallPlan>* out_pipe() { return out_pipe_.get(); }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000196 ActionProcessor* processor() { return processor_; }
197 void PerformAction() {
198 did_run_ = true;
199 ASSERT_TRUE(HasInputObject());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000200 EXPECT_TRUE(expected_input_object_ == GetInputObject());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000201 ASSERT_TRUE(processor());
202 processor()->ActionComplete(this, true);
203 }
204 string Type() const { return "DownloadActionTestAction"; }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000205 InstallPlan expected_input_object_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000206 bool did_run_;
207};
208
209namespace {
210// This class is an ActionProcessorDelegate that simply terminates the
211// run loop when the ActionProcessor has completed processing. It's used
212// only by the test PassObjectOutTest.
213class PassObjectOutTestProcessorDelegate : public ActionProcessorDelegate {
214 public:
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800215 void ProcessingDone(const ActionProcessor* processor, bool success) {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000216 ASSERT_TRUE(loop_);
217 g_main_loop_quit(loop_);
218 }
219 GMainLoop *loop_;
220};
221
222gboolean PassObjectOutTestStarter(gpointer data) {
223 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
224 processor->StartProcessing();
225 return FALSE;
226}
227}
228
229TEST(DownloadActionTest, PassObjectOutTest) {
230 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
231
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700232 DirectFileWriter writer;
233
rspangler@google.com49fdf182009-10-10 00:57:34 +0000234 // takes ownership of passed in HttpFetcher
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700235 InstallPlan install_plan(true,
236 "",
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700237 0,
Andrew de los Reyes1e338b82010-01-22 14:57:27 -0800238 OmahaHashCalculator::OmahaHashOfString("x"),
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700239 "/dev/null",
Andrew de los Reyes1e338b82010-01-22 14:57:27 -0800240 "/dev/null");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000241 ObjectFeederAction<InstallPlan> feeder_action;
242 feeder_action.set_obj(install_plan);
243 DownloadAction download_action(new MockHttpFetcher("x", 1));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700244 download_action.SetTestFileWriter(&writer);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000245
246 DownloadActionTestAction test_action;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000247 test_action.expected_input_object_ = install_plan;
248 BondActions(&feeder_action, &download_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000249 BondActions(&download_action, &test_action);
250
251 ActionProcessor processor;
252 PassObjectOutTestProcessorDelegate delegate;
253 delegate.loop_ = loop;
254 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000255 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000256 processor.EnqueueAction(&download_action);
257 processor.EnqueueAction(&test_action);
258
259 g_timeout_add(0, &PassObjectOutTestStarter, &processor);
260 g_main_loop_run(loop);
261 g_main_loop_unref(loop);
262
263 EXPECT_EQ(true, test_action.did_run_);
264}
265
266TEST(DownloadActionTest, BadOutFileTest) {
267 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
268
269 const string path("/fake/path/that/cant/be/created/because/of/missing/dirs");
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700270 DirectFileWriter writer;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000271
272 // takes ownership of passed in HttpFetcher
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700273 InstallPlan install_plan(true, "", 0, "", path, "");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000274 ObjectFeederAction<InstallPlan> feeder_action;
275 feeder_action.set_obj(install_plan);
276 DownloadAction download_action(new MockHttpFetcher("x", 1));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700277 download_action.SetTestFileWriter(&writer);
278
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000279 BondActions(&feeder_action, &download_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000280
281 ActionProcessor processor;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000282 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000283 processor.EnqueueAction(&download_action);
284 processor.StartProcessing();
285 ASSERT_FALSE(processor.IsRunning());
286
287 g_main_loop_unref(loop);
288}
289
290} // namespace chromeos_update_engine