blob: 3dfc0058277c3d98fe9b3a06d91bfcd39505c48d [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"
14
15namespace chromeos_update_engine {
16
17using std::string;
18using std::vector;
19
20class DownloadActionTest : public ::testing::Test { };
21
22namespace {
23class DownloadActionTestProcessorDelegate : public ActionProcessorDelegate {
24 public:
25 DownloadActionTestProcessorDelegate()
26 : loop_(NULL), processing_done_called_(false) {}
27 virtual ~DownloadActionTestProcessorDelegate() {
28 EXPECT_TRUE(processing_done_called_);
29 }
30 virtual void ProcessingDone(const ActionProcessor* processor) {
31 ASSERT_TRUE(loop_);
32 g_main_loop_quit(loop_);
33 vector<char> found_data = ReadFile(path_);
34 ASSERT_EQ(expected_data_.size(), found_data.size());
35 for (unsigned i = 0; i < expected_data_.size(); i++) {
36 EXPECT_EQ(expected_data_[i], found_data[i]);
37 }
38 processing_done_called_ = true;
39 }
40
41 virtual void ActionCompleted(const ActionProcessor* processor,
42 const AbstractAction* action,
43 bool success) {
44 // make sure actions always succeed
45 EXPECT_TRUE(success);
46 }
47
48 GMainLoop *loop_;
49 string path_;
50 vector<char> expected_data_;
51 bool processing_done_called_;
52};
53
54struct EntryPointArgs {
55 const vector<char> *data;
56 GMainLoop *loop;
57 ActionProcessor *processor;
58};
59
60gboolean StartProcessorInRunLoop(gpointer data) {
61 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
62 processor->StartProcessing();
63 return FALSE;
64}
65
66void TestWithData(const vector<char>& data, bool compress) {
67 vector<char> use_data;
68 if (compress) {
69 use_data = GzipCompressData(data);
70 } else {
71 use_data = data;
72 }
73
74 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
75
76 // TODO(adlr): see if we need a different file for build bots
77 const string path("/tmp/DownloadActionTest");
78 // takes ownership of passed in HttpFetcher
79 DownloadAction download_action("", path, 0,
80 OmahaHashCalculator::OmahaHashOfData(use_data),
81 compress, new MockHttpFetcher(&use_data[0],
82 use_data.size()));
83 DownloadActionTestProcessorDelegate delegate;
84 delegate.loop_ = loop;
85 delegate.expected_data_ = data;
86 delegate.path_ = path;
87 ActionProcessor processor;
88 processor.set_delegate(&delegate);
89 processor.EnqueueAction(&download_action);
90
91 g_timeout_add(0, &StartProcessorInRunLoop, &processor);
92 g_main_loop_run(loop);
93 g_main_loop_unref(loop);
94
95 // remove temp file; don't care if there are errors here
96 unlink(path.c_str());
97}
98} // namespace {}
99
100TEST(DownloadActionTest, SimpleTest) {
101 vector<char> small;
102 const char* foo = "foo";
103 small.insert(small.end(), foo, foo + strlen(foo));
104 TestWithData(small, false);
105 TestWithData(small, true);
106}
107
108TEST(DownloadActionTest, LargeTest) {
109 vector<char> big(5 * kMockHttpFetcherChunkSize);
110 char c = '0';
111 for (unsigned int i = 0; i < big.size(); i++) {
112 big[i] = c;
113 if ('9' == c)
114 c = '0';
115 else
116 c++;
117 }
118 TestWithData(big, false);
119 TestWithData(big, true);
120}
121
122namespace {
123class TerminateEarlyTestProcessorDelegate : public ActionProcessorDelegate {
124 public:
125 void ProcessingStopped(const ActionProcessor* processor) {
126 ASSERT_TRUE(loop_);
127 g_main_loop_quit(loop_);
128 }
129 GMainLoop *loop_;
130};
131
132gboolean TerminateEarlyTestStarter(gpointer data) {
133 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
134 processor->StartProcessing();
135 CHECK(processor->IsRunning());
136 processor->StopProcessing();
137 return FALSE;
138}
139
140} // namespace {}
141
142TEST(DownloadActionTest, TerminateEarlyTest) {
143 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
144
145 vector<char> data(kMockHttpFetcherChunkSize + kMockHttpFetcherChunkSize / 2);
146 memset(&data[0], 0, data.size());
147
148 const string path("/tmp/DownloadActionTest");
149 {
150 // takes ownership of passed in HttpFetcher
151 DownloadAction download_action("", path, 0, "", false,
152 new MockHttpFetcher(&data[0], data.size()));
153 TerminateEarlyTestProcessorDelegate delegate;
154 delegate.loop_ = loop;
155 ActionProcessor processor;
156 processor.set_delegate(&delegate);
157 processor.EnqueueAction(&download_action);
158
159 g_timeout_add(0, &TerminateEarlyTestStarter, &processor);
160 g_main_loop_run(loop);
161 g_main_loop_unref(loop);
162 }
163
164 // 1 or 0 chunks should have come through
165 const off_t resulting_file_size(FileSize(path));
166 if (resulting_file_size != 0)
167 EXPECT_EQ(kMockHttpFetcherChunkSize, resulting_file_size);
168}
169
170class DownloadActionTestAction;
171
172template<>
173class ActionTraits<DownloadActionTestAction> {
174 public:
175 typedef string OutputObjectType;
176 typedef string InputObjectType;
177};
178
179// This is a simple Action class for testing.
180struct DownloadActionTestAction : public Action<DownloadActionTestAction> {
181 DownloadActionTestAction() : did_run_(false) {}
182 typedef string InputObjectType;
183 typedef string OutputObjectType;
184 ActionPipe<string>* in_pipe() { return in_pipe_.get(); }
185 ActionPipe<string>* out_pipe() { return out_pipe_.get(); }
186 ActionProcessor* processor() { return processor_; }
187 void PerformAction() {
188 did_run_ = true;
189 ASSERT_TRUE(HasInputObject());
190 EXPECT_EQ(expected_input_object_, GetInputObject());
191 ASSERT_TRUE(processor());
192 processor()->ActionComplete(this, true);
193 }
194 string Type() const { return "DownloadActionTestAction"; }
195 string expected_input_object_;
196 bool did_run_;
197};
198
199namespace {
200// This class is an ActionProcessorDelegate that simply terminates the
201// run loop when the ActionProcessor has completed processing. It's used
202// only by the test PassObjectOutTest.
203class PassObjectOutTestProcessorDelegate : public ActionProcessorDelegate {
204 public:
205 void ProcessingDone(const ActionProcessor* processor) {
206 ASSERT_TRUE(loop_);
207 g_main_loop_quit(loop_);
208 }
209 GMainLoop *loop_;
210};
211
212gboolean PassObjectOutTestStarter(gpointer data) {
213 ActionProcessor *processor = reinterpret_cast<ActionProcessor*>(data);
214 processor->StartProcessing();
215 return FALSE;
216}
217}
218
219TEST(DownloadActionTest, PassObjectOutTest) {
220 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
221
222 const string path("/tmp/DownloadActionTest");
223
224 // takes ownership of passed in HttpFetcher
225 DownloadAction download_action("", path, 0,
226 OmahaHashCalculator::OmahaHashOfString("x"),
227 false, new MockHttpFetcher("x", 1));
228
229 DownloadActionTestAction test_action;
230 test_action.expected_input_object_ = path;
231 BondActions(&download_action, &test_action);
232
233 ActionProcessor processor;
234 PassObjectOutTestProcessorDelegate delegate;
235 delegate.loop_ = loop;
236 processor.set_delegate(&delegate);
237 processor.EnqueueAction(&download_action);
238 processor.EnqueueAction(&test_action);
239
240 g_timeout_add(0, &PassObjectOutTestStarter, &processor);
241 g_main_loop_run(loop);
242 g_main_loop_unref(loop);
243
244 EXPECT_EQ(true, test_action.did_run_);
245}
246
247TEST(DownloadActionTest, BadOutFileTest) {
248 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
249
250 const string path("/fake/path/that/cant/be/created/because/of/missing/dirs");
251
252 // takes ownership of passed in HttpFetcher
253 DownloadAction download_action("", path, 0, "", false,
254 new MockHttpFetcher("x", 1));
255
256 ActionProcessor processor;
257 processor.EnqueueAction(&download_action);
258 processor.StartProcessing();
259 ASSERT_FALSE(processor.IsRunning());
260
261 g_main_loop_unref(loop);
262}
263
264} // namespace chromeos_update_engine