blob: 1c08bf18dd08cd1de9e36c2f62eeebb0b09645b9 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004 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
pbos@webrtc.org371243d2014-03-07 15:22:04 +000028#include <string.h>
29
henrike@webrtc.org28e20752013-07-10 00:45:36 +000030#include <sstream>
31#include <deque>
32#include <map>
33
34#include "talk/base/base64.h"
35#include "talk/base/common.h"
36#include "talk/base/gunit.h"
37#include "talk/base/helpers.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038#include "talk/base/logging.h"
39#include "talk/base/natserver.h"
40#include "talk/base/natsocketfactory.h"
41#include "talk/base/stringencode.h"
42#include "talk/p2p/base/basicpacketsocketfactory.h"
43#include "talk/p2p/base/constants.h"
44#include "talk/p2p/base/parsing.h"
45#include "talk/p2p/base/portallocator.h"
46#include "talk/p2p/base/p2ptransport.h"
47#include "talk/p2p/base/relayport.h"
48#include "talk/p2p/base/relayserver.h"
49#include "talk/p2p/base/session.h"
50#include "talk/p2p/base/sessionclient.h"
51#include "talk/p2p/base/sessionmanager.h"
52#include "talk/p2p/base/stunport.h"
53#include "talk/p2p/base/stunserver.h"
54#include "talk/p2p/base/transportchannel.h"
55#include "talk/p2p/base/transportchannelproxy.h"
56#include "talk/p2p/base/udpport.h"
57#include "talk/xmpp/constants.h"
58
59using cricket::SignalingProtocol;
60using cricket::PROTOCOL_HYBRID;
61using cricket::PROTOCOL_JINGLE;
62using cricket::PROTOCOL_GINGLE;
63
64static const std::string kInitiator = "init@init.com";
65static const std::string kResponder = "resp@resp.com";
66// Expected from test random number generator.
67static const std::string kSessionId = "9254631414740579489";
68// TODO: When we need to test more than one transport type,
69// allow this to be injected like the content types are.
70static const std::string kTransportType = "http://www.google.com/transport/p2p";
71
72// Controls how long we wait for a session to send messages that we
73// expect, in milliseconds. We put it high to avoid flaky tests.
74static const int kEventTimeout = 5000;
75
76static const int kNumPorts = 2;
77static const int kPort0 = 28653;
78static const int kPortStep = 5;
79
henrike@webrtc.org28e20752013-07-10 00:45:36 +000080int GetPort(int port_index) {
81 return kPort0 + (port_index * kPortStep);
82}
83
84std::string GetPortString(int port_index) {
85 return talk_base::ToString(GetPort(port_index));
86}
87
88// Only works for port_index < 10, which is fine for our purposes.
89std::string GetUsername(int port_index) {
90 return "username" + std::string(8, talk_base::ToString(port_index)[0]);
91}
92
93// Only works for port_index < 10, which is fine for our purposes.
94std::string GetPassword(int port_index) {
95 return "password" + std::string(8, talk_base::ToString(port_index)[0]);
96}
97
98std::string IqAck(const std::string& id,
99 const std::string& from,
100 const std::string& to) {
101 return "<cli:iq"
102 " to=\"" + to + "\""
103 " id=\"" + id + "\""
104 " type=\"result\""
105 " from=\"" + from + "\""
106 " xmlns:cli=\"jabber:client\""
107 "/>";
108}
109
110std::string IqSet(const std::string& id,
111 const std::string& from,
112 const std::string& to,
113 const std::string& content) {
114 return "<cli:iq"
115 " to=\"" + to + "\""
116 " type=\"set\""
117 " from=\"" + from + "\""
118 " id=\"" + id + "\""
119 " xmlns:cli=\"jabber:client\""
120 ">"
121 + content +
122 "</cli:iq>";
123}
124
125std::string IqError(const std::string& id,
126 const std::string& from,
127 const std::string& to,
128 const std::string& content) {
129 return "<cli:error"
130 " to=\"" + to + "\""
131 " type=\"error\""
132 " from=\"" + from + "\""
133 " id=\"" + id + "\""
134 " xmlns:cli=\"jabber:client\""
135 ">"
136 + content +
137 "</cli:error>";
138}
139
140std::string GingleSessionXml(const std::string& type,
141 const std::string& content) {
142 return "<session"
143 " xmlns=\"http://www.google.com/session\""
144 " type=\"" + type + "\""
145 " id=\"" + kSessionId + "\""
146 " initiator=\"" + kInitiator + "\""
147 ">"
148 + content +
149 "</session>";
150}
151
152std::string GingleDescriptionXml(const std::string& content_type) {
153 return "<description"
154 " xmlns=\"" + content_type + "\""
155 "/>";
156}
157
158std::string P2pCandidateXml(const std::string& name, int port_index) {
159 // Port will update the rtcp username by +1 on the last character. So we need
160 // to compensate here. See Port::username_fragment() for detail.
161 std::string username = GetUsername(port_index);
162 // TODO: Use the component id instead of the channel name to
163 // determinte if we need to covert the username here.
164 if (name == "rtcp" || name == "video_rtcp" || name == "chanb") {
165 char next_ch = username[username.size() - 1];
166 ASSERT(username.size() > 0);
167 talk_base::Base64::GetNextBase64Char(next_ch, &next_ch);
168 username[username.size() - 1] = next_ch;
169 }
170 return "<candidate"
171 " name=\"" + name + "\""
172 " address=\"127.0.0.1\""
173 " port=\"" + GetPortString(port_index) + "\""
174 " preference=\"0.99\""
175 " username=\"" + username + "\""
176 " protocol=\"udp\""
177 " generation=\"0\""
178 " password=\"" + GetPassword(port_index) + "\""
179 " type=\"local\""
180 " network=\"network\""
181 "/>";
182}
183
184std::string JingleActionXml(const std::string& action,
185 const std::string& content) {
186 return "<jingle"
187 " xmlns=\"urn:xmpp:jingle:1\""
188 " action=\"" + action + "\""
189 " sid=\"" + kSessionId + "\""
190 ">"
191 + content +
192 "</jingle>";
193}
194
195std::string JingleInitiateActionXml(const std::string& content) {
196 return "<jingle"
197 " xmlns=\"urn:xmpp:jingle:1\""
198 " action=\"session-initiate\""
199 " sid=\"" + kSessionId + "\""
200 " initiator=\"" + kInitiator + "\""
201 ">"
202 + content +
203 "</jingle>";
204}
205
206std::string JingleGroupInfoXml(const std::string& content_name_a,
207 const std::string& content_name_b) {
208 std::string group_info = "<jin:group"
209 " type=\"BUNDLE\""
210 " xmlns:jin=\"google:jingle\""
211 ">";
212 if (!content_name_a.empty())
213 group_info += "<content name=\"" + content_name_a + "\""
214 "/>";
215 if (!content_name_b.empty())
216 group_info += "<content name=\"" + content_name_b + "\""
217 "/>";
218 group_info += "</jin:group>";
219 return group_info;
220}
221
222
223std::string JingleEmptyContentXml(const std::string& content_name,
224 const std::string& content_type,
225 const std::string& transport_type) {
226 return "<content"
227 " name=\"" + content_name + "\""
228 " creator=\"initiator\""
229 ">"
230 "<description"
231 " xmlns=\"" + content_type + "\""
232 "/>"
233 "<transport"
234 " xmlns=\"" + transport_type + "\""
235 "/>"
236 "</content>";
237}
238
239std::string JingleContentXml(const std::string& content_name,
240 const std::string& content_type,
241 const std::string& transport_type,
242 const std::string& transport_main) {
243 std::string transport = transport_type.empty() ? "" :
244 "<transport"
245 " xmlns=\"" + transport_type + "\""
246 ">"
247 + transport_main +
248 "</transport>";
249
250 return"<content"
251 " name=\"" + content_name + "\""
252 " creator=\"initiator\""
253 ">"
254 "<description"
255 " xmlns=\"" + content_type + "\""
256 "/>"
257 + transport +
258 "</content>";
259}
260
261std::string JingleTransportContentXml(const std::string& content_name,
262 const std::string& transport_type,
263 const std::string& content) {
264 return "<content"
265 " name=\"" + content_name + "\""
266 " creator=\"initiator\""
267 ">"
268 "<transport"
269 " xmlns=\"" + transport_type + "\""
270 ">"
271 + content +
272 "</transport>"
273 "</content>";
274}
275
276std::string GingleInitiateXml(const std::string& content_type) {
277 return GingleSessionXml(
278 "initiate",
279 GingleDescriptionXml(content_type));
280}
281
282std::string JingleInitiateXml(const std::string& content_name_a,
283 const std::string& content_type_a,
284 const std::string& content_name_b,
285 const std::string& content_type_b,
286 bool bundle = false) {
287 std::string content_xml;
288 if (content_name_b.empty()) {
289 content_xml = JingleEmptyContentXml(
290 content_name_a, content_type_a, kTransportType);
291 } else {
292 content_xml = JingleEmptyContentXml(
293 content_name_a, content_type_a, kTransportType) +
294 JingleEmptyContentXml(
295 content_name_b, content_type_b, kTransportType);
296 if (bundle) {
297 content_xml += JingleGroupInfoXml(content_name_a, content_name_b);
298 }
299 }
300 return JingleInitiateActionXml(content_xml);
301}
302
303std::string GingleAcceptXml(const std::string& content_type) {
304 return GingleSessionXml(
305 "accept",
306 GingleDescriptionXml(content_type));
307}
308
309std::string JingleAcceptXml(const std::string& content_name_a,
310 const std::string& content_type_a,
311 const std::string& content_name_b,
312 const std::string& content_type_b,
313 bool bundle = false) {
314 std::string content_xml;
315 if (content_name_b.empty()) {
316 content_xml = JingleEmptyContentXml(
317 content_name_a, content_type_a, kTransportType);
318 } else {
319 content_xml = JingleEmptyContentXml(
320 content_name_a, content_type_a, kTransportType) +
321 JingleEmptyContentXml(
322 content_name_b, content_type_b, kTransportType);
323 }
324 if (bundle) {
325 content_xml += JingleGroupInfoXml(content_name_a, content_name_b);
326 }
327
328 return JingleActionXml("session-accept", content_xml);
329}
330
331std::string Gingle2CandidatesXml(const std::string& channel_name,
332 int port_index0,
333 int port_index1) {
334 return GingleSessionXml(
335 "candidates",
336 P2pCandidateXml(channel_name, port_index0) +
337 P2pCandidateXml(channel_name, port_index1));
338}
339
340std::string Gingle4CandidatesXml(const std::string& channel_name_a,
341 int port_index0,
342 int port_index1,
343 const std::string& channel_name_b,
344 int port_index2,
345 int port_index3) {
346 return GingleSessionXml(
347 "candidates",
348 P2pCandidateXml(channel_name_a, port_index0) +
349 P2pCandidateXml(channel_name_a, port_index1) +
350 P2pCandidateXml(channel_name_b, port_index2) +
351 P2pCandidateXml(channel_name_b, port_index3));
352}
353
354std::string Jingle2TransportInfoXml(const std::string& content_name,
355 const std::string& channel_name,
356 int port_index0,
357 int port_index1) {
358 return JingleActionXml(
359 "transport-info",
360 JingleTransportContentXml(
361 content_name, kTransportType,
362 P2pCandidateXml(channel_name, port_index0) +
363 P2pCandidateXml(channel_name, port_index1)));
364}
365
366std::string Jingle4TransportInfoXml(const std::string& content_name,
367 const std::string& channel_name_a,
368 int port_index0,
369 int port_index1,
370 const std::string& channel_name_b,
371 int port_index2,
372 int port_index3) {
373 return JingleActionXml(
374 "transport-info",
375 JingleTransportContentXml(
376 content_name, kTransportType,
377 P2pCandidateXml(channel_name_a, port_index0) +
378 P2pCandidateXml(channel_name_a, port_index1) +
379 P2pCandidateXml(channel_name_b, port_index2) +
380 P2pCandidateXml(channel_name_b, port_index3)));
381}
382
383std::string JingleDescriptionInfoXml(const std::string& content_name,
384 const std::string& content_type) {
385 return JingleActionXml(
386 "description-info",
387 JingleContentXml(content_name, content_type, "", ""));
388}
389
390std::string GingleRejectXml(const std::string& reason) {
391 return GingleSessionXml(
392 "reject",
393 "<" + reason + "/>");
394}
395
396std::string JingleTerminateXml(const std::string& reason) {
397 return JingleActionXml(
398 "session-terminate",
399 "<reason><" + reason + "/></reason>");
400}
401
402std::string GingleTerminateXml(const std::string& reason) {
403 return GingleSessionXml(
404 "terminate",
405 "<" + reason + "/>");
406}
407
408std::string GingleRedirectXml(const std::string& intitiate,
409 const std::string& target) {
410 return intitiate +
411 "<error code=\"302\" type=\"modify\">"
412 "<redirect xmlns=\"http://www.google.com/session\">"
413 "xmpp:" + target +
414 "</redirect>"
415 "</error>";
416}
417
418std::string JingleRedirectXml(const std::string& intitiate,
419 const std::string& target) {
420 return intitiate +
421 "<error code=\"302\" type=\"modify\">"
422 "<redirect xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\">"
423 "xmpp:" + target +
424 "</redirect>"
425 "</error>";
426}
427
428std::string InitiateXml(SignalingProtocol protocol,
429 const std::string& gingle_content_type,
430 const std::string& content_name_a,
431 const std::string& content_type_a,
432 const std::string& content_name_b,
433 const std::string& content_type_b,
434 bool bundle = false) {
435 switch (protocol) {
436 case PROTOCOL_JINGLE:
437 return JingleInitiateXml(content_name_a, content_type_a,
438 content_name_b, content_type_b,
439 bundle);
440 case PROTOCOL_GINGLE:
441 return GingleInitiateXml(gingle_content_type);
442 case PROTOCOL_HYBRID:
443 return JingleInitiateXml(content_name_a, content_type_a,
444 content_name_b, content_type_b) +
445 GingleInitiateXml(gingle_content_type);
446 }
447 return "";
448}
449
450std::string InitiateXml(SignalingProtocol protocol,
451 const std::string& content_name,
452 const std::string& content_type) {
453 return InitiateXml(protocol,
454 content_type,
455 content_name, content_type,
456 "", "");
457}
458
459std::string AcceptXml(SignalingProtocol protocol,
460 const std::string& gingle_content_type,
461 const std::string& content_name_a,
462 const std::string& content_type_a,
463 const std::string& content_name_b,
464 const std::string& content_type_b,
465 bool bundle = false) {
466 switch (protocol) {
467 case PROTOCOL_JINGLE:
468 return JingleAcceptXml(content_name_a, content_type_a,
469 content_name_b, content_type_b, bundle);
470 case PROTOCOL_GINGLE:
471 return GingleAcceptXml(gingle_content_type);
472 case PROTOCOL_HYBRID:
473 return
474 JingleAcceptXml(content_name_a, content_type_a,
475 content_name_b, content_type_b) +
476 GingleAcceptXml(gingle_content_type);
477 }
478 return "";
479}
480
481
482std::string AcceptXml(SignalingProtocol protocol,
483 const std::string& content_name,
484 const std::string& content_type,
485 bool bundle = false) {
486 return AcceptXml(protocol,
487 content_type,
488 content_name, content_type,
489 "", "");
490}
491
492std::string TransportInfo2Xml(SignalingProtocol protocol,
493 const std::string& content_name,
494 const std::string& channel_name,
495 int port_index0,
496 int port_index1) {
497 switch (protocol) {
498 case PROTOCOL_JINGLE:
499 return Jingle2TransportInfoXml(
500 content_name,
501 channel_name, port_index0, port_index1);
502 case PROTOCOL_GINGLE:
503 return Gingle2CandidatesXml(
504 channel_name, port_index0, port_index1);
505 case PROTOCOL_HYBRID:
506 return
507 Jingle2TransportInfoXml(
508 content_name,
509 channel_name, port_index0, port_index1) +
510 Gingle2CandidatesXml(
511 channel_name, port_index0, port_index1);
512 }
513 return "";
514}
515
516std::string TransportInfo4Xml(SignalingProtocol protocol,
517 const std::string& content_name,
518 const std::string& channel_name_a,
519 int port_index0,
520 int port_index1,
521 const std::string& channel_name_b,
522 int port_index2,
523 int port_index3) {
524 switch (protocol) {
525 case PROTOCOL_JINGLE:
526 return Jingle4TransportInfoXml(
527 content_name,
528 channel_name_a, port_index0, port_index1,
529 channel_name_b, port_index2, port_index3);
530 case PROTOCOL_GINGLE:
531 return Gingle4CandidatesXml(
532 channel_name_a, port_index0, port_index1,
533 channel_name_b, port_index2, port_index3);
534 case PROTOCOL_HYBRID:
535 return
536 Jingle4TransportInfoXml(
537 content_name,
538 channel_name_a, port_index0, port_index1,
539 channel_name_b, port_index2, port_index3) +
540 Gingle4CandidatesXml(
541 channel_name_a, port_index0, port_index1,
542 channel_name_b, port_index2, port_index3);
543 }
544 return "";
545}
546
547std::string RejectXml(SignalingProtocol protocol,
548 const std::string& reason) {
549 switch (protocol) {
550 case PROTOCOL_JINGLE:
551 return JingleTerminateXml(reason);
552 case PROTOCOL_GINGLE:
553 return GingleRejectXml(reason);
554 case PROTOCOL_HYBRID:
555 return JingleTerminateXml(reason) +
556 GingleRejectXml(reason);
557 }
558 return "";
559}
560
561std::string TerminateXml(SignalingProtocol protocol,
562 const std::string& reason) {
563 switch (protocol) {
564 case PROTOCOL_JINGLE:
565 return JingleTerminateXml(reason);
566 case PROTOCOL_GINGLE:
567 return GingleTerminateXml(reason);
568 case PROTOCOL_HYBRID:
569 return JingleTerminateXml(reason) +
570 GingleTerminateXml(reason);
571 }
572 return "";
573}
574
575std::string RedirectXml(SignalingProtocol protocol,
576 const std::string& initiate,
577 const std::string& target) {
578 switch (protocol) {
579 case PROTOCOL_JINGLE:
580 return JingleRedirectXml(initiate, target);
581 case PROTOCOL_GINGLE:
582 return GingleRedirectXml(initiate, target);
583 default:
584 break;
585 }
586 return "";
587}
588
589// TODO: Break out and join with fakeportallocator.h
590class TestPortAllocatorSession : public cricket::PortAllocatorSession {
591 public:
592 TestPortAllocatorSession(const std::string& content_name,
593 int component,
594 const std::string& ice_ufrag,
595 const std::string& ice_pwd,
596 const int port_offset)
597 : PortAllocatorSession(content_name, component, ice_ufrag, ice_pwd, 0),
598 port_offset_(port_offset),
599 ports_(kNumPorts),
600 address_("127.0.0.1", 0),
601 network_("network", "unittest",
602 talk_base::IPAddress(INADDR_LOOPBACK), 8),
603 socket_factory_(talk_base::Thread::Current()),
604 running_(false),
605 port_(28653) {
606 network_.AddIP(address_.ipaddr());
607 }
608
609 ~TestPortAllocatorSession() {
610 for (size_t i = 0; i < ports_.size(); i++)
611 delete ports_[i];
612 }
613
614 virtual void StartGettingPorts() {
615 for (int i = 0; i < kNumPorts; i++) {
616 int index = port_offset_ + i;
617 ports_[i] = cricket::UDPPort::Create(
618 talk_base::Thread::Current(), &socket_factory_,
619 &network_, address_.ipaddr(), GetPort(index), GetPort(index),
620 GetUsername(index), GetPassword(index));
621 AddPort(ports_[i]);
622 }
623 running_ = true;
624 }
625
626 virtual void StopGettingPorts() { running_ = false; }
627 virtual bool IsGettingPorts() { return running_; }
628
629 void AddPort(cricket::Port* port) {
630 port->set_component(component_);
631 port->set_generation(0);
632 port->SignalDestroyed.connect(
633 this, &TestPortAllocatorSession::OnPortDestroyed);
634 port->SignalPortComplete.connect(
635 this, &TestPortAllocatorSession::OnPortComplete);
636 port->PrepareAddress();
637 SignalPortReady(this, port);
638 }
639
640 void OnPortDestroyed(cricket::PortInterface* port) {
641 for (size_t i = 0; i < ports_.size(); i++) {
642 if (ports_[i] == port)
643 ports_[i] = NULL;
644 }
645 }
646
647 void OnPortComplete(cricket::Port* port) {
648 SignalCandidatesReady(this, port->Candidates());
649 }
650
651 private:
652 int port_offset_;
653 std::vector<cricket::Port*> ports_;
654 talk_base::SocketAddress address_;
655 talk_base::Network network_;
656 talk_base::BasicPacketSocketFactory socket_factory_;
657 bool running_;
658 int port_;
659};
660
661class TestPortAllocator : public cricket::PortAllocator {
662 public:
663 TestPortAllocator() : port_offset_(0) {}
664
665 virtual cricket::PortAllocatorSession*
666 CreateSessionInternal(
667 const std::string& content_name,
668 int component,
669 const std::string& ice_ufrag,
670 const std::string& ice_pwd) {
671 port_offset_ += 2;
672 return new TestPortAllocatorSession(content_name, component,
673 ice_ufrag, ice_pwd, port_offset_ - 2);
674 }
675
676 int port_offset_;
677};
678
679class TestContentDescription : public cricket::ContentDescription {
680 public:
681 explicit TestContentDescription(const std::string& gingle_content_type,
682 const std::string& content_type)
683 : gingle_content_type(gingle_content_type),
684 content_type(content_type) {
685 }
686 virtual ContentDescription* Copy() const {
687 return new TestContentDescription(*this);
688 }
689
690 std::string gingle_content_type;
691 std::string content_type;
692};
693
694cricket::SessionDescription* NewTestSessionDescription(
695 const std::string gingle_content_type,
696 const std::string& content_name_a, const std::string& content_type_a,
697 const std::string& content_name_b, const std::string& content_type_b) {
698
699 cricket::SessionDescription* offer = new cricket::SessionDescription();
700 offer->AddContent(content_name_a, content_type_a,
701 new TestContentDescription(gingle_content_type,
702 content_type_a));
703 cricket::TransportDescription desc(cricket::NS_GINGLE_P2P,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000704 std::string(), std::string());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000705 offer->AddTransportInfo(cricket::TransportInfo(content_name_a, desc));
706
707 if (content_name_a != content_name_b) {
708 offer->AddContent(content_name_b, content_type_b,
709 new TestContentDescription(gingle_content_type,
710 content_type_b));
711 offer->AddTransportInfo(cricket::TransportInfo(content_name_b, desc));
712 }
713 return offer;
714}
715
716cricket::SessionDescription* NewTestSessionDescription(
717 const std::string& content_name, const std::string& content_type) {
718
719 cricket::SessionDescription* offer = new cricket::SessionDescription();
720 offer->AddContent(content_name, content_type,
721 new TestContentDescription(content_type,
722 content_type));
723 offer->AddTransportInfo(cricket::TransportInfo
724 (content_name, cricket::TransportDescription(
725 cricket::NS_GINGLE_P2P,
sergeyu@chromium.org0be6aa02013-08-23 23:21:25 +0000726 std::string(), std::string())));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727 return offer;
728}
729
730struct TestSessionClient: public cricket::SessionClient,
731 public sigslot::has_slots<> {
732 public:
733 TestSessionClient() {
734 }
735
736 ~TestSessionClient() {
737 }
738
739 virtual bool ParseContent(SignalingProtocol protocol,
740 const buzz::XmlElement* elem,
741 cricket::ContentDescription** content,
742 cricket::ParseError* error) {
743 std::string content_type;
744 std::string gingle_content_type;
745 if (protocol == PROTOCOL_GINGLE) {
746 gingle_content_type = elem->Name().Namespace();
747 } else {
748 content_type = elem->Name().Namespace();
749 }
750
751 *content = new TestContentDescription(gingle_content_type, content_type);
752 return true;
753 }
754
755 virtual bool WriteContent(SignalingProtocol protocol,
756 const cricket::ContentDescription* untyped_content,
757 buzz::XmlElement** elem,
758 cricket::WriteError* error) {
759 const TestContentDescription* content =
760 static_cast<const TestContentDescription*>(untyped_content);
761 std::string content_type = (protocol == PROTOCOL_GINGLE ?
762 content->gingle_content_type :
763 content->content_type);
764 *elem = new buzz::XmlElement(
765 buzz::QName(content_type, "description"), true);
766 return true;
767 }
768
769 void OnSessionCreate(cricket::Session* session, bool initiate) {
770 }
771
772 void OnSessionDestroy(cricket::Session* session) {
773 }
774};
775
776struct ChannelHandler : sigslot::has_slots<> {
777 explicit ChannelHandler(cricket::TransportChannel* p, const std::string& name)
778 : channel(p), last_readable(false), last_writable(false), data_count(0),
779 last_size(0), name(name) {
780 p->SignalReadableState.connect(this, &ChannelHandler::OnReadableState);
781 p->SignalWritableState.connect(this, &ChannelHandler::OnWritableState);
782 p->SignalReadPacket.connect(this, &ChannelHandler::OnReadPacket);
783 }
784
785 bool writable() const {
786 return last_writable && channel->writable();
787 }
788
789 bool readable() const {
790 return last_readable && channel->readable();
791 }
792
793 void OnReadableState(cricket::TransportChannel* p) {
794 EXPECT_EQ(channel, p);
795 last_readable = channel->readable();
796 }
797
798 void OnWritableState(cricket::TransportChannel* p) {
799 EXPECT_EQ(channel, p);
800 last_writable = channel->writable();
801 }
802
803 void OnReadPacket(cricket::TransportChannel* p, const char* buf,
wu@webrtc.orga9890802013-12-13 00:21:03 +0000804 size_t size, const talk_base::PacketTime& time, int flags) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000805 if (memcmp(buf, name.c_str(), name.size()) != 0)
806 return; // drop packet if packet doesn't belong to this channel. This
807 // can happen when transport channels are muxed together.
808 buf += name.size(); // Remove channel name from the message.
809 size -= name.size(); // Decrement size by channel name string size.
810 EXPECT_EQ(channel, p);
811 EXPECT_LE(size, sizeof(last_data));
812 data_count += 1;
813 last_size = size;
pbos@webrtc.org371243d2014-03-07 15:22:04 +0000814 memcpy(last_data, buf, size);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000815 }
816
817 void Send(const char* data, size_t size) {
mallinath@webrtc.org385857d2014-02-14 00:56:12 +0000818 talk_base::PacketOptions options;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000819 std::string data_with_id(name);
820 data_with_id += data;
821 int result = channel->SendPacket(data_with_id.c_str(), data_with_id.size(),
mallinath@webrtc.org385857d2014-02-14 00:56:12 +0000822 options, 0);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000823 EXPECT_EQ(static_cast<int>(data_with_id.size()), result);
824 }
825
826 cricket::TransportChannel* channel;
827 bool last_readable, last_writable;
828 int data_count;
829 char last_data[4096];
830 size_t last_size;
831 std::string name;
832};
833
834void PrintStanza(const std::string& message,
835 const buzz::XmlElement* stanza) {
836 printf("%s: %s\n", message.c_str(), stanza->Str().c_str());
837}
838
839class TestClient : public sigslot::has_slots<> {
840 public:
841 // TODO: Add channel_component_a/b as inputs to the ctor.
842 TestClient(cricket::PortAllocator* port_allocator,
843 int* next_message_id,
844 const std::string& local_name,
845 SignalingProtocol start_protocol,
846 const std::string& content_type,
847 const std::string& content_name_a,
848 const std::string& channel_name_a,
849 const std::string& content_name_b,
850 const std::string& channel_name_b) {
851 Construct(port_allocator, next_message_id, local_name, start_protocol,
852 content_type, content_name_a, channel_name_a,
853 content_name_b, channel_name_b);
854 }
855
856 ~TestClient() {
857 if (session) {
858 session_manager->DestroySession(session);
859 EXPECT_EQ(1U, session_destroyed_count);
860 }
861 delete session_manager;
862 delete client;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000863 for (std::deque<buzz::XmlElement*>::iterator it = sent_stanzas.begin();
864 it != sent_stanzas.end(); ++it) {
865 delete *it;
866 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000867 }
868
869 void Construct(cricket::PortAllocator* pa,
870 int* message_id,
871 const std::string& lname,
872 SignalingProtocol protocol,
873 const std::string& cont_type,
874 const std::string& cont_name_a,
875 const std::string& chan_name_a,
876 const std::string& cont_name_b,
877 const std::string& chan_name_b) {
878 port_allocator_ = pa;
879 next_message_id = message_id;
880 local_name = lname;
881 start_protocol = protocol;
882 content_type = cont_type;
883 content_name_a = cont_name_a;
884 channel_name_a = chan_name_a;
885 content_name_b = cont_name_b;
886 channel_name_b = chan_name_b;
887 session_created_count = 0;
888 session_destroyed_count = 0;
889 session_remote_description_update_count = 0;
890 new_local_description = false;
891 new_remote_description = false;
892 last_content_action = cricket::CA_OFFER;
893 last_content_source = cricket::CS_LOCAL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000894 session = NULL;
895 last_session_state = cricket::BaseSession::STATE_INIT;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000896 blow_up_on_error = true;
897 error_count = 0;
898
899 session_manager = new cricket::SessionManager(port_allocator_);
900 session_manager->SignalSessionCreate.connect(
901 this, &TestClient::OnSessionCreate);
902 session_manager->SignalSessionDestroy.connect(
903 this, &TestClient::OnSessionDestroy);
904 session_manager->SignalOutgoingMessage.connect(
905 this, &TestClient::OnOutgoingMessage);
906
907 client = new TestSessionClient();
908 session_manager->AddClient(content_type, client);
909 EXPECT_EQ(client, session_manager->GetClient(content_type));
910 }
911
912 uint32 sent_stanza_count() const {
henrike@webrtc.org28654cb2013-07-22 21:07:49 +0000913 return static_cast<uint32>(sent_stanzas.size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000914 }
915
916 const buzz::XmlElement* stanza() const {
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000917 return last_expected_sent_stanza.get();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000918 }
919
920 cricket::BaseSession::State session_state() const {
921 EXPECT_EQ(last_session_state, session->state());
922 return session->state();
923 }
924
925 void SetSessionState(cricket::BaseSession::State state) {
926 session->SetState(state);
927 EXPECT_EQ_WAIT(last_session_state, session->state(), kEventTimeout);
928 }
929
930 void CreateSession() {
931 session_manager->CreateSession(local_name, content_type);
932 }
933
934 void DeliverStanza(const buzz::XmlElement* stanza) {
935 session_manager->OnIncomingMessage(stanza);
936 }
937
938 void DeliverStanza(const std::string& str) {
939 buzz::XmlElement* stanza = buzz::XmlElement::ForStr(str);
940 session_manager->OnIncomingMessage(stanza);
941 delete stanza;
942 }
943
944 void DeliverAckToLastStanza() {
945 const buzz::XmlElement* orig_stanza = stanza();
946 const buzz::XmlElement* response_stanza =
947 buzz::XmlElement::ForStr(IqAck(orig_stanza->Attr(buzz::QN_IQ), "", ""));
948 session_manager->OnIncomingResponse(orig_stanza, response_stanza);
949 delete response_stanza;
950 }
951
952 void ExpectSentStanza(const std::string& expected) {
953 EXPECT_TRUE(!sent_stanzas.empty()) <<
954 "Found no stanza when expected " << expected;
955
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000956 last_expected_sent_stanza.reset(sent_stanzas.front());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000957 sent_stanzas.pop_front();
958
959 std::string actual = last_expected_sent_stanza->Str();
960 EXPECT_EQ(expected, actual);
961 }
962
963 void SkipUnsentStanza() {
964 GetNextOutgoingMessageID();
965 }
966
967 bool HasTransport(const std::string& content_name) const {
968 ASSERT(session != NULL);
969 const cricket::Transport* transport = session->GetTransport(content_name);
970 return transport != NULL && (kTransportType == transport->type());
971 }
972
973 bool HasChannel(const std::string& content_name,
974 int component) const {
975 ASSERT(session != NULL);
976 const cricket::TransportChannel* channel =
977 session->GetChannel(content_name, component);
978 return channel != NULL && (component == channel->component());
979 }
980
981 cricket::TransportChannel* GetChannel(const std::string& content_name,
982 int component) const {
983 ASSERT(session != NULL);
984 return session->GetChannel(content_name, component);
985 }
986
987 void OnSessionCreate(cricket::Session* created_session, bool initiate) {
988 session_created_count += 1;
989
990 session = created_session;
991 session->set_current_protocol(start_protocol);
992 session->SignalState.connect(this, &TestClient::OnSessionState);
993 session->SignalError.connect(this, &TestClient::OnSessionError);
994 session->SignalRemoteDescriptionUpdate.connect(
995 this, &TestClient::OnSessionRemoteDescriptionUpdate);
996 session->SignalNewLocalDescription.connect(
997 this, &TestClient::OnNewLocalDescription);
998 session->SignalNewRemoteDescription.connect(
999 this, &TestClient::OnNewRemoteDescription);
1000
1001 CreateChannels();
1002 }
1003
1004 void OnSessionDestroy(cricket::Session *session) {
1005 session_destroyed_count += 1;
1006 }
1007
1008 void OnSessionState(cricket::BaseSession* session,
1009 cricket::BaseSession::State state) {
1010 // EXPECT_EQ does not allow use of this, hence the tmp variable.
1011 cricket::BaseSession* tmp = this->session;
1012 EXPECT_EQ(tmp, session);
1013 last_session_state = state;
1014 }
1015
1016 void OnSessionError(cricket::BaseSession* session,
1017 cricket::BaseSession::Error error) {
1018 // EXPECT_EQ does not allow use of this, hence the tmp variable.
1019 cricket::BaseSession* tmp = this->session;
1020 EXPECT_EQ(tmp, session);
1021 if (blow_up_on_error) {
1022 EXPECT_TRUE(false);
1023 } else {
1024 error_count++;
1025 }
1026 }
1027
1028 void OnSessionRemoteDescriptionUpdate(cricket::BaseSession* session,
1029 const cricket::ContentInfos& contents) {
1030 session_remote_description_update_count++;
1031 }
1032
1033 void OnNewLocalDescription(cricket::BaseSession* session,
1034 cricket::ContentAction action) {
1035 new_local_description = true;
1036 last_content_action = action;
1037 last_content_source = cricket::CS_LOCAL;
1038 }
1039
1040 void OnNewRemoteDescription(cricket::BaseSession* session,
1041 cricket::ContentAction action) {
1042 new_remote_description = true;
1043 last_content_action = action;
1044 last_content_source = cricket::CS_REMOTE;
1045 }
1046
1047 void PrepareCandidates() {
1048 session_manager->OnSignalingReady();
1049 }
1050
1051 void OnOutgoingMessage(cricket::SessionManager* manager,
1052 const buzz::XmlElement* stanza) {
1053 buzz::XmlElement* elem = new buzz::XmlElement(*stanza);
1054 EXPECT_TRUE(elem->Name() == buzz::QN_IQ);
1055 EXPECT_TRUE(elem->HasAttr(buzz::QN_TO));
1056 EXPECT_FALSE(elem->HasAttr(buzz::QN_FROM));
1057 EXPECT_TRUE(elem->HasAttr(buzz::QN_TYPE));
1058 EXPECT_TRUE((elem->Attr(buzz::QN_TYPE) == "set") ||
1059 (elem->Attr(buzz::QN_TYPE) == "result") ||
1060 (elem->Attr(buzz::QN_TYPE) == "error"));
1061
1062 elem->SetAttr(buzz::QN_FROM, local_name);
1063 if (elem->Attr(buzz::QN_TYPE) == "set") {
1064 EXPECT_FALSE(elem->HasAttr(buzz::QN_ID));
1065 elem->SetAttr(buzz::QN_ID, GetNextOutgoingMessageID());
1066 }
1067
1068 // Uncommenting this is useful for debugging.
1069 // PrintStanza("OutgoingMessage", elem);
1070 sent_stanzas.push_back(elem);
1071 }
1072
1073 std::string GetNextOutgoingMessageID() {
1074 int message_id = (*next_message_id)++;
1075 std::ostringstream ost;
1076 ost << message_id;
1077 return ost.str();
1078 }
1079
1080 void CreateChannels() {
1081 ASSERT(session != NULL);
1082 // We either have a single content with multiple components (RTP/RTCP), or
1083 // multiple contents with single components, but not both.
1084 int component_a = 1;
1085 int component_b = (content_name_a == content_name_b) ? 2 : 1;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001086 chan_a.reset(new ChannelHandler(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001087 session->CreateChannel(content_name_a, channel_name_a, component_a),
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001088 channel_name_a));
1089 chan_b.reset(new ChannelHandler(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001090 session->CreateChannel(content_name_b, channel_name_b, component_b),
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001091 channel_name_b));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001092 }
1093
1094 int* next_message_id;
1095 std::string local_name;
1096 SignalingProtocol start_protocol;
1097 std::string content_type;
1098 std::string content_name_a;
1099 std::string channel_name_a;
1100 std::string content_name_b;
1101 std::string channel_name_b;
1102
1103 uint32 session_created_count;
1104 uint32 session_destroyed_count;
1105 uint32 session_remote_description_update_count;
1106 bool new_local_description;
1107 bool new_remote_description;
1108 cricket::ContentAction last_content_action;
1109 cricket::ContentSource last_content_source;
1110 std::deque<buzz::XmlElement*> sent_stanzas;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001111 talk_base::scoped_ptr<buzz::XmlElement> last_expected_sent_stanza;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001112
1113 cricket::SessionManager* session_manager;
1114 TestSessionClient* client;
1115 cricket::PortAllocator* port_allocator_;
1116 cricket::Session* session;
1117 cricket::BaseSession::State last_session_state;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001118 talk_base::scoped_ptr<ChannelHandler> chan_a;
1119 talk_base::scoped_ptr<ChannelHandler> chan_b;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001120 bool blow_up_on_error;
1121 int error_count;
1122};
1123
1124class SessionTest : public testing::Test {
1125 protected:
1126 virtual void SetUp() {
1127 // Seed needed for each test to satisfy expectations.
1128 talk_base::SetRandomTestMode(true);
1129 }
1130
1131 virtual void TearDown() {
1132 talk_base::SetRandomTestMode(false);
1133 }
1134
1135 // Tests sending data between two clients, over two channels.
1136 void TestSendRecv(ChannelHandler* chan1a,
1137 ChannelHandler* chan1b,
1138 ChannelHandler* chan2a,
1139 ChannelHandler* chan2b) {
1140 const char* dat1a = "spamspamspamspamspamspamspambakedbeansspam";
1141 const char* dat2a = "mapssnaebdekabmapsmapsmapsmapsmapsmapsmaps";
1142 const char* dat1b = "Lobster Thermidor a Crevette with a mornay sauce...";
1143 const char* dat2b = "...ecuas yanrom a htiw etteverC a rodimrehT retsboL";
1144
1145 for (int i = 0; i < 20; i++) {
1146 chan1a->Send(dat1a, strlen(dat1a));
1147 chan1b->Send(dat1b, strlen(dat1b));
1148 chan2a->Send(dat2a, strlen(dat2a));
1149 chan2b->Send(dat2b, strlen(dat2b));
1150
1151 EXPECT_EQ_WAIT(i + 1, chan1a->data_count, kEventTimeout);
1152 EXPECT_EQ_WAIT(i + 1, chan1b->data_count, kEventTimeout);
1153 EXPECT_EQ_WAIT(i + 1, chan2a->data_count, kEventTimeout);
1154 EXPECT_EQ_WAIT(i + 1, chan2b->data_count, kEventTimeout);
1155
1156 EXPECT_EQ(strlen(dat2a), chan1a->last_size);
1157 EXPECT_EQ(strlen(dat2b), chan1b->last_size);
1158 EXPECT_EQ(strlen(dat1a), chan2a->last_size);
1159 EXPECT_EQ(strlen(dat1b), chan2b->last_size);
1160
pbos@webrtc.org371243d2014-03-07 15:22:04 +00001161 EXPECT_EQ(0, memcmp(chan1a->last_data, dat2a, strlen(dat2a)));
1162 EXPECT_EQ(0, memcmp(chan1b->last_data, dat2b, strlen(dat2b)));
1163 EXPECT_EQ(0, memcmp(chan2a->last_data, dat1a, strlen(dat1a)));
1164 EXPECT_EQ(0, memcmp(chan2b->last_data, dat1b, strlen(dat1b)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001165 }
1166 }
1167
1168 // Test an initiate from one client to another, each with
1169 // independent initial protocols. Checks for the correct initiates,
1170 // candidates, and accept messages, and tests that working network
1171 // channels are established.
1172 void TestSession(SignalingProtocol initiator_protocol,
1173 SignalingProtocol responder_protocol,
1174 SignalingProtocol resulting_protocol,
1175 const std::string& gingle_content_type,
1176 const std::string& content_type,
1177 const std::string& content_name_a,
1178 const std::string& channel_name_a,
1179 const std::string& content_name_b,
1180 const std::string& channel_name_b,
1181 const std::string& initiate_xml,
1182 const std::string& transport_info_a_xml,
1183 const std::string& transport_info_b_xml,
1184 const std::string& transport_info_reply_a_xml,
1185 const std::string& transport_info_reply_b_xml,
1186 const std::string& accept_xml,
1187 bool bundle = false) {
1188 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
1189 new TestPortAllocator());
1190 int next_message_id = 0;
1191
1192 talk_base::scoped_ptr<TestClient> initiator(
1193 new TestClient(allocator.get(), &next_message_id,
1194 kInitiator, initiator_protocol,
1195 content_type,
1196 content_name_a, channel_name_a,
1197 content_name_b, channel_name_b));
1198 talk_base::scoped_ptr<TestClient> responder(
1199 new TestClient(allocator.get(), &next_message_id,
1200 kResponder, responder_protocol,
1201 content_type,
1202 content_name_a, channel_name_a,
1203 content_name_b, channel_name_b));
1204
1205 // Create Session and check channels and state.
1206 initiator->CreateSession();
1207 EXPECT_EQ(1U, initiator->session_created_count);
1208 EXPECT_EQ(kSessionId, initiator->session->id());
1209 EXPECT_EQ(initiator->session->local_name(), kInitiator);
1210 EXPECT_EQ(cricket::BaseSession::STATE_INIT,
1211 initiator->session_state());
1212
1213 // See comment in CreateChannels about how we choose component IDs.
1214 int component_a = 1;
1215 int component_b = (content_name_a == content_name_b) ? 2 : 1;
1216 EXPECT_TRUE(initiator->HasTransport(content_name_a));
1217 EXPECT_TRUE(initiator->HasChannel(content_name_a, component_a));
1218 EXPECT_TRUE(initiator->HasTransport(content_name_b));
1219 EXPECT_TRUE(initiator->HasChannel(content_name_b, component_b));
1220
1221 // Initiate and expect initiate message sent.
1222 cricket::SessionDescription* offer = NewTestSessionDescription(
1223 gingle_content_type,
1224 content_name_a, content_type,
1225 content_name_b, content_type);
1226 if (bundle) {
1227 cricket::ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
1228 group.AddContentName(content_name_a);
1229 group.AddContentName(content_name_b);
1230 EXPECT_TRUE(group.HasContentName(content_name_a));
1231 EXPECT_TRUE(group.HasContentName(content_name_b));
1232 offer->AddGroup(group);
1233 }
1234 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer));
1235 EXPECT_EQ(initiator->session->remote_name(), kResponder);
1236 EXPECT_EQ(initiator->session->local_description(), offer);
1237
1238 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
1239 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE,
1240 initiator->session_state());
1241
1242 initiator->ExpectSentStanza(
1243 IqSet("0", kInitiator, kResponder, initiate_xml));
1244
1245 // Deliver the initiate. Expect ack and session created with
1246 // transports.
1247 responder->DeliverStanza(initiator->stanza());
1248 responder->ExpectSentStanza(
1249 IqAck("0", kResponder, kInitiator));
1250 EXPECT_EQ(0U, responder->sent_stanza_count());
1251
1252 EXPECT_EQ(1U, responder->session_created_count);
1253 EXPECT_EQ(kSessionId, responder->session->id());
1254 EXPECT_EQ(responder->session->local_name(), kResponder);
1255 EXPECT_EQ(responder->session->remote_name(), kInitiator);
1256 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE,
1257 responder->session_state());
1258
1259 EXPECT_TRUE(responder->HasTransport(content_name_a));
1260 EXPECT_TRUE(responder->HasChannel(content_name_a, component_a));
1261 EXPECT_TRUE(responder->HasTransport(content_name_b));
1262 EXPECT_TRUE(responder->HasChannel(content_name_b, component_b));
1263
1264 // Expect transport-info message from initiator.
1265 // But don't send candidates until initiate ack is received.
1266 initiator->PrepareCandidates();
1267 WAIT(initiator->sent_stanza_count() > 0, 100);
1268 EXPECT_EQ(0U, initiator->sent_stanza_count());
1269 initiator->DeliverAckToLastStanza();
1270 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
1271 initiator->ExpectSentStanza(
1272 IqSet("1", kInitiator, kResponder, transport_info_a_xml));
1273
1274 // Deliver transport-info and expect ack.
1275 responder->DeliverStanza(initiator->stanza());
1276 responder->ExpectSentStanza(
1277 IqAck("1", kResponder, kInitiator));
1278
1279 if (!transport_info_b_xml.empty()) {
1280 // Expect second transport-info message from initiator.
1281 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
1282 initiator->ExpectSentStanza(
1283 IqSet("2", kInitiator, kResponder, transport_info_b_xml));
1284 EXPECT_EQ(0U, initiator->sent_stanza_count());
1285
1286 // Deliver second transport-info message and expect ack.
1287 responder->DeliverStanza(initiator->stanza());
1288 responder->ExpectSentStanza(
1289 IqAck("2", kResponder, kInitiator));
1290 } else {
1291 EXPECT_EQ(0U, initiator->sent_stanza_count());
1292 EXPECT_EQ(0U, responder->sent_stanza_count());
1293 initiator->SkipUnsentStanza();
1294 }
1295
1296 // Expect reply transport-info message from responder.
1297 responder->PrepareCandidates();
1298 EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout);
1299 responder->ExpectSentStanza(
1300 IqSet("3", kResponder, kInitiator, transport_info_reply_a_xml));
1301
1302 // Deliver reply transport-info and expect ack.
1303 initiator->DeliverStanza(responder->stanza());
1304 initiator->ExpectSentStanza(
1305 IqAck("3", kInitiator, kResponder));
1306
1307 if (!transport_info_reply_b_xml.empty()) {
1308 // Expect second reply transport-info message from responder.
1309 EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout);
1310 responder->ExpectSentStanza(
1311 IqSet("4", kResponder, kInitiator, transport_info_reply_b_xml));
1312 EXPECT_EQ(0U, responder->sent_stanza_count());
1313
1314 // Deliver second reply transport-info message and expect ack.
1315 initiator->DeliverStanza(responder->stanza());
1316 initiator->ExpectSentStanza(
1317 IqAck("4", kInitiator, kResponder));
1318 EXPECT_EQ(0U, initiator->sent_stanza_count());
1319 } else {
1320 EXPECT_EQ(0U, initiator->sent_stanza_count());
1321 EXPECT_EQ(0U, responder->sent_stanza_count());
1322 responder->SkipUnsentStanza();
1323 }
1324
1325 // The channels should be able to become writable at this point. This
1326 // requires pinging, so it may take a little while.
1327 EXPECT_TRUE_WAIT(initiator->chan_a->writable() &&
1328 initiator->chan_a->readable(), kEventTimeout);
1329 EXPECT_TRUE_WAIT(initiator->chan_b->writable() &&
1330 initiator->chan_b->readable(), kEventTimeout);
1331 EXPECT_TRUE_WAIT(responder->chan_a->writable() &&
1332 responder->chan_a->readable(), kEventTimeout);
1333 EXPECT_TRUE_WAIT(responder->chan_b->writable() &&
1334 responder->chan_b->readable(), kEventTimeout);
1335
1336 // Accept the session and expect accept stanza.
1337 cricket::SessionDescription* answer = NewTestSessionDescription(
1338 gingle_content_type,
1339 content_name_a, content_type,
1340 content_name_b, content_type);
1341 if (bundle) {
1342 cricket::ContentGroup group(cricket::GROUP_TYPE_BUNDLE);
1343 group.AddContentName(content_name_a);
1344 group.AddContentName(content_name_b);
1345 EXPECT_TRUE(group.HasContentName(content_name_a));
1346 EXPECT_TRUE(group.HasContentName(content_name_b));
1347 answer->AddGroup(group);
1348 }
1349 EXPECT_TRUE(responder->session->Accept(answer));
1350 EXPECT_EQ(responder->session->local_description(), answer);
1351
1352 responder->ExpectSentStanza(
1353 IqSet("5", kResponder, kInitiator, accept_xml));
1354
1355 EXPECT_EQ(0U, responder->sent_stanza_count());
1356
1357 // Deliver the accept message and expect an ack.
1358 initiator->DeliverStanza(responder->stanza());
1359 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
1360 initiator->ExpectSentStanza(
1361 IqAck("5", kInitiator, kResponder));
1362 EXPECT_EQ(0U, initiator->sent_stanza_count());
1363
1364 // Both sessions should be in progress and have functioning
1365 // channels.
1366 EXPECT_EQ(resulting_protocol, initiator->session->current_protocol());
1367 EXPECT_EQ(resulting_protocol, responder->session->current_protocol());
1368 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS,
1369 initiator->session_state(), kEventTimeout);
1370 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS,
1371 responder->session_state(), kEventTimeout);
1372 if (bundle) {
1373 cricket::TransportChannel* initiator_chan_a = initiator->chan_a->channel;
1374 cricket::TransportChannel* initiator_chan_b = initiator->chan_b->channel;
1375
1376 // Since we know these are TransportChannelProxy, type cast it.
1377 cricket::TransportChannelProxy* initiator_proxy_chan_a =
1378 static_cast<cricket::TransportChannelProxy*>(initiator_chan_a);
1379 cricket::TransportChannelProxy* initiator_proxy_chan_b =
1380 static_cast<cricket::TransportChannelProxy*>(initiator_chan_b);
1381 EXPECT_TRUE(initiator_proxy_chan_a->impl() != NULL);
1382 EXPECT_TRUE(initiator_proxy_chan_b->impl() != NULL);
1383 EXPECT_EQ(initiator_proxy_chan_a->impl(), initiator_proxy_chan_b->impl());
1384
1385 cricket::TransportChannel* responder_chan_a = responder->chan_a->channel;
1386 cricket::TransportChannel* responder_chan_b = responder->chan_b->channel;
1387
1388 // Since we know these are TransportChannelProxy, type cast it.
1389 cricket::TransportChannelProxy* responder_proxy_chan_a =
1390 static_cast<cricket::TransportChannelProxy*>(responder_chan_a);
1391 cricket::TransportChannelProxy* responder_proxy_chan_b =
1392 static_cast<cricket::TransportChannelProxy*>(responder_chan_b);
1393 EXPECT_TRUE(responder_proxy_chan_a->impl() != NULL);
1394 EXPECT_TRUE(responder_proxy_chan_b->impl() != NULL);
1395 EXPECT_EQ(responder_proxy_chan_a->impl(), responder_proxy_chan_b->impl());
1396 }
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001397 TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(),
1398 responder->chan_a.get(), responder->chan_b.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001399
1400 if (resulting_protocol == PROTOCOL_JINGLE) {
1401 // Deliver a description-info message to the initiator and check if the
1402 // content description changes.
1403 EXPECT_EQ(0U, initiator->session_remote_description_update_count);
1404
1405 const cricket::SessionDescription* old_session_desc =
1406 initiator->session->remote_description();
1407 const cricket::ContentInfo* old_content_a =
1408 old_session_desc->GetContentByName(content_name_a);
1409 const cricket::ContentDescription* old_content_desc_a =
1410 old_content_a->description;
1411 const cricket::ContentInfo* old_content_b =
1412 old_session_desc->GetContentByName(content_name_b);
1413 const cricket::ContentDescription* old_content_desc_b =
1414 old_content_b->description;
1415 EXPECT_TRUE(old_content_desc_a != NULL);
1416 EXPECT_TRUE(old_content_desc_b != NULL);
1417
1418 LOG(LS_INFO) << "A " << old_content_a->name;
1419 LOG(LS_INFO) << "B " << old_content_b->name;
1420
1421 std::string description_info_xml =
1422 JingleDescriptionInfoXml(content_name_a, content_type);
1423 initiator->DeliverStanza(
1424 IqSet("6", kResponder, kInitiator, description_info_xml));
1425 responder->SkipUnsentStanza();
1426 EXPECT_EQ(1U, initiator->session_remote_description_update_count);
1427
1428 const cricket::SessionDescription* new_session_desc =
1429 initiator->session->remote_description();
1430 const cricket::ContentInfo* new_content_a =
1431 new_session_desc->GetContentByName(content_name_a);
1432 const cricket::ContentDescription* new_content_desc_a =
1433 new_content_a->description;
1434 const cricket::ContentInfo* new_content_b =
1435 new_session_desc->GetContentByName(content_name_b);
1436 const cricket::ContentDescription* new_content_desc_b =
1437 new_content_b->description;
1438 EXPECT_TRUE(new_content_desc_a != NULL);
1439 EXPECT_TRUE(new_content_desc_b != NULL);
1440
1441 // TODO: We used to replace contents from an update, but
1442 // that no longer works with partial updates. We need to figure out
1443 // a way to merge patial updates into contents. For now, users of
1444 // Session should listen to SignalRemoteDescriptionUpdate and handle
1445 // updates. They should not expect remote_description to be the
1446 // latest value.
1447 // See session.cc OnDescriptionInfoMessage.
1448
1449 // EXPECT_NE(old_content_desc_a, new_content_desc_a);
1450
1451 // if (content_name_a != content_name_b) {
1452 // // If content_name_a != content_name_b, then b's content description
1453 // // should not have changed since the description-info message only
1454 // // contained an update for content_name_a.
1455 // EXPECT_EQ(old_content_desc_b, new_content_desc_b);
1456 // }
1457
1458 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
1459 initiator->ExpectSentStanza(
1460 IqAck("6", kInitiator, kResponder));
1461 EXPECT_EQ(0U, initiator->sent_stanza_count());
1462 } else {
1463 responder->SkipUnsentStanza();
1464 }
1465
1466 initiator->session->Terminate();
1467 initiator->ExpectSentStanza(
1468 IqSet("7", kInitiator, kResponder,
1469 TerminateXml(resulting_protocol,
1470 cricket::STR_TERMINATE_SUCCESS)));
1471
1472 responder->DeliverStanza(initiator->stanza());
1473 responder->ExpectSentStanza(
1474 IqAck("7", kResponder, kInitiator));
1475 EXPECT_EQ(cricket::BaseSession::STATE_SENTTERMINATE,
1476 initiator->session_state());
1477 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE,
1478 responder->session_state());
1479 }
1480
1481 // Test an initiate with other content, called "main".
1482 void TestOtherContent(SignalingProtocol initiator_protocol,
1483 SignalingProtocol responder_protocol,
1484 SignalingProtocol resulting_protocol) {
1485 std::string content_name = "main";
1486 std::string content_type = "http://oink.splat/session";
1487 std::string content_name_a = content_name;
1488 std::string channel_name_a = "rtp";
1489 std::string content_name_b = content_name;
1490 std::string channel_name_b = "rtcp";
1491 std::string initiate_xml = InitiateXml(
1492 initiator_protocol,
1493 content_name_a, content_type);
1494 std::string transport_info_a_xml = TransportInfo4Xml(
1495 initiator_protocol, content_name,
1496 channel_name_a, 0, 1,
1497 channel_name_b, 2, 3);
1498 std::string transport_info_b_xml = "";
1499 std::string transport_info_reply_a_xml = TransportInfo4Xml(
1500 resulting_protocol, content_name,
1501 channel_name_a, 4, 5,
1502 channel_name_b, 6, 7);
1503 std::string transport_info_reply_b_xml = "";
1504 std::string accept_xml = AcceptXml(
1505 resulting_protocol,
1506 content_name_a, content_type);
1507
1508
1509 TestSession(initiator_protocol, responder_protocol, resulting_protocol,
1510 content_type,
1511 content_type,
1512 content_name_a, channel_name_a,
1513 content_name_b, channel_name_b,
1514 initiate_xml,
1515 transport_info_a_xml, transport_info_b_xml,
1516 transport_info_reply_a_xml, transport_info_reply_b_xml,
1517 accept_xml);
1518 }
1519
1520 // Test an initiate with audio content.
1521 void TestAudioContent(SignalingProtocol initiator_protocol,
1522 SignalingProtocol responder_protocol,
1523 SignalingProtocol resulting_protocol) {
1524 std::string gingle_content_type = cricket::NS_GINGLE_AUDIO;
1525 std::string content_name = cricket::CN_AUDIO;
1526 std::string content_type = cricket::NS_JINGLE_RTP;
1527 std::string channel_name_a = "rtp";
1528 std::string channel_name_b = "rtcp";
1529 std::string initiate_xml = InitiateXml(
1530 initiator_protocol,
1531 gingle_content_type,
1532 content_name, content_type,
1533 "", "");
1534 std::string transport_info_a_xml = TransportInfo4Xml(
1535 initiator_protocol, content_name,
1536 channel_name_a, 0, 1,
1537 channel_name_b, 2, 3);
1538 std::string transport_info_b_xml = "";
1539 std::string transport_info_reply_a_xml = TransportInfo4Xml(
1540 resulting_protocol, content_name,
1541 channel_name_a, 4, 5,
1542 channel_name_b, 6, 7);
1543 std::string transport_info_reply_b_xml = "";
1544 std::string accept_xml = AcceptXml(
1545 resulting_protocol,
1546 gingle_content_type,
1547 content_name, content_type,
1548 "", "");
1549
1550
1551 TestSession(initiator_protocol, responder_protocol, resulting_protocol,
1552 gingle_content_type,
1553 content_type,
1554 content_name, channel_name_a,
1555 content_name, channel_name_b,
1556 initiate_xml,
1557 transport_info_a_xml, transport_info_b_xml,
1558 transport_info_reply_a_xml, transport_info_reply_b_xml,
1559 accept_xml);
1560 }
1561
1562 // Since media content is "split" into two contents (audio and
1563 // video), we need to treat it special.
1564 void TestVideoContents(SignalingProtocol initiator_protocol,
1565 SignalingProtocol responder_protocol,
1566 SignalingProtocol resulting_protocol) {
1567 std::string content_type = cricket::NS_JINGLE_RTP;
1568 std::string gingle_content_type = cricket::NS_GINGLE_VIDEO;
1569 std::string content_name_a = cricket::CN_AUDIO;
1570 std::string channel_name_a = "rtp";
1571 std::string content_name_b = cricket::CN_VIDEO;
1572 std::string channel_name_b = "video_rtp";
1573
1574 std::string initiate_xml = InitiateXml(
1575 initiator_protocol,
1576 gingle_content_type,
1577 content_name_a, content_type,
1578 content_name_b, content_type);
1579 std::string transport_info_a_xml = TransportInfo2Xml(
1580 initiator_protocol, content_name_a,
1581 channel_name_a, 0, 1);
1582 std::string transport_info_b_xml = TransportInfo2Xml(
1583 initiator_protocol, content_name_b,
1584 channel_name_b, 2, 3);
1585 std::string transport_info_reply_a_xml = TransportInfo2Xml(
1586 resulting_protocol, content_name_a,
1587 channel_name_a, 4, 5);
1588 std::string transport_info_reply_b_xml = TransportInfo2Xml(
1589 resulting_protocol, content_name_b,
1590 channel_name_b, 6, 7);
1591 std::string accept_xml = AcceptXml(
1592 resulting_protocol,
1593 gingle_content_type,
1594 content_name_a, content_type,
1595 content_name_b, content_type);
1596
1597 TestSession(initiator_protocol, responder_protocol, resulting_protocol,
1598 gingle_content_type,
1599 content_type,
1600 content_name_a, channel_name_a,
1601 content_name_b, channel_name_b,
1602 initiate_xml,
1603 transport_info_a_xml, transport_info_b_xml,
1604 transport_info_reply_a_xml, transport_info_reply_b_xml,
1605 accept_xml);
1606 }
1607
1608 void TestBadRedirect(SignalingProtocol protocol) {
1609 std::string content_name = "main";
1610 std::string content_type = "http://oink.splat/session";
1611 std::string channel_name_a = "chana";
1612 std::string channel_name_b = "chanb";
1613 std::string initiate_xml = InitiateXml(
1614 protocol, content_name, content_type);
1615 std::string transport_info_xml = TransportInfo4Xml(
1616 protocol, content_name,
1617 channel_name_a, 0, 1,
1618 channel_name_b, 2, 3);
1619 std::string transport_info_reply_xml = TransportInfo4Xml(
1620 protocol, content_name,
1621 channel_name_a, 4, 5,
1622 channel_name_b, 6, 7);
1623 std::string accept_xml = AcceptXml(
1624 protocol, content_name, content_type);
1625 std::string responder_full = kResponder + "/full";
1626
1627 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
1628 new TestPortAllocator());
1629 int next_message_id = 0;
1630
1631 talk_base::scoped_ptr<TestClient> initiator(
1632 new TestClient(allocator.get(), &next_message_id,
1633 kInitiator, protocol,
1634 content_type,
1635 content_name, channel_name_a,
1636 content_name, channel_name_b));
1637
1638 talk_base::scoped_ptr<TestClient> responder(
1639 new TestClient(allocator.get(), &next_message_id,
1640 responder_full, protocol,
1641 content_type,
1642 content_name, channel_name_a,
1643 content_name, channel_name_b));
1644
1645 // Create Session and check channels and state.
1646 initiator->CreateSession();
1647 EXPECT_EQ(1U, initiator->session_created_count);
1648 EXPECT_EQ(kSessionId, initiator->session->id());
1649 EXPECT_EQ(initiator->session->local_name(), kInitiator);
1650 EXPECT_EQ(cricket::BaseSession::STATE_INIT,
1651 initiator->session_state());
1652
1653 EXPECT_TRUE(initiator->HasChannel(content_name, 1));
1654 EXPECT_TRUE(initiator->HasChannel(content_name, 2));
1655
1656 // Initiate and expect initiate message sent.
1657 cricket::SessionDescription* offer = NewTestSessionDescription(
1658 content_name, content_type);
1659 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer));
1660 EXPECT_EQ(initiator->session->remote_name(), kResponder);
1661 EXPECT_EQ(initiator->session->local_description(), offer);
1662
1663 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
1664 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE,
1665 initiator->session_state());
1666 initiator->ExpectSentStanza(
1667 IqSet("0", kInitiator, kResponder, initiate_xml));
1668
1669 // Expect transport-info message from initiator.
1670 initiator->DeliverAckToLastStanza();
1671 initiator->PrepareCandidates();
1672 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
1673 initiator->ExpectSentStanza(
1674 IqSet("1", kInitiator, kResponder, transport_info_xml));
1675
1676 // Send an unauthorized redirect to the initiator and expect it be ignored.
1677 initiator->blow_up_on_error = false;
1678 const buzz::XmlElement* initiate_stanza = initiator->stanza();
1679 talk_base::scoped_ptr<buzz::XmlElement> redirect_stanza(
1680 buzz::XmlElement::ForStr(
1681 IqError("ER", kResponder, kInitiator,
1682 RedirectXml(protocol, initiate_xml, "not@allowed.com"))));
1683 initiator->session_manager->OnFailedSend(
1684 initiate_stanza, redirect_stanza.get());
1685 EXPECT_EQ(initiator->session->remote_name(), kResponder);
1686 initiator->blow_up_on_error = true;
1687 EXPECT_EQ(initiator->error_count, 1);
1688 }
1689
1690 void TestGoodRedirect(SignalingProtocol protocol) {
1691 std::string content_name = "main";
1692 std::string content_type = "http://oink.splat/session";
1693 std::string channel_name_a = "chana";
1694 std::string channel_name_b = "chanb";
1695 std::string initiate_xml = InitiateXml(
1696 protocol, content_name, content_type);
1697 std::string transport_info_xml = TransportInfo4Xml(
1698 protocol, content_name,
1699 channel_name_a, 0, 1,
1700 channel_name_b, 2, 3);
1701 std::string transport_info_reply_xml = TransportInfo4Xml(
1702 protocol, content_name,
1703 channel_name_a, 4, 5,
1704 channel_name_b, 6, 7);
1705 std::string accept_xml = AcceptXml(
1706 protocol, content_name, content_type);
1707 std::string responder_full = kResponder + "/full";
1708
1709 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
1710 new TestPortAllocator());
1711 int next_message_id = 0;
1712
1713 talk_base::scoped_ptr<TestClient> initiator(
1714 new TestClient(allocator.get(), &next_message_id,
1715 kInitiator, protocol,
1716 content_type,
1717 content_name, channel_name_a,
1718 content_name, channel_name_b));
1719
1720 talk_base::scoped_ptr<TestClient> responder(
1721 new TestClient(allocator.get(), &next_message_id,
1722 responder_full, protocol,
1723 content_type,
1724 content_name, channel_name_a,
1725 content_name, channel_name_b));
1726
1727 // Create Session and check channels and state.
1728 initiator->CreateSession();
1729 EXPECT_EQ(1U, initiator->session_created_count);
1730 EXPECT_EQ(kSessionId, initiator->session->id());
1731 EXPECT_EQ(initiator->session->local_name(), kInitiator);
1732 EXPECT_EQ(cricket::BaseSession::STATE_INIT,
1733 initiator->session_state());
1734
1735 EXPECT_TRUE(initiator->HasChannel(content_name, 1));
1736 EXPECT_TRUE(initiator->HasChannel(content_name, 2));
1737
1738 // Initiate and expect initiate message sent.
1739 cricket::SessionDescription* offer = NewTestSessionDescription(
1740 content_name, content_type);
1741 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer));
1742 EXPECT_EQ(initiator->session->remote_name(), kResponder);
1743 EXPECT_EQ(initiator->session->local_description(), offer);
1744
1745 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
1746 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE,
1747 initiator->session_state());
1748 initiator->ExpectSentStanza(
1749 IqSet("0", kInitiator, kResponder, initiate_xml));
1750
1751 // Expect transport-info message from initiator.
1752 initiator->DeliverAckToLastStanza();
1753 initiator->PrepareCandidates();
1754 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
1755 initiator->ExpectSentStanza(
1756 IqSet("1", kInitiator, kResponder, transport_info_xml));
1757
1758 // Send a redirect to the initiator and expect all of the message
1759 // to be resent.
1760 const buzz::XmlElement* initiate_stanza = initiator->stanza();
1761 talk_base::scoped_ptr<buzz::XmlElement> redirect_stanza(
1762 buzz::XmlElement::ForStr(
1763 IqError("ER2", kResponder, kInitiator,
1764 RedirectXml(protocol, initiate_xml, responder_full))));
1765 initiator->session_manager->OnFailedSend(
1766 initiate_stanza, redirect_stanza.get());
1767 EXPECT_EQ(initiator->session->remote_name(), responder_full);
1768
1769 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
1770 initiator->ExpectSentStanza(
1771 IqSet("2", kInitiator, responder_full, initiate_xml));
1772 initiator->ExpectSentStanza(
1773 IqSet("3", kInitiator, responder_full, transport_info_xml));
1774
1775 // Deliver the initiate. Expect ack and session created with
1776 // transports.
1777 responder->DeliverStanza(
1778 IqSet("2", kInitiator, responder_full, initiate_xml));
1779 responder->ExpectSentStanza(
1780 IqAck("2", responder_full, kInitiator));
1781 EXPECT_EQ(0U, responder->sent_stanza_count());
1782
1783 EXPECT_EQ(1U, responder->session_created_count);
1784 EXPECT_EQ(kSessionId, responder->session->id());
1785 EXPECT_EQ(responder->session->local_name(), responder_full);
1786 EXPECT_EQ(responder->session->remote_name(), kInitiator);
1787 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE,
1788 responder->session_state());
1789
1790 EXPECT_TRUE(responder->HasChannel(content_name, 1));
1791 EXPECT_TRUE(responder->HasChannel(content_name, 2));
1792
1793 // Deliver transport-info and expect ack.
1794 responder->DeliverStanza(
1795 IqSet("3", kInitiator, responder_full, transport_info_xml));
1796 responder->ExpectSentStanza(
1797 IqAck("3", responder_full, kInitiator));
1798
1799 // Expect reply transport-infos sent to new remote JID
1800 responder->PrepareCandidates();
1801 EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout);
1802 responder->ExpectSentStanza(
1803 IqSet("4", responder_full, kInitiator, transport_info_reply_xml));
1804
1805 initiator->DeliverStanza(responder->stanza());
1806 initiator->ExpectSentStanza(
1807 IqAck("4", kInitiator, responder_full));
1808
1809 // The channels should be able to become writable at this point. This
1810 // requires pinging, so it may take a little while.
1811 EXPECT_TRUE_WAIT(initiator->chan_a->writable() &&
1812 initiator->chan_a->readable(), kEventTimeout);
1813 EXPECT_TRUE_WAIT(initiator->chan_b->writable() &&
1814 initiator->chan_b->readable(), kEventTimeout);
1815 EXPECT_TRUE_WAIT(responder->chan_a->writable() &&
1816 responder->chan_a->readable(), kEventTimeout);
1817 EXPECT_TRUE_WAIT(responder->chan_b->writable() &&
1818 responder->chan_b->readable(), kEventTimeout);
1819
1820 // Accept the session and expect accept stanza.
1821 cricket::SessionDescription* answer = NewTestSessionDescription(
1822 content_name, content_type);
1823 EXPECT_TRUE(responder->session->Accept(answer));
1824 EXPECT_EQ(responder->session->local_description(), answer);
1825
1826 responder->ExpectSentStanza(
1827 IqSet("5", responder_full, kInitiator, accept_xml));
1828 EXPECT_EQ(0U, responder->sent_stanza_count());
1829
1830 // Deliver the accept message and expect an ack.
1831 initiator->DeliverStanza(responder->stanza());
1832 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
1833 initiator->ExpectSentStanza(
1834 IqAck("5", kInitiator, responder_full));
1835 EXPECT_EQ(0U, initiator->sent_stanza_count());
1836
1837 // Both sessions should be in progress and have functioning
1838 // channels.
1839 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS,
1840 initiator->session_state(), kEventTimeout);
1841 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS,
1842 responder->session_state(), kEventTimeout);
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001843 TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(),
1844 responder->chan_a.get(), responder->chan_b.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001845 }
1846
1847 void TestCandidatesInInitiateAndAccept(const std::string& test_name) {
1848 std::string content_name = "main";
1849 std::string content_type = "http://oink.splat/session";
1850 std::string channel_name_a = "rtp";
1851 std::string channel_name_b = "rtcp";
1852 cricket::SignalingProtocol protocol = PROTOCOL_JINGLE;
1853
1854 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
1855 new TestPortAllocator());
1856 int next_message_id = 0;
1857
1858 talk_base::scoped_ptr<TestClient> initiator(
1859 new TestClient(allocator.get(), &next_message_id,
1860 kInitiator, protocol,
1861 content_type,
1862 content_name, channel_name_a,
1863 content_name, channel_name_b));
1864
1865 talk_base::scoped_ptr<TestClient> responder(
1866 new TestClient(allocator.get(), &next_message_id,
1867 kResponder, protocol,
1868 content_type,
1869 content_name, channel_name_a,
1870 content_name, channel_name_b));
1871
1872 // Create Session and check channels and state.
1873 initiator->CreateSession();
1874 EXPECT_TRUE(initiator->HasTransport(content_name));
1875 EXPECT_TRUE(initiator->HasChannel(content_name, 1));
1876 EXPECT_TRUE(initiator->HasTransport(content_name));
1877 EXPECT_TRUE(initiator->HasChannel(content_name, 2));
1878
1879 // Initiate and expect initiate message sent.
1880 cricket::SessionDescription* offer = NewTestSessionDescription(
1881 content_name, content_type);
1882 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer));
1883
1884 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
1885 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE,
1886 initiator->session_state());
1887 initiator->ExpectSentStanza(
1888 IqSet("0", kInitiator, kResponder,
1889 InitiateXml(protocol, content_name, content_type)));
1890
1891 // Fake the delivery the initiate and candidates together.
1892 responder->DeliverStanza(
1893 IqSet("A", kInitiator, kResponder,
1894 JingleInitiateActionXml(
1895 JingleContentXml(
1896 content_name, content_type, kTransportType,
1897 P2pCandidateXml(channel_name_a, 0) +
1898 P2pCandidateXml(channel_name_a, 1) +
1899 P2pCandidateXml(channel_name_b, 2) +
1900 P2pCandidateXml(channel_name_b, 3)))));
1901 responder->ExpectSentStanza(
1902 IqAck("A", kResponder, kInitiator));
1903 EXPECT_EQ(0U, responder->sent_stanza_count());
1904
1905 EXPECT_EQ(1U, responder->session_created_count);
1906 EXPECT_EQ(kSessionId, responder->session->id());
1907 EXPECT_EQ(responder->session->local_name(), kResponder);
1908 EXPECT_EQ(responder->session->remote_name(), kInitiator);
1909 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE,
1910 responder->session_state());
1911
1912 EXPECT_TRUE(responder->HasTransport(content_name));
1913 EXPECT_TRUE(responder->HasChannel(content_name, 1));
1914 EXPECT_TRUE(responder->HasTransport(content_name));
1915 EXPECT_TRUE(responder->HasChannel(content_name, 2));
1916
1917 // Expect transport-info message from initiator.
1918 // But don't send candidates until initiate ack is received.
1919 initiator->DeliverAckToLastStanza();
1920 initiator->PrepareCandidates();
1921 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
1922 initiator->ExpectSentStanza(
1923 IqSet("1", kInitiator, kResponder,
1924 TransportInfo4Xml(protocol, content_name,
1925 channel_name_a, 0, 1,
1926 channel_name_b, 2, 3)));
1927
1928 responder->PrepareCandidates();
1929 EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout);
1930 responder->ExpectSentStanza(
1931 IqSet("2", kResponder, kInitiator,
1932 TransportInfo4Xml(protocol, content_name,
1933 channel_name_a, 4, 5,
1934 channel_name_b, 6, 7)));
1935
1936 // Accept the session and expect accept stanza.
1937 cricket::SessionDescription* answer = NewTestSessionDescription(
1938 content_name, content_type);
1939 EXPECT_TRUE(responder->session->Accept(answer));
1940
1941 responder->ExpectSentStanza(
1942 IqSet("3", kResponder, kInitiator,
1943 AcceptXml(protocol, content_name, content_type)));
1944 EXPECT_EQ(0U, responder->sent_stanza_count());
1945
1946 // Fake the delivery the accept and candidates together.
1947 initiator->DeliverStanza(
1948 IqSet("B", kResponder, kInitiator,
1949 JingleActionXml("session-accept",
1950 JingleContentXml(
1951 content_name, content_type, kTransportType,
1952 P2pCandidateXml(channel_name_a, 4) +
1953 P2pCandidateXml(channel_name_a, 5) +
1954 P2pCandidateXml(channel_name_b, 6) +
1955 P2pCandidateXml(channel_name_b, 7)))));
1956 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
1957 initiator->ExpectSentStanza(
1958 IqAck("B", kInitiator, kResponder));
1959 EXPECT_EQ(0U, initiator->sent_stanza_count());
1960
1961 // The channels should be able to become writable at this point. This
1962 // requires pinging, so it may take a little while.
1963 EXPECT_TRUE_WAIT(initiator->chan_a->writable() &&
1964 initiator->chan_a->readable(), kEventTimeout);
1965 EXPECT_TRUE_WAIT(initiator->chan_b->writable() &&
1966 initiator->chan_b->readable(), kEventTimeout);
1967 EXPECT_TRUE_WAIT(responder->chan_a->writable() &&
1968 responder->chan_a->readable(), kEventTimeout);
1969 EXPECT_TRUE_WAIT(responder->chan_b->writable() &&
1970 responder->chan_b->readable(), kEventTimeout);
1971
1972
1973 // Both sessions should be in progress and have functioning
1974 // channels.
1975 EXPECT_EQ(protocol, initiator->session->current_protocol());
1976 EXPECT_EQ(protocol, responder->session->current_protocol());
1977 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS,
1978 initiator->session_state(), kEventTimeout);
1979 EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS,
1980 responder->session_state(), kEventTimeout);
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001981 TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(),
1982 responder->chan_a.get(), responder->chan_b.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001983 }
1984
1985 // Tests that when an initiator terminates right after initiate,
1986 // everything behaves correctly.
1987 void TestEarlyTerminationFromInitiator(SignalingProtocol protocol) {
1988 std::string content_name = "main";
1989 std::string content_type = "http://oink.splat/session";
1990
1991 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
1992 new TestPortAllocator());
1993 int next_message_id = 0;
1994
1995 talk_base::scoped_ptr<TestClient> initiator(
1996 new TestClient(allocator.get(), &next_message_id,
1997 kInitiator, protocol,
1998 content_type,
1999 content_name, "a",
2000 content_name, "b"));
2001
2002 talk_base::scoped_ptr<TestClient> responder(
2003 new TestClient(allocator.get(), &next_message_id,
2004 kResponder, protocol,
2005 content_type,
2006 content_name, "a",
2007 content_name, "b"));
2008
2009 // Send initiate
2010 initiator->CreateSession();
2011 EXPECT_TRUE(initiator->session->Initiate(
2012 kResponder, NewTestSessionDescription(content_name, content_type)));
2013 initiator->ExpectSentStanza(
2014 IqSet("0", kInitiator, kResponder,
2015 InitiateXml(protocol, content_name, content_type)));
2016 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE,
2017 initiator->session_state());
2018
2019 responder->DeliverStanza(initiator->stanza());
2020 responder->ExpectSentStanza(
2021 IqAck("0", kResponder, kInitiator));
2022 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE,
2023 responder->session_state());
2024
2025 initiator->session->TerminateWithReason(cricket::STR_TERMINATE_ERROR);
2026 initiator->ExpectSentStanza(
2027 IqSet("1", kInitiator, kResponder,
2028 TerminateXml(protocol, cricket::STR_TERMINATE_ERROR)));
2029 EXPECT_EQ(cricket::BaseSession::STATE_SENTTERMINATE,
2030 initiator->session_state());
2031
2032 responder->DeliverStanza(initiator->stanza());
2033 responder->ExpectSentStanza(
2034 IqAck("1", kResponder, kInitiator));
2035 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE,
2036 responder->session_state());
2037 }
2038
2039 // Tests that when the responder rejects, everything behaves
2040 // correctly.
2041 void TestRejection(SignalingProtocol protocol) {
2042 std::string content_name = "main";
2043 std::string content_type = "http://oink.splat/session";
2044
2045 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
2046 new TestPortAllocator());
2047 int next_message_id = 0;
2048
2049 talk_base::scoped_ptr<TestClient> initiator(
2050 new TestClient(allocator.get(), &next_message_id,
2051 kInitiator, protocol,
2052 content_type,
2053 content_name, "a",
2054 content_name, "b"));
2055
2056 // Send initiate
2057 initiator->CreateSession();
2058 EXPECT_TRUE(initiator->session->Initiate(
2059 kResponder, NewTestSessionDescription(content_name, content_type)));
2060 initiator->ExpectSentStanza(
2061 IqSet("0", kInitiator, kResponder,
2062 InitiateXml(protocol, content_name, content_type)));
2063 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE,
2064 initiator->session_state());
2065
2066 initiator->DeliverStanza(
2067 IqSet("1", kResponder, kInitiator,
2068 RejectXml(protocol, cricket::STR_TERMINATE_ERROR)));
2069 initiator->ExpectSentStanza(
2070 IqAck("1", kInitiator, kResponder));
2071 if (protocol == PROTOCOL_JINGLE) {
2072 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE,
2073 initiator->session_state());
2074 } else {
2075 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDREJECT,
2076 initiator->session_state());
2077 }
2078 }
2079
2080 void TestTransportMux() {
2081 SignalingProtocol initiator_protocol = PROTOCOL_JINGLE;
2082 SignalingProtocol responder_protocol = PROTOCOL_JINGLE;
2083 SignalingProtocol resulting_protocol = PROTOCOL_JINGLE;
2084 std::string content_type = cricket::NS_JINGLE_RTP;
2085 std::string gingle_content_type = cricket::NS_GINGLE_VIDEO;
2086 std::string content_name_a = cricket::CN_AUDIO;
2087 std::string channel_name_a = "rtp";
2088 std::string content_name_b = cricket::CN_VIDEO;
2089 std::string channel_name_b = "video_rtp";
2090
2091 std::string initiate_xml = InitiateXml(
2092 initiator_protocol,
2093 gingle_content_type,
2094 content_name_a, content_type,
2095 content_name_b, content_type, true);
2096 std::string transport_info_a_xml = TransportInfo2Xml(
2097 initiator_protocol, content_name_a,
2098 channel_name_a, 0, 1);
2099 std::string transport_info_b_xml = TransportInfo2Xml(
2100 initiator_protocol, content_name_b,
2101 channel_name_b, 2, 3);
2102 std::string transport_info_reply_a_xml = TransportInfo2Xml(
2103 resulting_protocol, content_name_a,
2104 channel_name_a, 4, 5);
2105 std::string transport_info_reply_b_xml = TransportInfo2Xml(
2106 resulting_protocol, content_name_b,
2107 channel_name_b, 6, 7);
2108 std::string accept_xml = AcceptXml(
2109 resulting_protocol,
2110 gingle_content_type,
2111 content_name_a, content_type,
2112 content_name_b, content_type, true);
2113
2114 TestSession(initiator_protocol, responder_protocol, resulting_protocol,
2115 gingle_content_type,
2116 content_type,
2117 content_name_a, channel_name_a,
2118 content_name_b, channel_name_b,
2119 initiate_xml,
2120 transport_info_a_xml, transport_info_b_xml,
2121 transport_info_reply_a_xml, transport_info_reply_b_xml,
2122 accept_xml,
2123 true);
2124 }
2125
2126 void TestSendDescriptionInfo() {
2127 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
2128 new TestPortAllocator());
2129 int next_message_id = 0;
2130
2131 std::string content_name = "content-name";
2132 std::string content_type = "content-type";
2133 talk_base::scoped_ptr<TestClient> initiator(
2134 new TestClient(allocator.get(), &next_message_id,
2135 kInitiator, PROTOCOL_JINGLE,
2136 content_type,
2137 content_name, "",
2138 "", ""));
2139
2140 initiator->CreateSession();
2141 cricket::SessionDescription* offer = NewTestSessionDescription(
2142 content_name, content_type);
2143 std::string initiate_xml = InitiateXml(
2144 PROTOCOL_JINGLE, content_name, content_type);
2145
2146 cricket::ContentInfos contents;
2147 TestContentDescription content(content_type, content_type);
2148 contents.push_back(
2149 cricket::ContentInfo(content_name, content_type, &content));
2150 std::string description_info_xml = JingleDescriptionInfoXml(
2151 content_name, content_type);
2152
2153 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer));
2154 initiator->ExpectSentStanza(
2155 IqSet("0", kInitiator, kResponder, initiate_xml));
2156
2157 EXPECT_TRUE(initiator->session->SendDescriptionInfoMessage(contents));
2158 initiator->ExpectSentStanza(
2159 IqSet("1", kInitiator, kResponder, description_info_xml));
2160 }
2161
2162 void DoTestSignalNewDescription(
2163 TestClient* client,
2164 cricket::BaseSession::State state,
2165 cricket::ContentAction expected_content_action,
2166 cricket::ContentSource expected_content_source) {
2167 // Clean up before the new test.
2168 client->new_local_description = false;
2169 client->new_remote_description = false;
2170
2171 client->SetSessionState(state);
2172 EXPECT_EQ((expected_content_source == cricket::CS_LOCAL),
2173 client->new_local_description);
2174 EXPECT_EQ((expected_content_source == cricket::CS_REMOTE),
2175 client->new_remote_description);
2176 EXPECT_EQ(expected_content_action, client->last_content_action);
2177 EXPECT_EQ(expected_content_source, client->last_content_source);
2178 }
2179
2180 void TestCallerSignalNewDescription() {
2181 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
2182 new TestPortAllocator());
2183 int next_message_id = 0;
2184
2185 std::string content_name = "content-name";
2186 std::string content_type = "content-type";
2187 talk_base::scoped_ptr<TestClient> initiator(
2188 new TestClient(allocator.get(), &next_message_id,
2189 kInitiator, PROTOCOL_JINGLE,
2190 content_type,
2191 content_name, "",
2192 "", ""));
2193
2194 initiator->CreateSession();
2195
2196 // send offer -> send update offer ->
2197 // receive pr answer -> receive update pr answer ->
2198 // receive answer
2199 DoTestSignalNewDescription(
2200 initiator.get(), cricket::BaseSession::STATE_SENTINITIATE,
2201 cricket::CA_OFFER, cricket::CS_LOCAL);
2202
2203 DoTestSignalNewDescription(
2204 initiator.get(), cricket::BaseSession::STATE_SENTINITIATE,
2205 cricket::CA_OFFER, cricket::CS_LOCAL);
2206
2207 DoTestSignalNewDescription(
2208 initiator.get(), cricket::BaseSession::STATE_RECEIVEDPRACCEPT,
2209 cricket::CA_PRANSWER, cricket::CS_REMOTE);
2210
2211 DoTestSignalNewDescription(
2212 initiator.get(), cricket::BaseSession::STATE_RECEIVEDPRACCEPT,
2213 cricket::CA_PRANSWER, cricket::CS_REMOTE);
2214
2215 DoTestSignalNewDescription(
2216 initiator.get(), cricket::BaseSession::STATE_RECEIVEDACCEPT,
2217 cricket::CA_ANSWER, cricket::CS_REMOTE);
2218 }
2219
2220 void TestCalleeSignalNewDescription() {
2221 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
2222 new TestPortAllocator());
2223 int next_message_id = 0;
2224
2225 std::string content_name = "content-name";
2226 std::string content_type = "content-type";
2227 talk_base::scoped_ptr<TestClient> initiator(
2228 new TestClient(allocator.get(), &next_message_id,
2229 kInitiator, PROTOCOL_JINGLE,
2230 content_type,
2231 content_name, "",
2232 "", ""));
2233
2234 initiator->CreateSession();
2235
2236 // receive offer -> receive update offer ->
2237 // send pr answer -> send update pr answer ->
2238 // send answer
2239 DoTestSignalNewDescription(
2240 initiator.get(), cricket::BaseSession::STATE_RECEIVEDINITIATE,
2241 cricket::CA_OFFER, cricket::CS_REMOTE);
2242
2243 DoTestSignalNewDescription(
2244 initiator.get(), cricket::BaseSession::STATE_RECEIVEDINITIATE,
2245 cricket::CA_OFFER, cricket::CS_REMOTE);
2246
2247 DoTestSignalNewDescription(
2248 initiator.get(), cricket::BaseSession::STATE_SENTPRACCEPT,
2249 cricket::CA_PRANSWER, cricket::CS_LOCAL);
2250
2251 DoTestSignalNewDescription(
2252 initiator.get(), cricket::BaseSession::STATE_SENTPRACCEPT,
2253 cricket::CA_PRANSWER, cricket::CS_LOCAL);
2254
2255 DoTestSignalNewDescription(
2256 initiator.get(), cricket::BaseSession::STATE_SENTACCEPT,
2257 cricket::CA_ANSWER, cricket::CS_LOCAL);
2258 }
2259
2260 void TestGetTransportStats() {
2261 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
2262 new TestPortAllocator());
2263 int next_message_id = 0;
2264
2265 std::string content_name = "content-name";
2266 std::string content_type = "content-type";
2267 talk_base::scoped_ptr<TestClient> initiator(
2268 new TestClient(allocator.get(), &next_message_id,
2269 kInitiator, PROTOCOL_JINGLE,
2270 content_type,
2271 content_name, "",
2272 "", ""));
2273 initiator->CreateSession();
2274
2275 cricket::SessionStats stats;
2276 EXPECT_TRUE(initiator->session->GetStats(&stats));
2277 // At initiation, there are 2 transports.
2278 EXPECT_EQ(2ul, stats.proxy_to_transport.size());
2279 EXPECT_EQ(2ul, stats.transport_stats.size());
2280 }
2281};
2282
2283// For each of these, "X => Y = Z" means "if a client with protocol X
2284// initiates to a client with protocol Y, they end up speaking protocol Z.
2285
2286// Gingle => Gingle = Gingle (with other content)
2287TEST_F(SessionTest, GingleToGingleOtherContent) {
2288 TestOtherContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
2289}
2290
2291// Gingle => Gingle = Gingle (with audio content)
2292TEST_F(SessionTest, GingleToGingleAudioContent) {
2293 TestAudioContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
2294}
2295
2296// Gingle => Gingle = Gingle (with video contents)
2297TEST_F(SessionTest, GingleToGingleVideoContents) {
2298 TestVideoContents(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
2299}
2300
2301// Jingle => Jingle = Jingle (with other content)
2302TEST_F(SessionTest, JingleToJingleOtherContent) {
2303 TestOtherContent(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
2304}
2305
2306// Jingle => Jingle = Jingle (with audio content)
2307TEST_F(SessionTest, JingleToJingleAudioContent) {
2308 TestAudioContent(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
2309}
2310
2311// Jingle => Jingle = Jingle (with video contents)
2312TEST_F(SessionTest, JingleToJingleVideoContents) {
2313 TestVideoContents(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
2314}
2315
2316// Hybrid => Hybrid = Jingle (with other content)
2317TEST_F(SessionTest, HybridToHybridOtherContent) {
2318 TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
2319}
2320
2321// Hybrid => Hybrid = Jingle (with audio content)
2322TEST_F(SessionTest, HybridToHybridAudioContent) {
2323 TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
2324}
2325
2326// Hybrid => Hybrid = Jingle (with video contents)
2327TEST_F(SessionTest, HybridToHybridVideoContents) {
2328 TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
2329}
2330
2331// Gingle => Hybrid = Gingle (with other content)
2332TEST_F(SessionTest, GingleToHybridOtherContent) {
2333 TestOtherContent(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE);
2334}
2335
2336// Gingle => Hybrid = Gingle (with audio content)
2337TEST_F(SessionTest, GingleToHybridAudioContent) {
2338 TestAudioContent(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE);
2339}
2340
2341// Gingle => Hybrid = Gingle (with video contents)
2342TEST_F(SessionTest, GingleToHybridVideoContents) {
2343 TestVideoContents(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE);
2344}
2345
2346// Jingle => Hybrid = Jingle (with other content)
2347TEST_F(SessionTest, JingleToHybridOtherContent) {
2348 TestOtherContent(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
2349}
2350
2351// Jingle => Hybrid = Jingle (with audio content)
2352TEST_F(SessionTest, JingleToHybridAudioContent) {
2353 TestAudioContent(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
2354}
2355
2356// Jingle => Hybrid = Jingle (with video contents)
2357TEST_F(SessionTest, JingleToHybridVideoContents) {
2358 TestVideoContents(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
2359}
2360
2361// Hybrid => Gingle = Gingle (with other content)
2362TEST_F(SessionTest, HybridToGingleOtherContent) {
2363 TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
2364}
2365
2366// Hybrid => Gingle = Gingle (with audio content)
2367TEST_F(SessionTest, HybridToGingleAudioContent) {
2368 TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
2369}
2370
2371// Hybrid => Gingle = Gingle (with video contents)
2372TEST_F(SessionTest, HybridToGingleVideoContents) {
2373 TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
2374}
2375
2376// Hybrid => Jingle = Jingle (with other content)
2377TEST_F(SessionTest, HybridToJingleOtherContent) {
2378 TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
2379}
2380
2381// Hybrid => Jingle = Jingle (with audio content)
2382TEST_F(SessionTest, HybridToJingleAudioContent) {
2383 TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
2384}
2385
2386// Hybrid => Jingle = Jingle (with video contents)
2387TEST_F(SessionTest, HybridToJingleVideoContents) {
2388 TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
2389}
2390
2391TEST_F(SessionTest, GingleEarlyTerminationFromInitiator) {
2392 TestEarlyTerminationFromInitiator(PROTOCOL_GINGLE);
2393}
2394
2395TEST_F(SessionTest, JingleEarlyTerminationFromInitiator) {
2396 TestEarlyTerminationFromInitiator(PROTOCOL_JINGLE);
2397}
2398
2399TEST_F(SessionTest, HybridEarlyTerminationFromInitiator) {
2400 TestEarlyTerminationFromInitiator(PROTOCOL_HYBRID);
2401}
2402
2403TEST_F(SessionTest, GingleRejection) {
2404 TestRejection(PROTOCOL_GINGLE);
2405}
2406
2407TEST_F(SessionTest, JingleRejection) {
2408 TestRejection(PROTOCOL_JINGLE);
2409}
2410
2411TEST_F(SessionTest, GingleGoodRedirect) {
2412 TestGoodRedirect(PROTOCOL_GINGLE);
2413}
2414
2415TEST_F(SessionTest, JingleGoodRedirect) {
2416 TestGoodRedirect(PROTOCOL_JINGLE);
2417}
2418
2419TEST_F(SessionTest, GingleBadRedirect) {
2420 TestBadRedirect(PROTOCOL_GINGLE);
2421}
2422
2423TEST_F(SessionTest, JingleBadRedirect) {
2424 TestBadRedirect(PROTOCOL_JINGLE);
2425}
2426
2427TEST_F(SessionTest, TestCandidatesInInitiateAndAccept) {
2428 TestCandidatesInInitiateAndAccept("Candidates in initiate/accept");
2429}
2430
2431TEST_F(SessionTest, TestTransportMux) {
2432 TestTransportMux();
2433}
2434
2435TEST_F(SessionTest, TestSendDescriptionInfo) {
2436 TestSendDescriptionInfo();
2437}
2438
2439TEST_F(SessionTest, TestCallerSignalNewDescription) {
2440 TestCallerSignalNewDescription();
2441}
2442
2443TEST_F(SessionTest, TestCalleeSignalNewDescription) {
2444 TestCalleeSignalNewDescription();
2445}
2446
2447TEST_F(SessionTest, TestGetTransportStats) {
2448 TestGetTransportStats();
2449}