Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / session / tunnel / tunnelsessionclient_unittest.cc
1 /*
2  * libjingle
3  * Copyright 2010, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <string>
29 #include "webrtc/p2p/base/sessionmanager.h"
30 #include "webrtc/p2p/base/transport.h"
31 #include "webrtc/p2p/client/fakeportallocator.h"
32 #include "talk/session/tunnel/tunnelsessionclient.h"
33 #include "webrtc/base/gunit.h"
34 #include "webrtc/base/messagehandler.h"
35 #include "webrtc/base/scoped_ptr.h"
36 #include "webrtc/base/stream.h"
37 #include "webrtc/base/thread.h"
38 #include "webrtc/base/timeutils.h"
39
40 static const int kTimeoutMs = 10000;
41 static const int kBlockSize = 4096;
42 static const buzz::Jid kLocalJid("local@localhost");
43 static const buzz::Jid kRemoteJid("remote@localhost");
44
45 // This test fixture creates the necessary plumbing to create and run
46 // two TunnelSessionClients that talk to each other.
47 class TunnelSessionClientTest : public testing::Test,
48                                 public rtc::MessageHandler,
49                                 public sigslot::has_slots<> {
50  public:
51   TunnelSessionClientTest()
52       : local_pa_(rtc::Thread::Current(), NULL),
53         remote_pa_(rtc::Thread::Current(), NULL),
54         local_sm_(&local_pa_, rtc::Thread::Current()),
55         remote_sm_(&remote_pa_, rtc::Thread::Current()),
56         local_client_(kLocalJid, &local_sm_),
57         remote_client_(kRemoteJid, &remote_sm_),
58         done_(false) {
59     local_sm_.SignalRequestSignaling.connect(this,
60         &TunnelSessionClientTest::OnLocalRequestSignaling);
61     local_sm_.SignalOutgoingMessage.connect(this,
62         &TunnelSessionClientTest::OnOutgoingMessage);
63     remote_sm_.SignalRequestSignaling.connect(this,
64         &TunnelSessionClientTest::OnRemoteRequestSignaling);
65     remote_sm_.SignalOutgoingMessage.connect(this,
66         &TunnelSessionClientTest::OnOutgoingMessage);
67     remote_client_.SignalIncomingTunnel.connect(this,
68         &TunnelSessionClientTest::OnIncomingTunnel);
69   }
70
71   // Transfer the desired amount of data from the local to the remote client.
72   void TestTransfer(int size) {
73     // Create some dummy data to send.
74     send_stream_.ReserveSize(size);
75     for (int i = 0; i < size; ++i) {
76       char ch = static_cast<char>(i);
77       send_stream_.Write(&ch, 1, NULL, NULL);
78     }
79     send_stream_.Rewind();
80     // Prepare the receive stream.
81     recv_stream_.ReserveSize(size);
82     // Create the tunnel and set things in motion.
83     local_tunnel_.reset(local_client_.CreateTunnel(kRemoteJid, "test"));
84     local_tunnel_->SignalEvent.connect(this,
85         &TunnelSessionClientTest::OnStreamEvent);
86     EXPECT_TRUE_WAIT(done_, kTimeoutMs);
87     // Make sure we received the right data.
88     EXPECT_EQ(0, memcmp(send_stream_.GetBuffer(),
89                         recv_stream_.GetBuffer(), size));
90   }
91
92  private:
93   enum { MSG_LSIGNAL, MSG_RSIGNAL };
94
95   // There's no SessionManager* argument in this callback, so we need 2 of them.
96   void OnLocalRequestSignaling() {
97     local_sm_.OnSignalingReady();
98   }
99   void OnRemoteRequestSignaling() {
100     remote_sm_.OnSignalingReady();
101   }
102
103   // Post a message, to avoid problems with directly connecting the callbacks.
104   void OnOutgoingMessage(cricket::SessionManager* manager,
105                          const buzz::XmlElement* stanza) {
106     if (manager == &local_sm_) {
107       rtc::Thread::Current()->Post(this, MSG_LSIGNAL,
108           rtc::WrapMessageData(*stanza));
109     } else if (manager == &remote_sm_) {
110       rtc::Thread::Current()->Post(this, MSG_RSIGNAL,
111           rtc::WrapMessageData(*stanza));
112     }
113   }
114
115   // Need to add a "from=" attribute (normally added by the server)
116   // Then route the incoming signaling message to the "other" session manager.
117   virtual void OnMessage(rtc::Message* message) {
118     rtc::TypedMessageData<buzz::XmlElement>* data =
119         static_cast<rtc::TypedMessageData<buzz::XmlElement>*>(
120             message->pdata);
121     bool response = data->data().Attr(buzz::QN_TYPE) == buzz::STR_RESULT;
122     if (message->message_id == MSG_RSIGNAL) {
123       data->data().AddAttr(buzz::QN_FROM, remote_client_.jid().Str());
124       if (!response) {
125         local_sm_.OnIncomingMessage(&data->data());
126       } else {
127         local_sm_.OnIncomingResponse(NULL, &data->data());
128       }
129     } else if (message->message_id == MSG_LSIGNAL) {
130       data->data().AddAttr(buzz::QN_FROM, local_client_.jid().Str());
131       if (!response) {
132         remote_sm_.OnIncomingMessage(&data->data());
133       } else {
134         remote_sm_.OnIncomingResponse(NULL, &data->data());
135       }
136     }
137     delete data;
138   }
139
140   // Accept the tunnel when it arrives and wire up the stream.
141   void OnIncomingTunnel(cricket::TunnelSessionClient* client,
142                         buzz::Jid jid, std::string description,
143                         cricket::Session* session) {
144     remote_tunnel_.reset(remote_client_.AcceptTunnel(session));
145     remote_tunnel_->SignalEvent.connect(this,
146         &TunnelSessionClientTest::OnStreamEvent);
147   }
148
149   // Send from send_stream_ as long as we're not flow-controlled.
150   // Read bytes out into recv_stream_ as they arrive.
151   // End the test when we are notified that the local side has closed the
152   // tunnel. All data has been read out at this point.
153   void OnStreamEvent(rtc::StreamInterface* stream, int events,
154                      int error) {
155     if (events & rtc::SE_READ) {
156       if (stream == remote_tunnel_.get()) {
157         ReadData();
158       }
159     }
160     if (events & rtc::SE_WRITE) {
161       if (stream == local_tunnel_.get()) {
162         bool done = false;
163         WriteData(&done);
164         if (done) {
165           local_tunnel_->Close();
166         }
167       }
168     }
169     if (events & rtc::SE_CLOSE) {
170       if (stream == remote_tunnel_.get()) {
171         remote_tunnel_->Close();
172         done_ = true;
173       }
174     }
175   }
176
177   // Spool from the tunnel into recv_stream.
178   // Flow() doesn't work here because it won't write if the read blocks.
179   void ReadData() {
180     char block[kBlockSize];
181     size_t read, position;
182     rtc::StreamResult res;
183     while ((res = remote_tunnel_->Read(block, sizeof(block), &read, NULL)) ==
184         rtc::SR_SUCCESS) {
185       recv_stream_.Write(block, read, NULL, NULL);
186     }
187     ASSERT(res != rtc::SR_EOS);
188     recv_stream_.GetPosition(&position);
189     LOG(LS_VERBOSE) << "Recv position: " << position;
190   }
191   // Spool from send_stream into the tunnel. Back up if we get flow controlled.
192   void WriteData(bool* done) {
193     char block[kBlockSize];
194     size_t leftover = 0, position;
195     rtc::StreamResult res = rtc::Flow(&send_stream_,
196         block, sizeof(block), local_tunnel_.get(), &leftover);
197     if (res == rtc::SR_BLOCK) {
198       send_stream_.GetPosition(&position);
199       send_stream_.SetPosition(position - leftover);
200       LOG(LS_VERBOSE) << "Send position: " << position - leftover;
201       *done = false;
202     } else if (res == rtc::SR_SUCCESS) {
203       *done = true;
204     } else {
205       ASSERT(false);  // shouldn't happen
206     }
207   }
208
209  private:
210   cricket::FakePortAllocator local_pa_;
211   cricket::FakePortAllocator remote_pa_;
212   cricket::SessionManager local_sm_;
213   cricket::SessionManager remote_sm_;
214   cricket::TunnelSessionClient local_client_;
215   cricket::TunnelSessionClient remote_client_;
216   rtc::scoped_ptr<rtc::StreamInterface> local_tunnel_;
217   rtc::scoped_ptr<rtc::StreamInterface> remote_tunnel_;
218   rtc::MemoryStream send_stream_;
219   rtc::MemoryStream recv_stream_;
220   bool done_;
221 };
222
223 // Test the normal case of sending data from one side to the other.
224 TEST_F(TunnelSessionClientTest, TestTransfer) {
225   TestTransfer(1000000);
226 }