• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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