c62120beeb73f5eef48d71399720c0bf67760543
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / p2p / client / connectivitychecker_unittest.cc
1 // Copyright 2011 Google Inc. All Rights Reserved.
2
3
4 #include <string>
5
6 #include "talk/base/asynchttprequest.h"
7 #include "talk/base/gunit.h"
8 #include "talk/base/fakenetwork.h"
9 #include "talk/base/scoped_ptr.h"
10 #include "talk/base/socketaddress.h"
11 #include "talk/p2p/base/basicpacketsocketfactory.h"
12 #include "talk/p2p/base/relayport.h"
13 #include "talk/p2p/base/stunport.h"
14 #include "talk/p2p/client/connectivitychecker.h"
15 #include "talk/p2p/client/httpportallocator.h"
16
17 namespace cricket {
18
19 static const talk_base::SocketAddress kClientAddr1("11.11.11.11", 0);
20 static const talk_base::SocketAddress kClientAddr2("22.22.22.22", 0);
21 static const talk_base::SocketAddress kExternalAddr("33.33.33.33", 3333);
22 static const talk_base::SocketAddress kStunAddr("44.44.44.44", 4444);
23 static const talk_base::SocketAddress kRelayAddr("55.55.55.55", 5555);
24 static const talk_base::SocketAddress kProxyAddr("66.66.66.66", 6666);
25 static const talk_base::ProxyType kProxyType = talk_base::PROXY_HTTPS;
26 static const char kRelayHost[] = "relay.google.com";
27 static const char kRelayToken[] =
28     "CAESFwoOb2phQGdvb2dsZS5jb20Q043h47MmGhBTB1rbfIXkhuarDCZe+xF6";
29 static const char kBrowserAgent[] = "browser_test";
30 static const char kJid[] = "a.b@c";
31 static const char kUserName[] = "testuser";
32 static const char kPassword[] = "testpassword";
33 static const char kMagicCookie[] = "testcookie";
34 static const char kRelayUdpPort[] = "4444";
35 static const char kRelayTcpPort[] = "5555";
36 static const char kRelaySsltcpPort[] = "6666";
37 static const char kSessionId[] = "testsession";
38 static const char kConnection[] = "testconnection";
39 static const int kMinPort = 1000;
40 static const int kMaxPort = 2000;
41
42 // Fake implementation to mock away real network usage.
43 class FakeRelayPort : public RelayPort {
44  public:
45   FakeRelayPort(talk_base::Thread* thread,
46                 talk_base::PacketSocketFactory* factory,
47                 talk_base::Network* network, const talk_base::IPAddress& ip,
48                 int min_port, int max_port,
49                 const std::string& username, const std::string& password)
50       : RelayPort(thread, factory, network, ip, min_port, max_port,
51                   username, password) {
52   }
53
54   // Just signal that we are done.
55   virtual void PrepareAddress() {
56     SignalPortComplete(this);
57   }
58 };
59
60 // Fake implementation to mock away real network usage.
61 class FakeStunPort : public StunPort {
62  public:
63   FakeStunPort(talk_base::Thread* thread,
64                talk_base::PacketSocketFactory* factory,
65                talk_base::Network* network,
66                const talk_base::IPAddress& ip,
67                int min_port, int max_port,
68                const std::string& username, const std::string& password,
69                const talk_base::SocketAddress& server_addr)
70       : StunPort(thread, factory, network, ip, min_port, max_port,
71                  username, password, server_addr) {
72   }
73
74   // Just set external address and signal that we are done.
75   virtual void PrepareAddress() {
76     AddAddress(kExternalAddr, kExternalAddr, talk_base::SocketAddress(), "udp",
77                STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, true);
78     SignalPortComplete(this);
79   }
80 };
81
82 // Fake implementation to mock away real network usage by responding
83 // to http requests immediately.
84 class FakeHttpPortAllocatorSession : public TestHttpPortAllocatorSession {
85  public:
86   FakeHttpPortAllocatorSession(
87       HttpPortAllocator* allocator,
88       const std::string& content_name,
89       int component,
90       const std::string& ice_ufrag, const std::string& ice_pwd,
91       const std::vector<talk_base::SocketAddress>& stun_hosts,
92       const std::vector<std::string>& relay_hosts,
93       const std::string& relay_token,
94       const std::string& agent)
95       : TestHttpPortAllocatorSession(allocator,
96                                      content_name,
97                                      component,
98                                      ice_ufrag,
99                                      ice_pwd,
100                                      stun_hosts,
101                                      relay_hosts,
102                                      relay_token,
103                                      agent) {
104   }
105   virtual void SendSessionRequest(const std::string& host, int port) {
106     FakeReceiveSessionResponse(host, port);
107   }
108
109   // Pass results to the real implementation.
110   void FakeReceiveSessionResponse(const std::string& host, int port) {
111     talk_base::AsyncHttpRequest* response = CreateAsyncHttpResponse(port);
112     TestHttpPortAllocatorSession::OnRequestDone(response);
113     response->Destroy(true);
114   }
115
116  private:
117   // Helper method for creating a response to a relay session request.
118   talk_base::AsyncHttpRequest* CreateAsyncHttpResponse(int port) {
119     talk_base::AsyncHttpRequest* request =
120         new talk_base::AsyncHttpRequest(kBrowserAgent);
121     std::stringstream ss;
122     ss << "username=" << kUserName << std::endl
123        << "password=" << kPassword << std::endl
124        << "magic_cookie=" << kMagicCookie << std::endl
125        << "relay.ip=" << kRelayAddr.ipaddr().ToString() << std::endl
126        << "relay.udp_port=" << kRelayUdpPort << std::endl
127        << "relay.tcp_port=" << kRelayTcpPort << std::endl
128        << "relay.ssltcp_port=" << kRelaySsltcpPort << std::endl;
129     request->response().document.reset(
130         new talk_base::MemoryStream(ss.str().c_str()));
131     request->response().set_success();
132     request->set_port(port);
133     request->set_secure(port == talk_base::HTTP_SECURE_PORT);
134     return request;
135   }
136 };
137
138 // Fake implementation for creating fake http sessions.
139 class FakeHttpPortAllocator : public HttpPortAllocator {
140  public:
141   FakeHttpPortAllocator(talk_base::NetworkManager* network_manager,
142                         const std::string& user_agent)
143       : HttpPortAllocator(network_manager, user_agent) {
144   }
145
146   virtual PortAllocatorSession* CreateSessionInternal(
147       const std::string& content_name, int component,
148       const std::string& ice_ufrag, const std::string& ice_pwd) {
149     std::vector<talk_base::SocketAddress> stun_hosts;
150     stun_hosts.push_back(kStunAddr);
151     std::vector<std::string> relay_hosts;
152     relay_hosts.push_back(kRelayHost);
153     return new FakeHttpPortAllocatorSession(this,
154                                             content_name,
155                                             component,
156                                             ice_ufrag,
157                                             ice_pwd,
158                                             stun_hosts,
159                                             relay_hosts,
160                                             kRelayToken,
161                                             kBrowserAgent);
162   }
163 };
164
165 class ConnectivityCheckerForTest : public ConnectivityChecker {
166  public:
167   ConnectivityCheckerForTest(talk_base::Thread* worker,
168                              const std::string& jid,
169                              const std::string& session_id,
170                              const std::string& user_agent,
171                              const std::string& relay_token,
172                              const std::string& connection)
173       : ConnectivityChecker(worker,
174                             jid,
175                             session_id,
176                             user_agent,
177                             relay_token,
178                             connection),
179         proxy_initiated_(false) {
180   }
181
182   talk_base::FakeNetworkManager* network_manager() const {
183     return network_manager_;
184   }
185
186   FakeHttpPortAllocator* port_allocator() const {
187     return fake_port_allocator_;
188   }
189
190  protected:
191   // Overridden methods for faking a real network.
192   virtual talk_base::NetworkManager* CreateNetworkManager() {
193     network_manager_ = new talk_base::FakeNetworkManager();
194     return network_manager_;
195   }
196   virtual talk_base::BasicPacketSocketFactory* CreateSocketFactory(
197       talk_base::Thread* thread) {
198     // Create socket factory, for simplicity, let it run on the current thread.
199     socket_factory_ =
200         new talk_base::BasicPacketSocketFactory(talk_base::Thread::Current());
201     return socket_factory_;
202   }
203   virtual HttpPortAllocator* CreatePortAllocator(
204       talk_base::NetworkManager* network_manager,
205       const std::string& user_agent,
206       const std::string& relay_token) {
207     fake_port_allocator_ =
208         new FakeHttpPortAllocator(network_manager, user_agent);
209     return fake_port_allocator_;
210   }
211   virtual StunPort* CreateStunPort(
212       const std::string& username, const std::string& password,
213       const PortConfiguration* config, talk_base::Network* network) {
214     return new FakeStunPort(worker(), socket_factory_,
215                             network, network->ip(),
216                             kMinPort, kMaxPort,
217                             username, password,
218                             config->stun_address);
219   }
220   virtual RelayPort* CreateRelayPort(
221       const std::string& username, const std::string& password,
222       const PortConfiguration* config, talk_base::Network* network) {
223     return new FakeRelayPort(worker(), socket_factory_,
224                              network, network->ip(),
225                              kMinPort, kMaxPort,
226                              username, password);
227   }
228   virtual void InitiateProxyDetection() {
229     if (!proxy_initiated_) {
230       proxy_initiated_ = true;
231       proxy_info_.address = kProxyAddr;
232       proxy_info_.type = kProxyType;
233       SetProxyInfo(proxy_info_);
234     }
235   }
236
237   virtual talk_base::ProxyInfo GetProxyInfo() const {
238     return proxy_info_;
239   }
240
241  private:
242   talk_base::BasicPacketSocketFactory* socket_factory_;
243   FakeHttpPortAllocator* fake_port_allocator_;
244   talk_base::FakeNetworkManager* network_manager_;
245   talk_base::ProxyInfo proxy_info_;
246   bool proxy_initiated_;
247 };
248
249 class ConnectivityCheckerTest : public testing::Test {
250  protected:
251   void VerifyNic(const NicInfo& info,
252                  const talk_base::SocketAddress& local_address) {
253     // Verify that the external address has been set.
254     EXPECT_EQ(kExternalAddr, info.external_address);
255
256     // Verify that the stun server address has been set.
257     EXPECT_EQ(kStunAddr, info.stun_server_address);
258
259     // Verify that the media server address has been set. Don't care
260     // about port since it is different for different protocols.
261     EXPECT_EQ(kRelayAddr.ipaddr(), info.media_server_address.ipaddr());
262
263     // Verify that local ip matches.
264     EXPECT_EQ(local_address.ipaddr(), info.ip);
265
266     // Verify that we have received responses for our
267     // pings. Unsuccessful ping has rtt value -1, successful >= 0.
268     EXPECT_GE(info.stun.rtt, 0);
269     EXPECT_GE(info.udp.rtt, 0);
270     EXPECT_GE(info.tcp.rtt, 0);
271     EXPECT_GE(info.ssltcp.rtt, 0);
272
273     // If proxy has been set, verify address and type.
274     if (!info.proxy_info.address.IsNil()) {
275       EXPECT_EQ(kProxyAddr, info.proxy_info.address);
276       EXPECT_EQ(kProxyType, info.proxy_info.type);
277     }
278   }
279 };
280
281 // Tests a configuration with two network interfaces. Verifies that 4
282 // combinations of ip/proxy are created and that all protocols are
283 // tested on each combination.
284 TEST_F(ConnectivityCheckerTest, TestStart) {
285   ConnectivityCheckerForTest connectivity_checker(talk_base::Thread::Current(),
286                                                   kJid,
287                                                   kSessionId,
288                                                   kBrowserAgent,
289                                                   kRelayToken,
290                                                   kConnection);
291   connectivity_checker.Initialize();
292   connectivity_checker.set_stun_address(kStunAddr);
293   connectivity_checker.network_manager()->AddInterface(kClientAddr1);
294   connectivity_checker.network_manager()->AddInterface(kClientAddr2);
295
296   connectivity_checker.Start();
297   talk_base::Thread::Current()->ProcessMessages(1000);
298
299   NicMap nics = connectivity_checker.GetResults();
300
301   // There should be 4 nics in our map. 2 for each interface added,
302   // one with proxy set and one without.
303   EXPECT_EQ(4U, nics.size());
304
305   // First verify interfaces without proxy.
306   talk_base::SocketAddress nilAddress;
307
308   // First lookup the address of the first nic combined with no proxy.
309   NicMap::iterator i = nics.find(NicId(kClientAddr1.ipaddr(), nilAddress));
310   ASSERT(i != nics.end());
311   NicInfo info = i->second;
312   VerifyNic(info, kClientAddr1);
313
314   // Then make sure the second device has been tested without proxy.
315   i = nics.find(NicId(kClientAddr2.ipaddr(), nilAddress));
316   ASSERT(i != nics.end());
317   info = i->second;
318   VerifyNic(info, kClientAddr2);
319
320   // Now verify both interfaces with proxy.
321   i = nics.find(NicId(kClientAddr1.ipaddr(), kProxyAddr));
322   ASSERT(i != nics.end());
323   info = i->second;
324   VerifyNic(info, kClientAddr1);
325
326   i = nics.find(NicId(kClientAddr2.ipaddr(), kProxyAddr));
327   ASSERT(i != nics.end());
328   info = i->second;
329   VerifyNic(info, kClientAddr2);
330 };
331
332 // Tests that nothing bad happens if thera are no network interfaces
333 // available to check.
334 TEST_F(ConnectivityCheckerTest, TestStartNoNetwork) {
335   ConnectivityCheckerForTest connectivity_checker(talk_base::Thread::Current(),
336                                                   kJid,
337                                                   kSessionId,
338                                                   kBrowserAgent,
339                                                   kRelayToken,
340                                                   kConnection);
341   connectivity_checker.Initialize();
342   connectivity_checker.Start();
343   talk_base::Thread::Current()->ProcessMessages(1000);
344
345   NicMap nics = connectivity_checker.GetResults();
346
347   // Verify that no nics where checked.
348   EXPECT_EQ(0U, nics.size());
349 }
350
351 }  // namespace cricket