blob: 3543870b8a81d1b8d8e99706268d60797ccb94b7 [file] [log] [blame]
Jae Hoon Kim0ae8fe12019-06-26 14:32:50 -07001//
2// Copyright (C) 2019 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "update_engine/libcurl_http_fetcher.h"
18
19#include <string>
20
21#include <brillo/message_loops/fake_message_loop.h>
Amin Hassanid3d84212019-08-17 00:27:44 -070022#include <gmock/gmock.h>
Jae Hoon Kim0ae8fe12019-06-26 14:32:50 -070023#include <gtest/gtest.h>
24
25#include "update_engine/common/fake_hardware.h"
26#include "update_engine/common/mock_proxy_resolver.h"
Amin Hassanid3d84212019-08-17 00:27:44 -070027#include "update_engine/mock_libcurl_http_fetcher.h"
Jae Hoon Kim0ae8fe12019-06-26 14:32:50 -070028
29using std::string;
30
31namespace chromeos_update_engine {
32
33namespace {
Kelvin Zhangf0c73d42021-09-07 10:34:26 -070034
Jae Hoon Kim0ae8fe12019-06-26 14:32:50 -070035constexpr char kHeaderName[] = "X-Goog-Test-Header";
Jae Hoon Kim0ae8fe12019-06-26 14:32:50 -070036
37class LibcurlHttpFetcherTest : public ::testing::Test {
38 protected:
39 void SetUp() override {
40 loop_.SetAsCurrent();
41 fake_hardware_.SetIsOfficialBuild(true);
42 fake_hardware_.SetIsOOBEEnabled(false);
43 }
44
45 brillo::FakeMessageLoop loop_{nullptr};
46 FakeHardware fake_hardware_;
Amin Hassanid3d84212019-08-17 00:27:44 -070047 MockLibcurlHttpFetcher libcurl_fetcher_{nullptr, &fake_hardware_};
Xiaochu Liub5ba7972019-07-11 09:51:06 -070048 UnresolvedHostStateMachine state_machine_;
Jae Hoon Kim0ae8fe12019-06-26 14:32:50 -070049};
50
Kelvin Zhangf0c73d42021-09-07 10:34:26 -070051} // namespace
52
Jae Hoon Kim0ae8fe12019-06-26 14:32:50 -070053TEST_F(LibcurlHttpFetcherTest, GetEmptyHeaderValueTest) {
54 const string header_value = "";
55 string actual_header_value;
56 libcurl_fetcher_.SetHeader(kHeaderName, header_value);
57 EXPECT_TRUE(libcurl_fetcher_.GetHeader(kHeaderName, &actual_header_value));
58 EXPECT_EQ("", actual_header_value);
59}
60
61TEST_F(LibcurlHttpFetcherTest, GetHeaderTest) {
62 const string header_value = "This-is-value 123";
63 string actual_header_value;
64 libcurl_fetcher_.SetHeader(kHeaderName, header_value);
65 EXPECT_TRUE(libcurl_fetcher_.GetHeader(kHeaderName, &actual_header_value));
66 EXPECT_EQ(header_value, actual_header_value);
67}
68
69TEST_F(LibcurlHttpFetcherTest, GetNonExistentHeaderValueTest) {
70 string actual_header_value;
71 // Skip |SetHeaader()| call.
72 EXPECT_FALSE(libcurl_fetcher_.GetHeader(kHeaderName, &actual_header_value));
73 // Even after a failed |GetHeaderValue()|, enforce that the passed pointer to
74 // modifiable string was cleared to be empty.
75 EXPECT_EQ("", actual_header_value);
76}
77
78TEST_F(LibcurlHttpFetcherTest, GetHeaderEdgeCaseTest) {
79 const string header_value = "\a\b\t\v\f\r\\ edge:-case: \a\b\t\v\f\r\\";
80 string actual_header_value;
81 libcurl_fetcher_.SetHeader(kHeaderName, header_value);
82 EXPECT_TRUE(libcurl_fetcher_.GetHeader(kHeaderName, &actual_header_value));
83 EXPECT_EQ(header_value, actual_header_value);
84}
85
Xiaochu Liub5ba7972019-07-11 09:51:06 -070086TEST_F(LibcurlHttpFetcherTest, InvalidURLTest) {
87 int no_network_max_retries = 1;
88 libcurl_fetcher_.set_no_network_max_retries(no_network_max_retries);
89
Amin Hassanid3d84212019-08-17 00:27:44 -070090 libcurl_fetcher_.BeginTransfer("not-a-URL");
Xiaochu Liub5ba7972019-07-11 09:51:06 -070091 while (loop_.PendingTasks()) {
92 loop_.RunOnce(true);
93 }
94
95 EXPECT_EQ(libcurl_fetcher_.get_no_network_max_retries(),
96 no_network_max_retries);
97}
98
Amin Hassanid3d84212019-08-17 00:27:44 -070099TEST_F(LibcurlHttpFetcherTest, CouldNotResolveHostTest) {
Xiaochu Liub5ba7972019-07-11 09:51:06 -0700100 int no_network_max_retries = 1;
101 libcurl_fetcher_.set_no_network_max_retries(no_network_max_retries);
102
Amin Hassanid3d84212019-08-17 00:27:44 -0700103 libcurl_fetcher_.BeginTransfer("https://An-uNres0lvable-uRl.invalid");
104
Tianjie934b8472020-06-24 23:10:49 -0700105 // It's slower on Android that libcurl handle may not finish within 1 cycle.
106 // Will need to wait for more cycles until it finishes. Original test didn't
107 // correctly handle when we need to re-watch libcurl fds.
108 while (loop_.PendingTasks() &&
109 libcurl_fetcher_.GetAuxiliaryErrorCode() == ErrorCode::kSuccess) {
110 loop_.RunOnce(true);
111 }
Amin Hassanice99ee72020-10-07 22:24:33 -0700112
Amin Hassanid3d84212019-08-17 00:27:44 -0700113 EXPECT_EQ(libcurl_fetcher_.GetAuxiliaryErrorCode(),
114 ErrorCode::kUnresolvedHostError);
115
116 while (loop_.PendingTasks()) {
117 loop_.RunOnce(true);
118 }
119 // The auxilary error code should've have been changed.
120 EXPECT_EQ(libcurl_fetcher_.GetAuxiliaryErrorCode(),
121 ErrorCode::kUnresolvedHostError);
122
123 // If libcurl fails to resolve the name, we call res_init() to reload
124 // resolv.conf and retry exactly once more. See crbug.com/982813 for details.
125 EXPECT_EQ(libcurl_fetcher_.get_no_network_max_retries(),
126 no_network_max_retries + 1);
127}
128
129TEST_F(LibcurlHttpFetcherTest, HostResolvedTest) {
130 int no_network_max_retries = 2;
131 libcurl_fetcher_.set_no_network_max_retries(no_network_max_retries);
132
Xiaochu Liub5ba7972019-07-11 09:51:06 -0700133 // This test actually sends request to internet but according to
134 // https://tools.ietf.org/html/rfc2606#section-2, .invalid domain names are
135 // reserved and sure to be invalid. Ideally we should mock libcurl or
136 // reorganize LibcurlHttpFetcher so the part that sends request can be mocked
137 // easily.
138 // TODO(xiaochu) Refactor LibcurlHttpFetcher (and its relates) so it's
139 // easier to mock the part that depends on internet connectivity.
140 libcurl_fetcher_.BeginTransfer("https://An-uNres0lvable-uRl.invalid");
Amin Hassanid3d84212019-08-17 00:27:44 -0700141
Tianjie934b8472020-06-24 23:10:49 -0700142 // It's slower on Android that libcurl handle may not finish within 1 cycle.
143 // Will need to wait for more cycles until it finishes. Original test didn't
144 // correctly handle when we need to re-watch libcurl fds.
145 while (loop_.PendingTasks() &&
146 libcurl_fetcher_.GetAuxiliaryErrorCode() == ErrorCode::kSuccess) {
147 loop_.RunOnce(true);
148 }
Amin Hassanice99ee72020-10-07 22:24:33 -0700149
Amin Hassanid3d84212019-08-17 00:27:44 -0700150 EXPECT_EQ(libcurl_fetcher_.GetAuxiliaryErrorCode(),
151 ErrorCode::kUnresolvedHostError);
152
153 // The second time, it will resolve, with error code 200 but we set the
154 // download size be smaller than the transfer size so it will retry again.
155 EXPECT_CALL(libcurl_fetcher_, GetHttpResponseCode())
156 .WillOnce(testing::Invoke(
157 [this]() { libcurl_fetcher_.http_response_code_ = 200; }))
158 .WillRepeatedly(testing::Invoke(
159 [this]() { libcurl_fetcher_.http_response_code_ = 0; }));
160 libcurl_fetcher_.transfer_size_ = 10;
161
Tianjie934b8472020-06-24 23:10:49 -0700162 // It's slower on Android that libcurl handle may not finish within 1 cycle.
163 // Will need to wait for more cycles until it finishes. Original test didn't
164 // correctly handle when we need to re-watch libcurl fds.
165 while (loop_.PendingTasks() && libcurl_fetcher_.GetAuxiliaryErrorCode() ==
166 ErrorCode::kUnresolvedHostError) {
167 loop_.RunOnce(true);
168 }
Amin Hassanice99ee72020-10-07 22:24:33 -0700169
Amin Hassanid3d84212019-08-17 00:27:44 -0700170 EXPECT_EQ(libcurl_fetcher_.GetAuxiliaryErrorCode(),
171 ErrorCode::kUnresolvedHostRecovered);
172
Xiaochu Liub5ba7972019-07-11 09:51:06 -0700173 while (loop_.PendingTasks()) {
174 loop_.RunOnce(true);
175 }
Amin Hassanid3d84212019-08-17 00:27:44 -0700176 // The auxilary error code should not have been changed.
177 EXPECT_EQ(libcurl_fetcher_.GetAuxiliaryErrorCode(),
178 ErrorCode::kUnresolvedHostRecovered);
Xiaochu Liub5ba7972019-07-11 09:51:06 -0700179
180 // If libcurl fails to resolve the name, we call res_init() to reload
181 // resolv.conf and retry exactly once more. See crbug.com/982813 for details.
182 EXPECT_EQ(libcurl_fetcher_.get_no_network_max_retries(),
183 no_network_max_retries + 1);
184}
185
186TEST_F(LibcurlHttpFetcherTest, HttpFetcherStateMachineRetryFailedTest) {
187 state_machine_.UpdateState(true);
188 state_machine_.UpdateState(true);
Amin Hassanid3d84212019-08-17 00:27:44 -0700189 EXPECT_EQ(state_machine_.GetState(),
Xiaochu Liub5ba7972019-07-11 09:51:06 -0700190 UnresolvedHostStateMachine::State::kNotRetry);
191}
192
193TEST_F(LibcurlHttpFetcherTest, HttpFetcherStateMachineRetrySucceedTest) {
194 state_machine_.UpdateState(true);
195 state_machine_.UpdateState(false);
Amin Hassanid3d84212019-08-17 00:27:44 -0700196 EXPECT_EQ(state_machine_.GetState(),
Xiaochu Liub5ba7972019-07-11 09:51:06 -0700197 UnresolvedHostStateMachine::State::kRetriedSuccess);
198}
199
200TEST_F(LibcurlHttpFetcherTest, HttpFetcherStateMachineNoRetryTest) {
201 state_machine_.UpdateState(false);
202 state_machine_.UpdateState(false);
Amin Hassanid3d84212019-08-17 00:27:44 -0700203 EXPECT_EQ(state_machine_.GetState(),
Xiaochu Liub5ba7972019-07-11 09:51:06 -0700204 UnresolvedHostStateMachine::State::kInit);
205}
206
Jae Hoon Kim0ae8fe12019-06-26 14:32:50 -0700207} // namespace chromeos_update_engine