| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium OS Authors. All rights reserved. | 1 // 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <unistd.h> | 5 #include <unistd.h> |
| 6 #include <string> |
| 7 #include <vector> |
| 6 #include <base/scoped_ptr.h> | 8 #include <base/scoped_ptr.h> |
| 7 #include <glib.h> | 9 #include <glib.h> |
| 8 #include <base/logging.h> | |
| 9 #include <gtest/gtest.h> | 10 #include <gtest/gtest.h> |
| 11 #include "chromeos/obsolete_logging.h" |
| 10 #include "update_engine/libcurl_http_fetcher.h" | 12 #include "update_engine/libcurl_http_fetcher.h" |
| 11 #include "update_engine/mock_http_fetcher.h" | 13 #include "update_engine/mock_http_fetcher.h" |
| 12 | 14 |
| 15 using std::string; |
| 16 using std::vector; |
| 17 |
| 13 namespace chromeos_update_engine { | 18 namespace chromeos_update_engine { |
| 14 | 19 |
| 15 namespace { | 20 namespace { |
| 16 // WARNING, if you update this, you must also update test_http_server.py | 21 // WARNING, if you update this, you must also update test_http_server.py |
| 17 const char* const kServerPort = "8080"; | 22 const char* const kServerPort = "8080"; |
| 18 string LocalServerUrlForPath(const string& path) { | 23 string LocalServerUrlForPath(const string& path) { |
| 19 return string("http://127.0.0.1:") + kServerPort + path; | 24 return string("http://127.0.0.1:") + kServerPort + path; |
| 20 } | 25 } |
| 21 } | 26 } |
| 22 | 27 |
| 23 template <typename T> | 28 template <typename T> |
| 24 class HttpFetcherTest : public ::testing::Test { | 29 class HttpFetcherTest : public ::testing::Test { |
| 25 public: | 30 public: |
| 26 HttpFetcher* NewLargeFetcher() = 0; | 31 HttpFetcher* NewLargeFetcher() = 0; |
| 27 HttpFetcher* NewSmallFetcher() = 0; | 32 HttpFetcher* NewSmallFetcher() = 0; |
| 28 string BigUrl() const = 0; | 33 string BigUrl() const = 0; |
| 29 string SmallUrl() const = 0; | 34 string SmallUrl() const = 0; |
| 35 bool IsMock() const = 0; |
| 30 }; | 36 }; |
| 31 | 37 |
| 32 class NullHttpServer { | 38 class NullHttpServer { |
| 33 public: | 39 public: |
| 34 NullHttpServer() : started_(true) {} | 40 NullHttpServer() : started_(true) {} |
| 35 ~NullHttpServer() {} | 41 ~NullHttpServer() {} |
| 36 bool started_; | 42 bool started_; |
| 37 }; | 43 }; |
| 38 | 44 |
| 39 | 45 |
| 40 template <> | 46 template <> |
| 41 class HttpFetcherTest<MockHttpFetcher> : public ::testing::Test { | 47 class HttpFetcherTest<MockHttpFetcher> : public ::testing::Test { |
| 42 public: | 48 public: |
| 43 HttpFetcher* NewLargeFetcher() { | 49 HttpFetcher* NewLargeFetcher() { |
| 44 vector<char> big_data(1000000); | 50 vector<char> big_data(1000000); |
| 45 return new MockHttpFetcher(big_data.data(), big_data.size()); | 51 return new MockHttpFetcher(big_data.data(), big_data.size()); |
| 46 } | 52 } |
| 47 HttpFetcher* NewSmallFetcher() { | 53 HttpFetcher* NewSmallFetcher() { |
| 48 return new MockHttpFetcher("x", 1); | 54 return new MockHttpFetcher("x", 1); |
| 49 } | 55 } |
| 50 string BigUrl() const { | 56 string BigUrl() const { |
| 51 return "unused://unused"; | 57 return "unused://unused"; |
| 52 } | 58 } |
| 53 string SmallUrl() const { | 59 string SmallUrl() const { |
| 54 return "unused://unused"; | 60 return "unused://unused"; |
| 55 } | 61 } |
| 62 bool IsMock() const { return true; } |
| 56 typedef NullHttpServer HttpServer; | 63 typedef NullHttpServer HttpServer; |
| 57 }; | 64 }; |
| 58 | 65 |
| 59 class PythonHttpServer { | 66 class PythonHttpServer { |
| 60 public: | 67 public: |
| 61 PythonHttpServer() { | 68 PythonHttpServer() { |
| 62 char *argv[2] = {strdup("./test_http_server.py"), NULL}; | 69 char *argv[2] = {strdup("./test_http_server"), NULL}; |
| 63 GError *err; | 70 GError *err; |
| 64 started_ = false; | 71 started_ = false; |
| 65 if (!g_spawn_async(NULL, | 72 if (!g_spawn_async(NULL, |
| 66 argv, | 73 argv, |
| 67 NULL, | 74 NULL, |
| 68 G_SPAWN_DO_NOT_REAP_CHILD, | 75 G_SPAWN_DO_NOT_REAP_CHILD, |
| 69 NULL, | 76 NULL, |
| 70 NULL, | 77 NULL, |
| 71 &pid_, | 78 &pid_, |
| 72 &err)) { | 79 &err)) { |
| 73 return; | 80 return; |
| 74 } | 81 } |
| 75 int rc = 1; | 82 int rc = 1; |
| 76 while (0 != rc) { | 83 while (0 != rc) { |
| 77 | |
| 78 rc = system((string("wget --output-document=/dev/null ") + | 84 rc = system((string("wget --output-document=/dev/null ") + |
| 79 LocalServerUrlForPath("/test")).c_str()); | 85 LocalServerUrlForPath("/test")).c_str()); |
| 80 usleep(10 * 1000); // 10 ms | 86 usleep(10 * 1000); // 10 ms |
| 81 } | 87 } |
| 82 started_ = true; | 88 started_ = true; |
| 83 free(argv[0]); | 89 free(argv[0]); |
| 84 return; | 90 return; |
| 85 } | 91 } |
| 86 ~PythonHttpServer() { | 92 ~PythonHttpServer() { |
| 87 if (!started_) | 93 if (!started_) |
| (...skipping 17 matching lines...) Expand all Loading... |
| 105 } | 111 } |
| 106 HttpFetcher* NewSmallFetcher() { | 112 HttpFetcher* NewSmallFetcher() { |
| 107 return NewLargeFetcher(); | 113 return NewLargeFetcher(); |
| 108 } | 114 } |
| 109 string BigUrl() const { | 115 string BigUrl() const { |
| 110 return LocalServerUrlForPath("/big"); | 116 return LocalServerUrlForPath("/big"); |
| 111 } | 117 } |
| 112 string SmallUrl() const { | 118 string SmallUrl() const { |
| 113 return LocalServerUrlForPath("/foo"); | 119 return LocalServerUrlForPath("/foo"); |
| 114 } | 120 } |
| 121 bool IsMock() const { return false; } |
| 115 typedef PythonHttpServer HttpServer; | 122 typedef PythonHttpServer HttpServer; |
| 116 }; | 123 }; |
| 117 | 124 |
| 118 typedef ::testing::Types<LibcurlHttpFetcher, MockHttpFetcher> | 125 typedef ::testing::Types<LibcurlHttpFetcher, MockHttpFetcher> |
| 119 HttpFetcherTestTypes; | 126 HttpFetcherTestTypes; |
| 120 TYPED_TEST_CASE(HttpFetcherTest, HttpFetcherTestTypes); | 127 TYPED_TEST_CASE(HttpFetcherTest, HttpFetcherTestTypes); |
| 121 | 128 |
| 122 namespace { | 129 namespace { |
| 123 class HttpFetcherTestDelegate : public HttpFetcherDelegate { | 130 class HttpFetcherTestDelegate : public HttpFetcherDelegate { |
| 124 public: | 131 public: |
| 125 virtual void ReceivedBytes(HttpFetcher* fetcher, | 132 virtual void ReceivedBytes(HttpFetcher* fetcher, |
| 126 const char* bytes, int length) { | 133 const char* bytes, int length) { |
| 127 char str[length + 1]; | 134 char str[length + 1]; |
| 128 memset(str, 0, length + 1); | 135 memset(str, 0, length + 1); |
| 129 memcpy(str, bytes, length); | 136 memcpy(str, bytes, length); |
| 130 } | 137 } |
| 131 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) { | 138 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) { |
| 132 g_main_loop_quit(loop_); | 139 g_main_loop_quit(loop_); |
| 133 } | 140 } |
| 134 GMainLoop* loop_; | 141 GMainLoop* loop_; |
| 135 }; | 142 }; |
| 143 |
| 144 struct StartTransferArgs { |
| 145 HttpFetcher *http_fetcher; |
| 146 string url; |
| 147 }; |
| 148 |
| 149 gboolean StartTransfer(gpointer data) { |
| 150 StartTransferArgs *args = reinterpret_cast<StartTransferArgs*>(data); |
| 151 args->http_fetcher->BeginTransfer(args->url); |
| 152 return FALSE; |
| 153 } |
| 136 } // namespace {} | 154 } // namespace {} |
| 137 | 155 |
| 138 TYPED_TEST(HttpFetcherTest, SimpleTest) { | 156 TYPED_TEST(HttpFetcherTest, SimpleTest) { |
| 139 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE); | 157 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE); |
| 140 { | 158 { |
| 141 HttpFetcherTestDelegate delegate; | 159 HttpFetcherTestDelegate delegate; |
| 142 delegate.loop_ = loop; | 160 delegate.loop_ = loop; |
| 143 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher()); | 161 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher()); |
| 144 fetcher->set_delegate(&delegate); | 162 fetcher->set_delegate(&delegate); |
| 145 | 163 |
| 146 typename TestFixture::HttpServer server; | 164 typename TestFixture::HttpServer server; |
| 147 ASSERT_TRUE(server.started_); | 165 ASSERT_TRUE(server.started_); |
| 148 | 166 |
| 149 fetcher->BeginTransfer(this->SmallUrl()); | 167 StartTransferArgs start_xfer_args = {fetcher.get(), this->SmallUrl()}; |
| 168 |
| 169 g_timeout_add(0, StartTransfer, &start_xfer_args); |
| 150 g_main_loop_run(loop); | 170 g_main_loop_run(loop); |
| 151 } | 171 } |
| 152 g_main_loop_unref(loop); | 172 g_main_loop_unref(loop); |
| 153 } | 173 } |
| 154 | 174 |
| 155 namespace { | 175 namespace { |
| 156 class PausingHttpFetcherTestDelegate : public HttpFetcherDelegate { | 176 class PausingHttpFetcherTestDelegate : public HttpFetcherDelegate { |
| 157 public: | 177 public: |
| 158 virtual void ReceivedBytes(HttpFetcher* fetcher, | 178 virtual void ReceivedBytes(HttpFetcher* fetcher, |
| 159 const char* bytes, int length) { | 179 const char* bytes, int length) { |
| 160 char str[length + 1]; | 180 char str[length + 1]; |
| 161 LOG(INFO) << "got " << length << " bytes"; | |
| 162 memset(str, 0, length + 1); | 181 memset(str, 0, length + 1); |
| 163 memcpy(str, bytes, length); | 182 memcpy(str, bytes, length); |
| 164 CHECK(!paused_); | 183 CHECK(!paused_); |
| 165 paused_ = true; | 184 paused_ = true; |
| 166 fetcher->Pause(); | 185 fetcher->Pause(); |
| 167 LOG(INFO) << "calling pause"; | |
| 168 } | 186 } |
| 169 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) { | 187 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) { |
| 170 g_main_loop_quit(loop_); | 188 g_main_loop_quit(loop_); |
| 171 } | 189 } |
| 172 void Unpause() { | 190 void Unpause() { |
| 173 CHECK(paused_); | 191 CHECK(paused_); |
| 174 paused_ = false; | 192 paused_ = false; |
| 175 fetcher_->Unpause(); | 193 fetcher_->Unpause(); |
| 176 LOG(INFO) << "calling unpause"; | |
| 177 } | 194 } |
| 178 bool paused_; | 195 bool paused_; |
| 179 HttpFetcher* fetcher_; | 196 HttpFetcher* fetcher_; |
| 180 GMainLoop* loop_; | 197 GMainLoop* loop_; |
| 181 }; | 198 }; |
| 182 | 199 |
| 183 gboolean UnpausingTimeoutCallback(gpointer data) { | 200 gboolean UnpausingTimeoutCallback(gpointer data) { |
| 184 PausingHttpFetcherTestDelegate *delegate = | 201 PausingHttpFetcherTestDelegate *delegate = |
| 185 reinterpret_cast<PausingHttpFetcherTestDelegate*>(data); | 202 reinterpret_cast<PausingHttpFetcherTestDelegate*>(data); |
| 186 if (delegate->paused_) | 203 if (delegate->paused_) |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 267 NULL); | 284 NULL); |
| 268 g_source_attach(timeout_source_, NULL); | 285 g_source_attach(timeout_source_, NULL); |
| 269 fetcher->BeginTransfer(this->BigUrl()); | 286 fetcher->BeginTransfer(this->BigUrl()); |
| 270 | 287 |
| 271 g_main_loop_run(loop); | 288 g_main_loop_run(loop); |
| 272 g_source_destroy(timeout_source_); | 289 g_source_destroy(timeout_source_); |
| 273 } | 290 } |
| 274 g_main_loop_unref(loop); | 291 g_main_loop_unref(loop); |
| 275 } | 292 } |
| 276 | 293 |
| 294 namespace { |
| 295 class FlakyHttpFetcherTestDelegate : public HttpFetcherDelegate { |
| 296 public: |
| 297 virtual void ReceivedBytes(HttpFetcher* fetcher, |
| 298 const char* bytes, int length) { |
| 299 data.append(bytes, length); |
| 300 } |
| 301 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) { |
| 302 g_main_loop_quit(loop_); |
| 303 } |
| 304 string data; |
| 305 GMainLoop* loop_; |
| 306 }; |
| 307 } // namespace {} |
| 308 |
| 309 TYPED_TEST(HttpFetcherTest, FlakyTest) { |
| 310 if (this->IsMock()) |
| 311 return; |
| 312 GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE); |
| 313 { |
| 314 FlakyHttpFetcherTestDelegate delegate; |
| 315 delegate.loop_ = loop; |
| 316 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher()); |
| 317 fetcher->set_delegate(&delegate); |
| 318 |
| 319 typename TestFixture::HttpServer server; |
| 320 ASSERT_TRUE(server.started_); |
| 321 |
| 322 StartTransferArgs start_xfer_args = { |
| 323 fetcher.get(), |
| 324 LocalServerUrlForPath("/flaky") |
| 325 }; |
| 326 |
| 327 g_timeout_add(0, StartTransfer, &start_xfer_args); |
| 328 g_main_loop_run(loop); |
| 329 |
| 330 // verify the data we get back |
| 331 ASSERT_EQ(100000, delegate.data.size()); |
| 332 for (int i = 0; i < 100000; i += 10) { |
| 333 // Assert so that we don't flood the screen w/ EXPECT errors on failure. |
| 334 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij"); |
| 335 } |
| 336 } |
| 337 g_main_loop_unref(loop); |
| 338 } |
| 339 |
| 277 } // namespace chromeos_update_engine | 340 } // namespace chromeos_update_engine |
| OLD | NEW |