1 // Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include <sstream>
6
7 #include "include/base/cef_cxx17_backports.h"
8 #include "include/cef_task.h"
9 #include "include/cef_waitable_event.h"
10 #include "include/wrapper/cef_closure_task.h"
11 #include "include/wrapper/cef_helpers.h"
12 #include "tests/ceftests/test_request.h"
13 #include "tests/ceftests/test_server.h"
14 #include "tests/ceftests/track_callback.h"
15 #include "tests/gtest/include/gtest/gtest.h"
16
17 namespace {
18
19 struct TestState {
20 TrackCallback got_initialized_;
21 TrackCallback got_connected_;
22 TrackCallback got_request_;
23 TrackCallback got_response_;
24 TrackCallback got_disconnected_;
25 TrackCallback got_shutdown_;
26
ExpectAll__anon0a89199a0111::TestState27 bool ExpectAll() {
28 EXPECT_TRUE(got_initialized_);
29 EXPECT_TRUE(got_connected_);
30 EXPECT_TRUE(got_request_);
31 EXPECT_TRUE(got_response_);
32 EXPECT_TRUE(got_disconnected_);
33 EXPECT_TRUE(got_shutdown_);
34 return got_initialized_ && got_connected_ && got_request_ &&
35 got_response_ && got_disconnected_ && got_shutdown_;
36 }
37 };
38
39 const char kResponseData[] = "Test data";
40
41 class TestServerObserver : public test_server::ObserverHelper {
42 public:
TestServerObserver(TestState * state,const std::string & path,base::OnceClosure done_callback)43 TestServerObserver(TestState* state,
44 const std::string& path,
45 base::OnceClosure done_callback)
46 : state_(state),
47 path_(path),
48 done_callback_(std::move(done_callback)),
49 weak_ptr_factory_(this) {
50 DCHECK(state);
51 DCHECK(!path.empty());
52 DCHECK(!done_callback_.is_null());
53 Initialize();
54 }
55
~TestServerObserver()56 ~TestServerObserver() override { std::move(done_callback_).Run(); }
57
OnInitialized(const std::string & server_origin)58 void OnInitialized(const std::string& server_origin) override {
59 CEF_REQUIRE_UI_THREAD();
60 EXPECT_FALSE(state_->got_initialized_);
61 EXPECT_FALSE(state_->got_connected_);
62 EXPECT_FALSE(state_->got_request_);
63 EXPECT_FALSE(state_->got_response_);
64 EXPECT_FALSE(state_->got_disconnected_);
65 EXPECT_FALSE(state_->got_shutdown_);
66
67 state_->got_initialized_.yes();
68
69 url_ = server_origin + path_;
70
71 // Send a request to the server.
72 test_request::SendConfig config;
73 config.request_ = CefRequest::Create();
74 config.request_->SetURL(url_);
75 test_request::Send(config,
76 base::BindOnce(&TestServerObserver::OnRequestResponse,
77 weak_ptr_factory_.GetWeakPtr()));
78 }
79
OnClientConnected(CefRefPtr<CefServer> server,int connection_id)80 bool OnClientConnected(CefRefPtr<CefServer> server,
81 int connection_id) override {
82 CEF_REQUIRE_UI_THREAD();
83 if (state_->got_connected_) {
84 // We already got the callback once. Let the next observer get the
85 // callback.
86 return false;
87 }
88
89 EXPECT_TRUE(state_->got_initialized_);
90 EXPECT_FALSE(state_->got_request_);
91 EXPECT_FALSE(state_->got_response_);
92 EXPECT_FALSE(state_->got_disconnected_);
93 EXPECT_FALSE(state_->got_shutdown_);
94
95 state_->got_connected_.yes();
96
97 // We don't know if this connection is the one that we're going to
98 // handle, so continue propagating the callback.
99 return false;
100 }
101
OnHttpRequest(CefRefPtr<CefServer> server,int connection_id,const CefString & client_address,CefRefPtr<CefRequest> request)102 bool OnHttpRequest(CefRefPtr<CefServer> server,
103 int connection_id,
104 const CefString& client_address,
105 CefRefPtr<CefRequest> request) override {
106 CEF_REQUIRE_UI_THREAD();
107 const std::string& url = request->GetURL();
108 if (url != url_)
109 return false;
110
111 EXPECT_TRUE(state_->got_initialized_);
112 EXPECT_TRUE(state_->got_connected_);
113 EXPECT_FALSE(state_->got_request_);
114 EXPECT_FALSE(state_->got_response_);
115 EXPECT_FALSE(state_->got_disconnected_);
116 EXPECT_FALSE(state_->got_shutdown_);
117
118 state_->got_request_.yes();
119 connection_id_ = connection_id;
120
121 server->SendHttp200Response(connection_id, "text/plain", kResponseData,
122 sizeof(kResponseData) - 1);
123
124 // Stop propagating the callback.
125 return true;
126 }
127
OnRequestResponse(const test_request::State & state)128 void OnRequestResponse(const test_request::State& state) {
129 CEF_REQUIRE_UI_THREAD();
130 // Don't test for disconnected, which may race response.
131 EXPECT_TRUE(state_->got_initialized_);
132 EXPECT_TRUE(state_->got_connected_);
133 EXPECT_TRUE(state_->got_request_);
134 EXPECT_FALSE(state_->got_response_);
135 EXPECT_FALSE(state_->got_shutdown_);
136
137 state_->got_response_.yes();
138
139 EXPECT_STREQ(url_.c_str(), state.request_->GetURL().ToString().c_str());
140 EXPECT_EQ(UR_SUCCESS, state.status_);
141 EXPECT_EQ(ERR_NONE, state.error_code_);
142 EXPECT_EQ(200, state.response_->GetStatus());
143 EXPECT_STREQ(kResponseData, state.download_data_.c_str());
144
145 // Trigger shutdown asynchronously.
146 CefPostTask(TID_UI, base::BindOnce(&TestServerObserver::Shutdown,
147 weak_ptr_factory_.GetWeakPtr()));
148 }
149
OnClientDisconnected(CefRefPtr<CefServer> server,int connection_id)150 bool OnClientDisconnected(CefRefPtr<CefServer> server,
151 int connection_id) override {
152 CEF_REQUIRE_UI_THREAD();
153 if (connection_id != connection_id_) {
154 // Not the connection that we handled. Let the next observer get the
155 // callback.
156 return false;
157 }
158
159 // Don't test for response, which may race disconnected.
160 EXPECT_TRUE(state_->got_initialized_);
161 EXPECT_TRUE(state_->got_connected_);
162 EXPECT_TRUE(state_->got_request_);
163 EXPECT_FALSE(state_->got_disconnected_);
164 EXPECT_FALSE(state_->got_shutdown_);
165
166 state_->got_disconnected_.yes();
167
168 // Stop propagating the callback.
169 return true;
170 }
171
OnShutdown()172 void OnShutdown() override {
173 CEF_REQUIRE_UI_THREAD();
174 EXPECT_TRUE(state_->got_initialized_);
175 EXPECT_TRUE(state_->got_connected_);
176 EXPECT_TRUE(state_->got_request_);
177 EXPECT_TRUE(state_->got_response_);
178 EXPECT_TRUE(state_->got_disconnected_);
179 EXPECT_FALSE(state_->got_shutdown_);
180
181 state_->got_shutdown_.yes();
182
183 // End the test.
184 delete this;
185 }
186
187 private:
188 TestState* const state_;
189 const std::string path_;
190 base::OnceClosure done_callback_;
191
192 std::string url_;
193 int connection_id_ = -1;
194
195 base::WeakPtrFactory<TestServerObserver> weak_ptr_factory_;
196
197 DISALLOW_COPY_AND_ASSIGN(TestServerObserver);
198 };
199
CreateObserverOnUIThread(TestState * state,const std::string & path,base::OnceClosure done_callback)200 void CreateObserverOnUIThread(TestState* state,
201 const std::string& path,
202 base::OnceClosure done_callback) {
203 if (!CefCurrentlyOn(TID_UI)) {
204 CefPostTask(TID_UI, base::BindOnce(CreateObserverOnUIThread,
205 base::Unretained(state), path,
206 std::move(done_callback)));
207 return;
208 }
209
210 new TestServerObserver(state, path, std::move(done_callback));
211 }
212
SignalIfDone(CefRefPtr<CefWaitableEvent> event,size_t * count,size_t total)213 void SignalIfDone(CefRefPtr<CefWaitableEvent> event,
214 size_t* count,
215 size_t total) {
216 if (++(*count) == total) {
217 event->Signal();
218 }
219 }
220
221 } // namespace
222
TEST(TestServerTest,ObserverHelperSingle)223 TEST(TestServerTest, ObserverHelperSingle) {
224 CefRefPtr<CefWaitableEvent> event =
225 CefWaitableEvent::CreateWaitableEvent(true, false);
226
227 TestState state;
228 CreateObserverOnUIThread(&state, "/TestServerTest.ObserverHelperSingle",
229 base::BindOnce(&CefWaitableEvent::Signal, event));
230 event->TimedWait(2000);
231
232 EXPECT_TRUE(state.ExpectAll());
233 }
234
TEST(TestServerTest,ObserverHelperMultiple)235 TEST(TestServerTest, ObserverHelperMultiple) {
236 CefRefPtr<CefWaitableEvent> event =
237 CefWaitableEvent::CreateWaitableEvent(true, false);
238
239 TestState states[3];
240 size_t count = 0;
241 const size_t size = base::size(states);
242
243 for (size_t i = 0; i < size; ++i) {
244 std::stringstream ss;
245 ss << "/TestServerTest.ObserverHelperMultiple" << i;
246 auto done_callback =
247 base::BindOnce(SignalIfDone, event, base::Unretained(&count), size);
248 CreateObserverOnUIThread(&states[i], ss.str(), std::move(done_callback));
249 }
250
251 event->TimedWait(2000);
252
253 EXPECT_EQ(size, count);
254 for (size_t i = 0; i < size; ++i) {
255 EXPECT_TRUE(states[i].ExpectAll()) << i;
256 }
257 }
258