xref: /aosp_15_r20/external/libbrillo/brillo/http/http_request_test.cc (revision 1a96fba65179ea7d3f56207137718607415c5953)
1*1a96fba6SXin Li // Copyright 2014 The Chromium OS Authors. All rights reserved.
2*1a96fba6SXin Li // Use of this source code is governed by a BSD-style license that can be
3*1a96fba6SXin Li // found in the LICENSE file.
4*1a96fba6SXin Li 
5*1a96fba6SXin Li #include <brillo/http/http_request.h>
6*1a96fba6SXin Li 
7*1a96fba6SXin Li #include <string>
8*1a96fba6SXin Li 
9*1a96fba6SXin Li #include <base/bind.h>
10*1a96fba6SXin Li #include <base/callback.h>
11*1a96fba6SXin Li #include <brillo/http/mock_connection.h>
12*1a96fba6SXin Li #include <brillo/http/mock_transport.h>
13*1a96fba6SXin Li #include <brillo/mime_utils.h>
14*1a96fba6SXin Li #include <brillo/streams/mock_stream.h>
15*1a96fba6SXin Li #include <gmock/gmock.h>
16*1a96fba6SXin Li #include <gtest/gtest.h>
17*1a96fba6SXin Li 
18*1a96fba6SXin Li using testing::DoAll;
19*1a96fba6SXin Li using testing::Invoke;
20*1a96fba6SXin Li using testing::Return;
21*1a96fba6SXin Li using testing::SetArgPointee;
22*1a96fba6SXin Li using testing::Unused;
23*1a96fba6SXin Li using testing::WithArg;
24*1a96fba6SXin Li using testing::_;
25*1a96fba6SXin Li 
26*1a96fba6SXin Li namespace brillo {
27*1a96fba6SXin Li namespace http {
28*1a96fba6SXin Li 
29*1a96fba6SXin Li MATCHER_P(ContainsStringData, str, "") {
30*1a96fba6SXin Li   if (arg->GetSize() != str.size())
31*1a96fba6SXin Li     return false;
32*1a96fba6SXin Li 
33*1a96fba6SXin Li   std::string data;
34*1a96fba6SXin Li   char buf[100];
35*1a96fba6SXin Li   size_t read = 0;
36*1a96fba6SXin Li   while (arg->ReadBlocking(buf, sizeof(buf), &read, nullptr) && read > 0) {
37*1a96fba6SXin Li     data.append(buf, read);
38*1a96fba6SXin Li   }
39*1a96fba6SXin Li   return data == str;
40*1a96fba6SXin Li }
41*1a96fba6SXin Li 
42*1a96fba6SXin Li class HttpRequestTest : public testing::Test {
43*1a96fba6SXin Li  public:
SetUp()44*1a96fba6SXin Li   void SetUp() override {
45*1a96fba6SXin Li     transport_ = std::make_shared<MockTransport>();
46*1a96fba6SXin Li     connection_ = std::make_shared<MockConnection>(transport_);
47*1a96fba6SXin Li   }
48*1a96fba6SXin Li 
TearDown()49*1a96fba6SXin Li   void TearDown() override {
50*1a96fba6SXin Li     // Having shared pointers to mock objects (some of methods in these tests
51*1a96fba6SXin Li     // return shared pointers to connection and transport) could cause the
52*1a96fba6SXin Li     // test expectations to hold on to the mock object without releasing them
53*1a96fba6SXin Li     // at the end of a test, causing Mock's object leak detection to erroneously
54*1a96fba6SXin Li     // detect mock object "leaks". Verify and clear the expectations manually
55*1a96fba6SXin Li     // and explicitly to ensure the shared pointer refcounters are not
56*1a96fba6SXin Li     // preventing the mocks to be destroyed at the end of each test.
57*1a96fba6SXin Li     testing::Mock::VerifyAndClearExpectations(connection_.get());
58*1a96fba6SXin Li     connection_.reset();
59*1a96fba6SXin Li     testing::Mock::VerifyAndClearExpectations(transport_.get());
60*1a96fba6SXin Li     transport_.reset();
61*1a96fba6SXin Li   }
62*1a96fba6SXin Li 
63*1a96fba6SXin Li  protected:
64*1a96fba6SXin Li   std::shared_ptr<MockTransport> transport_;
65*1a96fba6SXin Li   std::shared_ptr<MockConnection> connection_;
66*1a96fba6SXin Li };
67*1a96fba6SXin Li 
TEST_F(HttpRequestTest,Defaults)68*1a96fba6SXin Li TEST_F(HttpRequestTest, Defaults) {
69*1a96fba6SXin Li   Request request{"http://www.foo.bar", request_type::kPost, transport_};
70*1a96fba6SXin Li   EXPECT_TRUE(request.GetContentType().empty());
71*1a96fba6SXin Li   EXPECT_TRUE(request.GetReferer().empty());
72*1a96fba6SXin Li   EXPECT_TRUE(request.GetUserAgent().empty());
73*1a96fba6SXin Li   EXPECT_EQ("*/*", request.GetAccept());
74*1a96fba6SXin Li   EXPECT_EQ("http://www.foo.bar", request.GetRequestURL());
75*1a96fba6SXin Li   EXPECT_EQ(request_type::kPost, request.GetRequestMethod());
76*1a96fba6SXin Li 
77*1a96fba6SXin Li   Request request2{"http://www.foo.bar/baz", request_type::kGet, transport_};
78*1a96fba6SXin Li   EXPECT_EQ("http://www.foo.bar/baz", request2.GetRequestURL());
79*1a96fba6SXin Li   EXPECT_EQ(request_type::kGet, request2.GetRequestMethod());
80*1a96fba6SXin Li }
81*1a96fba6SXin Li 
TEST_F(HttpRequestTest,ContentType)82*1a96fba6SXin Li TEST_F(HttpRequestTest, ContentType) {
83*1a96fba6SXin Li   Request request{"http://www.foo.bar", request_type::kPost, transport_};
84*1a96fba6SXin Li   request.SetContentType(mime::image::kJpeg);
85*1a96fba6SXin Li   EXPECT_EQ(mime::image::kJpeg, request.GetContentType());
86*1a96fba6SXin Li }
87*1a96fba6SXin Li 
TEST_F(HttpRequestTest,Referer)88*1a96fba6SXin Li TEST_F(HttpRequestTest, Referer) {
89*1a96fba6SXin Li   Request request{"http://www.foo.bar", request_type::kPost, transport_};
90*1a96fba6SXin Li   request.SetReferer("http://www.foo.bar/baz");
91*1a96fba6SXin Li   EXPECT_EQ("http://www.foo.bar/baz", request.GetReferer());
92*1a96fba6SXin Li }
93*1a96fba6SXin Li 
TEST_F(HttpRequestTest,UserAgent)94*1a96fba6SXin Li TEST_F(HttpRequestTest, UserAgent) {
95*1a96fba6SXin Li   Request request{"http://www.foo.bar", request_type::kPost, transport_};
96*1a96fba6SXin Li   request.SetUserAgent("FooBar Browser");
97*1a96fba6SXin Li   EXPECT_EQ("FooBar Browser", request.GetUserAgent());
98*1a96fba6SXin Li }
99*1a96fba6SXin Li 
TEST_F(HttpRequestTest,Accept)100*1a96fba6SXin Li TEST_F(HttpRequestTest, Accept) {
101*1a96fba6SXin Li   Request request{"http://www.foo.bar", request_type::kPost, transport_};
102*1a96fba6SXin Li   request.SetAccept("text/*, text/html, text/html;level=1, */*");
103*1a96fba6SXin Li   EXPECT_EQ("text/*, text/html, text/html;level=1, */*", request.GetAccept());
104*1a96fba6SXin Li }
105*1a96fba6SXin Li 
TEST_F(HttpRequestTest,GetResponseAndBlock)106*1a96fba6SXin Li TEST_F(HttpRequestTest, GetResponseAndBlock) {
107*1a96fba6SXin Li   Request request{"http://www.foo.bar", request_type::kPost, transport_};
108*1a96fba6SXin Li   request.SetUserAgent("FooBar Browser");
109*1a96fba6SXin Li   request.SetReferer("http://www.foo.bar/baz");
110*1a96fba6SXin Li   request.SetAccept("text/*, text/html, text/html;level=1, */*");
111*1a96fba6SXin Li   request.AddHeader(request_header::kAcceptEncoding, "compress, gzip");
112*1a96fba6SXin Li   request.AddHeaders({
113*1a96fba6SXin Li       {request_header::kAcceptLanguage, "da, en-gb;q=0.8, en;q=0.7"},
114*1a96fba6SXin Li       {request_header::kConnection, "close"},
115*1a96fba6SXin Li   });
116*1a96fba6SXin Li   request.AddRange(-10);
117*1a96fba6SXin Li   request.AddRange(100, 200);
118*1a96fba6SXin Li   request.AddRange(300);
119*1a96fba6SXin Li   std::string req_body{"Foo bar baz"};
120*1a96fba6SXin Li   request.AddHeader(request_header::kContentType, mime::text::kPlain);
121*1a96fba6SXin Li 
122*1a96fba6SXin Li   EXPECT_CALL(*transport_, CreateConnection(
123*1a96fba6SXin Li       "http://www.foo.bar",
124*1a96fba6SXin Li       request_type::kPost,
125*1a96fba6SXin Li       HeaderList{
126*1a96fba6SXin Li         {request_header::kAcceptEncoding, "compress, gzip"},
127*1a96fba6SXin Li         {request_header::kAcceptLanguage, "da, en-gb;q=0.8, en;q=0.7"},
128*1a96fba6SXin Li         {request_header::kConnection, "close"},
129*1a96fba6SXin Li         {request_header::kContentType, mime::text::kPlain},
130*1a96fba6SXin Li         {request_header::kRange, "bytes=-10,100-200,300-"},
131*1a96fba6SXin Li         {request_header::kAccept, "text/*, text/html, text/html;level=1, */*"},
132*1a96fba6SXin Li       },
133*1a96fba6SXin Li       "FooBar Browser",
134*1a96fba6SXin Li       "http://www.foo.bar/baz",
135*1a96fba6SXin Li       nullptr)).WillOnce(Return(connection_));
136*1a96fba6SXin Li 
137*1a96fba6SXin Li   EXPECT_CALL(*connection_, MockSetRequestData(ContainsStringData(req_body), _))
138*1a96fba6SXin Li       .WillOnce(Return(true));
139*1a96fba6SXin Li 
140*1a96fba6SXin Li   EXPECT_TRUE(
141*1a96fba6SXin Li       request.AddRequestBody(req_body.data(), req_body.size(), nullptr));
142*1a96fba6SXin Li 
143*1a96fba6SXin Li   EXPECT_CALL(*connection_, FinishRequest(_)).WillOnce(Return(true));
144*1a96fba6SXin Li   auto resp = request.GetResponseAndBlock(nullptr);
145*1a96fba6SXin Li   EXPECT_NE(nullptr, resp.get());
146*1a96fba6SXin Li }
147*1a96fba6SXin Li 
TEST_F(HttpRequestTest,GetResponse)148*1a96fba6SXin Li TEST_F(HttpRequestTest, GetResponse) {
149*1a96fba6SXin Li   Request request{"http://foo.bar", request_type::kGet, transport_};
150*1a96fba6SXin Li 
151*1a96fba6SXin Li   std::string resp_data{"FooBar response body"};
152*1a96fba6SXin Li   auto read_data =
153*1a96fba6SXin Li       [&resp_data](void* buffer, Unused, size_t* read, Unused) -> bool {
154*1a96fba6SXin Li     memcpy(buffer, resp_data.data(), resp_data.size());
155*1a96fba6SXin Li     *read = resp_data.size();
156*1a96fba6SXin Li     return true;
157*1a96fba6SXin Li   };
158*1a96fba6SXin Li 
159*1a96fba6SXin Li   auto success_callback = base::Bind(
160*1a96fba6SXin Li       [](MockConnection* connection, const std::string& resp_data,
161*1a96fba6SXin Li          RequestID request_id, std::unique_ptr<Response> resp) {
162*1a96fba6SXin Li     EXPECT_EQ(23, request_id);
163*1a96fba6SXin Li     EXPECT_CALL(*connection, GetResponseStatusCode())
164*1a96fba6SXin Li         .WillOnce(Return(status_code::Partial));
165*1a96fba6SXin Li     EXPECT_EQ(status_code::Partial, resp->GetStatusCode());
166*1a96fba6SXin Li 
167*1a96fba6SXin Li     EXPECT_CALL(*connection, GetResponseStatusText())
168*1a96fba6SXin Li         .WillOnce(Return("Partial completion"));
169*1a96fba6SXin Li     EXPECT_EQ("Partial completion", resp->GetStatusText());
170*1a96fba6SXin Li 
171*1a96fba6SXin Li     EXPECT_CALL(*connection, GetResponseHeader(response_header::kContentType))
172*1a96fba6SXin Li         .WillOnce(Return(mime::text::kHtml));
173*1a96fba6SXin Li     EXPECT_EQ(mime::text::kHtml, resp->GetContentType());
174*1a96fba6SXin Li 
175*1a96fba6SXin Li     EXPECT_EQ(resp_data, resp->ExtractDataAsString());
176*1a96fba6SXin Li   }, connection_.get(), resp_data);
177*1a96fba6SXin Li 
178*1a96fba6SXin Li   auto finish_request_async =
179*1a96fba6SXin Li       [this, &read_data](const SuccessCallback& success_callback) {
180*1a96fba6SXin Li     std::unique_ptr<MockStream> mock_stream{new MockStream};
181*1a96fba6SXin Li     EXPECT_CALL(*mock_stream, ReadBlocking(_, _, _, _))
182*1a96fba6SXin Li         .WillOnce(Invoke(read_data))
183*1a96fba6SXin Li         .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
184*1a96fba6SXin Li 
185*1a96fba6SXin Li     EXPECT_CALL(*connection_, MockExtractDataStream(_))
186*1a96fba6SXin Li       .WillOnce(Return(mock_stream.release()));
187*1a96fba6SXin Li     std::unique_ptr<Response> resp{new Response{connection_}};
188*1a96fba6SXin Li     success_callback.Run(23, std::move(resp));
189*1a96fba6SXin Li   };
190*1a96fba6SXin Li 
191*1a96fba6SXin Li   EXPECT_CALL(
192*1a96fba6SXin Li       *transport_,
193*1a96fba6SXin Li       CreateConnection("http://foo.bar", request_type::kGet, _, "", "", _))
194*1a96fba6SXin Li       .WillOnce(Return(connection_));
195*1a96fba6SXin Li 
196*1a96fba6SXin Li   EXPECT_CALL(*connection_, FinishRequestAsync(_, _))
197*1a96fba6SXin Li       .WillOnce(DoAll(WithArg<0>(Invoke(finish_request_async)), Return(23)));
198*1a96fba6SXin Li 
199*1a96fba6SXin Li   EXPECT_EQ(23, request.GetResponse(success_callback, {}));
200*1a96fba6SXin Li }
201*1a96fba6SXin Li 
202*1a96fba6SXin Li }  // namespace http
203*1a96fba6SXin Li }  // namespace brillo
204