blob: 104107fb9fe5c75e00d781f58eb3aaba64b210ee [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 }
Darin Petkovc1a8b422010-07-19 11:34:49 -070031 virtual void ProcessingDone(const ActionProcessor* processor,
32 ActionExitCode code) {
rspangler@google.com49fdf182009-10-10 00:57:34 +000033 ASSERT_TRUE(loop_);
34 g_main_loop_quit(loop_);
adlr@google.comc98a7ed2009-12-04 18:54:03 +000035 vector<char> found_data;
36 ASSERT_TRUE(utils::ReadFile(path_, &found_data));
rspangler@google.com49fdf182009-10-10 00:57:34 +000037 ASSERT_EQ(expected_data_.size(), found_data.size());
38 for (unsigned i = 0; i < expected_data_.size(); i++) {
39 EXPECT_EQ(expected_data_[i], found_data[i]);
40 }
41 processing_done_called_ = true;
42 }
43
adlr@google.comc98a7ed2009-12-04 18:54:03 +000044 virtual void ActionCompleted(ActionProcessor* processor,
45 AbstractAction* action,
Darin Petkovc1a8b422010-07-19 11:34:49 -070046 ActionExitCode code) {
rspangler@google.com49fdf182009-10-10 00:57:34 +000047 // make sure actions always succeed
Darin Petkovc1a8b422010-07-19 11:34:49 -070048 EXPECT_EQ(kActionCodeSuccess, code);
rspangler@google.com49fdf182009-10-10 00:57:34 +000049 }
50
51 GMainLoop *loop_;
52 string path_;
53 vector<char> expected_data_;
54 bool processing_done_called_;
55};
56
57struct EntryPointArgs {
58 const vector<char> *data;
59 GMainLoop *loop;
60 ActionProcessor *processor;
61};
62
63gboolean StartProcessorInRunLoop(gpointer data) {
64 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
65 processor->StartProcessing();
66 return FALSE;
67}
68
Andrew de los Reyesf9185172010-05-03 11:07:05 -070069void TestWithData(const vector<char>& data) {
rspangler@google.com49fdf182009-10-10 00:57:34 +000070 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
71
72 // TODO(adlr): see if we need a different file for build bots
Andrew de los Reyesf9185172010-05-03 11:07:05 -070073 ScopedTempFile output_temp_file;
74 DirectFileWriter writer;
75
rspangler@google.com49fdf182009-10-10 00:57:34 +000076 // takes ownership of passed in HttpFetcher
Andrew de los Reyesf9185172010-05-03 11:07:05 -070077 InstallPlan install_plan(true,
78 "",
Andrew de los Reyes63b96d72010-05-10 13:08:54 -070079 0,
Andrew de los Reyesf9185172010-05-03 11:07:05 -070080 OmahaHashCalculator::OmahaHashOfData(data),
81 output_temp_file.GetPath(),
82 "");
adlr@google.comc98a7ed2009-12-04 18:54:03 +000083 ObjectFeederAction<InstallPlan> feeder_action;
84 feeder_action.set_obj(install_plan);
Andrew de los Reyesf9185172010-05-03 11:07:05 -070085 DownloadAction download_action(new MockHttpFetcher(&data[0],
86 data.size()));
87 download_action.SetTestFileWriter(&writer);
adlr@google.comc98a7ed2009-12-04 18:54:03 +000088 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;
Andrew de los Reyesf9185172010-05-03 11:07:05 -070093 delegate.path_ = output_temp_file.GetPath();
rspangler@google.com49fdf182009-10-10 00:57:34 +000094 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);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000102}
103} // namespace {}
104
105TEST(DownloadActionTest, SimpleTest) {
106 vector<char> small;
107 const char* foo = "foo";
108 small.insert(small.end(), foo, foo + strlen(foo));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700109 TestWithData(small);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000110}
111
112TEST(DownloadActionTest, LargeTest) {
113 vector<char> big(5 * kMockHttpFetcherChunkSize);
114 char c = '0';
115 for (unsigned int i = 0; i < big.size(); i++) {
116 big[i] = c;
117 if ('9' == c)
118 c = '0';
119 else
120 c++;
121 }
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700122 TestWithData(big);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000123}
124
125namespace {
126class TerminateEarlyTestProcessorDelegate : public ActionProcessorDelegate {
127 public:
128 void ProcessingStopped(const ActionProcessor* processor) {
129 ASSERT_TRUE(loop_);
130 g_main_loop_quit(loop_);
131 }
132 GMainLoop *loop_;
133};
134
135gboolean TerminateEarlyTestStarter(gpointer data) {
136 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
137 processor->StartProcessing();
138 CHECK(processor->IsRunning());
139 processor->StopProcessing();
140 return FALSE;
141}
142
143} // namespace {}
144
145TEST(DownloadActionTest, TerminateEarlyTest) {
146 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
147
148 vector<char> data(kMockHttpFetcherChunkSize + kMockHttpFetcherChunkSize / 2);
149 memset(&data[0], 0, data.size());
150
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700151 ScopedTempFile temp_file;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000152 {
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700153 DirectFileWriter writer;
154
rspangler@google.com49fdf182009-10-10 00:57:34 +0000155 // takes ownership of passed in HttpFetcher
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000156 ObjectFeederAction<InstallPlan> feeder_action;
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700157 InstallPlan install_plan(true, "", 0, "", temp_file.GetPath(), "");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000158 feeder_action.set_obj(install_plan);
159 DownloadAction download_action(new MockHttpFetcher(&data[0], data.size()));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700160 download_action.SetTestFileWriter(&writer);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000161 TerminateEarlyTestProcessorDelegate delegate;
162 delegate.loop_ = loop;
163 ActionProcessor processor;
164 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000165 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000166 processor.EnqueueAction(&download_action);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000167 BondActions(&feeder_action, &download_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000168
169 g_timeout_add(0, &TerminateEarlyTestStarter, &processor);
170 g_main_loop_run(loop);
171 g_main_loop_unref(loop);
172 }
173
174 // 1 or 0 chunks should have come through
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700175 const off_t resulting_file_size(utils::FileSize(temp_file.GetPath()));
176 EXPECT_GE(resulting_file_size, 0);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000177 if (resulting_file_size != 0)
178 EXPECT_EQ(kMockHttpFetcherChunkSize, resulting_file_size);
179}
180
181class DownloadActionTestAction;
182
183template<>
184class ActionTraits<DownloadActionTestAction> {
185 public:
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000186 typedef InstallPlan OutputObjectType;
187 typedef InstallPlan InputObjectType;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000188};
189
190// This is a simple Action class for testing.
191struct DownloadActionTestAction : public Action<DownloadActionTestAction> {
192 DownloadActionTestAction() : did_run_(false) {}
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000193 typedef InstallPlan InputObjectType;
194 typedef InstallPlan OutputObjectType;
195 ActionPipe<InstallPlan>* in_pipe() { return in_pipe_.get(); }
196 ActionPipe<InstallPlan>* out_pipe() { return out_pipe_.get(); }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000197 ActionProcessor* processor() { return processor_; }
198 void PerformAction() {
199 did_run_ = true;
200 ASSERT_TRUE(HasInputObject());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000201 EXPECT_TRUE(expected_input_object_ == GetInputObject());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000202 ASSERT_TRUE(processor());
Darin Petkovc1a8b422010-07-19 11:34:49 -0700203 processor()->ActionComplete(this, kActionCodeSuccess);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000204 }
205 string Type() const { return "DownloadActionTestAction"; }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000206 InstallPlan expected_input_object_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000207 bool did_run_;
208};
209
210namespace {
211// This class is an ActionProcessorDelegate that simply terminates the
212// run loop when the ActionProcessor has completed processing. It's used
213// only by the test PassObjectOutTest.
214class PassObjectOutTestProcessorDelegate : public ActionProcessorDelegate {
215 public:
Darin Petkovc1a8b422010-07-19 11:34:49 -0700216 void ProcessingDone(const ActionProcessor* processor, ActionExitCode code) {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000217 ASSERT_TRUE(loop_);
218 g_main_loop_quit(loop_);
219 }
220 GMainLoop *loop_;
221};
222
223gboolean PassObjectOutTestStarter(gpointer data) {
224 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
225 processor->StartProcessing();
226 return FALSE;
227}
228}
229
230TEST(DownloadActionTest, PassObjectOutTest) {
231 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
232
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700233 DirectFileWriter writer;
234
rspangler@google.com49fdf182009-10-10 00:57:34 +0000235 // takes ownership of passed in HttpFetcher
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700236 InstallPlan install_plan(true,
237 "",
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700238 0,
Andrew de los Reyes1e338b82010-01-22 14:57:27 -0800239 OmahaHashCalculator::OmahaHashOfString("x"),
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700240 "/dev/null",
Andrew de los Reyes1e338b82010-01-22 14:57:27 -0800241 "/dev/null");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000242 ObjectFeederAction<InstallPlan> feeder_action;
243 feeder_action.set_obj(install_plan);
244 DownloadAction download_action(new MockHttpFetcher("x", 1));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700245 download_action.SetTestFileWriter(&writer);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000246
247 DownloadActionTestAction test_action;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000248 test_action.expected_input_object_ = install_plan;
249 BondActions(&feeder_action, &download_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000250 BondActions(&download_action, &test_action);
251
252 ActionProcessor processor;
253 PassObjectOutTestProcessorDelegate delegate;
254 delegate.loop_ = loop;
255 processor.set_delegate(&delegate);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000256 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000257 processor.EnqueueAction(&download_action);
258 processor.EnqueueAction(&test_action);
259
260 g_timeout_add(0, &PassObjectOutTestStarter, &processor);
261 g_main_loop_run(loop);
262 g_main_loop_unref(loop);
263
264 EXPECT_EQ(true, test_action.did_run_);
265}
266
267TEST(DownloadActionTest, BadOutFileTest) {
268 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
269
270 const string path("/fake/path/that/cant/be/created/because/of/missing/dirs");
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700271 DirectFileWriter writer;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000272
273 // takes ownership of passed in HttpFetcher
Andrew de los Reyes63b96d72010-05-10 13:08:54 -0700274 InstallPlan install_plan(true, "", 0, "", path, "");
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000275 ObjectFeederAction<InstallPlan> feeder_action;
276 feeder_action.set_obj(install_plan);
277 DownloadAction download_action(new MockHttpFetcher("x", 1));
Andrew de los Reyesf9185172010-05-03 11:07:05 -0700278 download_action.SetTestFileWriter(&writer);
Darin Petkovc1a8b422010-07-19 11:34:49 -0700279
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000280 BondActions(&feeder_action, &download_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000281
282 ActionProcessor processor;
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000283 processor.EnqueueAction(&feeder_action);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000284 processor.EnqueueAction(&download_action);
285 processor.StartProcessing();
286 ASSERT_FALSE(processor.IsRunning());
287
288 g_main_loop_unref(loop);
289}
290
291} // namespace chromeos_update_engine