3 * Copyright 2004 Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
34 #include "talk/base/base64.h"
35 #include "talk/base/common.h"
36 #include "talk/base/gunit.h"
37 #include "talk/base/helpers.h"
38 #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"
59 using cricket::SignalingProtocol;
60 using cricket::PROTOCOL_HYBRID;
61 using cricket::PROTOCOL_JINGLE;
62 using cricket::PROTOCOL_GINGLE;
64 static const std::string kInitiator = "init@init.com";
65 static const std::string kResponder = "resp@resp.com";
66 // Expected from test random number generator.
67 static 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.
70 static const std::string kTransportType = "http://www.google.com/transport/p2p";
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.
74 static const int kEventTimeout = 5000;
76 static const int kNumPorts = 2;
77 static const int kPort0 = 28653;
78 static const int kPortStep = 5;
80 int GetPort(int port_index) {
81 return kPort0 + (port_index * kPortStep);
84 std::string GetPortString(int port_index) {
85 return talk_base::ToString(GetPort(port_index));
88 // Only works for port_index < 10, which is fine for our purposes.
89 std::string GetUsername(int port_index) {
90 return "username" + std::string(8, talk_base::ToString(port_index)[0]);
93 // Only works for port_index < 10, which is fine for our purposes.
94 std::string GetPassword(int port_index) {
95 return "password" + std::string(8, talk_base::ToString(port_index)[0]);
98 std::string IqAck(const std::string& id,
99 const std::string& from,
100 const std::string& to) {
105 " from=\"" + from + "\""
106 " xmlns:cli=\"jabber:client\""
110 std::string IqSet(const std::string& id,
111 const std::string& from,
112 const std::string& to,
113 const std::string& content) {
117 " from=\"" + from + "\""
119 " xmlns:cli=\"jabber:client\""
125 std::string IqError(const std::string& id,
126 const std::string& from,
127 const std::string& to,
128 const std::string& content) {
132 " from=\"" + from + "\""
134 " xmlns:cli=\"jabber:client\""
140 std::string GingleSessionXml(const std::string& type,
141 const std::string& content) {
143 " xmlns=\"http://www.google.com/session\""
144 " type=\"" + type + "\""
145 " id=\"" + kSessionId + "\""
146 " initiator=\"" + kInitiator + "\""
152 std::string GingleDescriptionXml(const std::string& content_type) {
153 return "<description"
154 " xmlns=\"" + content_type + "\""
158 std::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;
171 " name=\"" + name + "\""
172 " address=\"127.0.0.1\""
173 " port=\"" + GetPortString(port_index) + "\""
174 " preference=\"0.99\""
175 " username=\"" + username + "\""
178 " password=\"" + GetPassword(port_index) + "\""
180 " network=\"network\""
184 std::string JingleActionXml(const std::string& action,
185 const std::string& content) {
187 " xmlns=\"urn:xmpp:jingle:1\""
188 " action=\"" + action + "\""
189 " sid=\"" + kSessionId + "\""
195 std::string JingleInitiateActionXml(const std::string& content) {
197 " xmlns=\"urn:xmpp:jingle:1\""
198 " action=\"session-initiate\""
199 " sid=\"" + kSessionId + "\""
200 " initiator=\"" + kInitiator + "\""
206 std::string JingleGroupInfoXml(const std::string& content_name_a,
207 const std::string& content_name_b) {
208 std::string group_info = "<jin:group"
210 " xmlns:jin=\"google:jingle\""
212 if (!content_name_a.empty())
213 group_info += "<content name=\"" + content_name_a + "\""
215 if (!content_name_b.empty())
216 group_info += "<content name=\"" + content_name_b + "\""
218 group_info += "</jin:group>";
223 std::string JingleEmptyContentXml(const std::string& content_name,
224 const std::string& content_type,
225 const std::string& transport_type) {
227 " name=\"" + content_name + "\""
228 " creator=\"initiator\""
231 " xmlns=\"" + content_type + "\""
234 " xmlns=\"" + transport_type + "\""
239 std::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() ? "" :
245 " xmlns=\"" + transport_type + "\""
251 " name=\"" + content_name + "\""
252 " creator=\"initiator\""
255 " xmlns=\"" + content_type + "\""
261 std::string JingleTransportContentXml(const std::string& content_name,
262 const std::string& transport_type,
263 const std::string& content) {
265 " name=\"" + content_name + "\""
266 " creator=\"initiator\""
269 " xmlns=\"" + transport_type + "\""
276 std::string GingleInitiateXml(const std::string& content_type) {
277 return GingleSessionXml(
279 GingleDescriptionXml(content_type));
282 std::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);
292 content_xml = JingleEmptyContentXml(
293 content_name_a, content_type_a, kTransportType) +
294 JingleEmptyContentXml(
295 content_name_b, content_type_b, kTransportType);
297 content_xml += JingleGroupInfoXml(content_name_a, content_name_b);
300 return JingleInitiateActionXml(content_xml);
303 std::string GingleAcceptXml(const std::string& content_type) {
304 return GingleSessionXml(
306 GingleDescriptionXml(content_type));
309 std::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);
319 content_xml = JingleEmptyContentXml(
320 content_name_a, content_type_a, kTransportType) +
321 JingleEmptyContentXml(
322 content_name_b, content_type_b, kTransportType);
325 content_xml += JingleGroupInfoXml(content_name_a, content_name_b);
328 return JingleActionXml("session-accept", content_xml);
331 std::string Gingle2CandidatesXml(const std::string& channel_name,
334 return GingleSessionXml(
336 P2pCandidateXml(channel_name, port_index0) +
337 P2pCandidateXml(channel_name, port_index1));
340 std::string Gingle4CandidatesXml(const std::string& channel_name_a,
343 const std::string& channel_name_b,
346 return GingleSessionXml(
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));
354 std::string Jingle2TransportInfoXml(const std::string& content_name,
355 const std::string& channel_name,
358 return JingleActionXml(
360 JingleTransportContentXml(
361 content_name, kTransportType,
362 P2pCandidateXml(channel_name, port_index0) +
363 P2pCandidateXml(channel_name, port_index1)));
366 std::string Jingle4TransportInfoXml(const std::string& content_name,
367 const std::string& channel_name_a,
370 const std::string& channel_name_b,
373 return JingleActionXml(
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)));
383 std::string JingleDescriptionInfoXml(const std::string& content_name,
384 const std::string& content_type) {
385 return JingleActionXml(
387 JingleContentXml(content_name, content_type, "", ""));
390 std::string GingleRejectXml(const std::string& reason) {
391 return GingleSessionXml(
393 "<" + reason + "/>");
396 std::string JingleTerminateXml(const std::string& reason) {
397 return JingleActionXml(
399 "<reason><" + reason + "/></reason>");
402 std::string GingleTerminateXml(const std::string& reason) {
403 return GingleSessionXml(
405 "<" + reason + "/>");
408 std::string GingleRedirectXml(const std::string& intitiate,
409 const std::string& target) {
411 "<error code=\"302\" type=\"modify\">"
412 "<redirect xmlns=\"http://www.google.com/session\">"
418 std::string JingleRedirectXml(const std::string& intitiate,
419 const std::string& target) {
421 "<error code=\"302\" type=\"modify\">"
422 "<redirect xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\">"
428 std::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) {
436 case PROTOCOL_JINGLE:
437 return JingleInitiateXml(content_name_a, content_type_a,
438 content_name_b, content_type_b,
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);
450 std::string InitiateXml(SignalingProtocol protocol,
451 const std::string& content_name,
452 const std::string& content_type) {
453 return InitiateXml(protocol,
455 content_name, content_type,
459 std::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) {
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:
474 JingleAcceptXml(content_name_a, content_type_a,
475 content_name_b, content_type_b) +
476 GingleAcceptXml(gingle_content_type);
482 std::string AcceptXml(SignalingProtocol protocol,
483 const std::string& content_name,
484 const std::string& content_type,
485 bool bundle = false) {
486 return AcceptXml(protocol,
488 content_name, content_type,
492 std::string TransportInfo2Xml(SignalingProtocol protocol,
493 const std::string& content_name,
494 const std::string& channel_name,
498 case PROTOCOL_JINGLE:
499 return Jingle2TransportInfoXml(
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:
507 Jingle2TransportInfoXml(
509 channel_name, port_index0, port_index1) +
510 Gingle2CandidatesXml(
511 channel_name, port_index0, port_index1);
516 std::string TransportInfo4Xml(SignalingProtocol protocol,
517 const std::string& content_name,
518 const std::string& channel_name_a,
521 const std::string& channel_name_b,
525 case PROTOCOL_JINGLE:
526 return Jingle4TransportInfoXml(
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:
536 Jingle4TransportInfoXml(
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);
547 std::string RejectXml(SignalingProtocol protocol,
548 const std::string& reason) {
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);
561 std::string TerminateXml(SignalingProtocol protocol,
562 const std::string& reason) {
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);
575 std::string RedirectXml(SignalingProtocol protocol,
576 const std::string& initiate,
577 const std::string& target) {
579 case PROTOCOL_JINGLE:
580 return JingleRedirectXml(initiate, target);
581 case PROTOCOL_GINGLE:
582 return GingleRedirectXml(initiate, target);
589 // TODO: Break out and join with fakeportallocator.h
590 class TestPortAllocatorSession : public cricket::PortAllocatorSession {
592 TestPortAllocatorSession(const std::string& content_name,
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),
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()),
606 network_.AddIP(address_.ipaddr());
609 ~TestPortAllocatorSession() {
610 for (size_t i = 0; i < ports_.size(); i++)
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));
626 virtual void StopGettingPorts() { running_ = false; }
627 virtual bool IsGettingPorts() { return running_; }
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);
640 void OnPortDestroyed(cricket::PortInterface* port) {
641 for (size_t i = 0; i < ports_.size(); i++) {
642 if (ports_[i] == port)
647 void OnPortComplete(cricket::Port* port) {
648 SignalCandidatesReady(this, port->Candidates());
653 std::vector<cricket::Port*> ports_;
654 talk_base::SocketAddress address_;
655 talk_base::Network network_;
656 talk_base::BasicPacketSocketFactory socket_factory_;
661 class TestPortAllocator : public cricket::PortAllocator {
663 TestPortAllocator() : port_offset_(0) {}
665 virtual cricket::PortAllocatorSession*
666 CreateSessionInternal(
667 const std::string& content_name,
669 const std::string& ice_ufrag,
670 const std::string& ice_pwd) {
672 return new TestPortAllocatorSession(content_name, component,
673 ice_ufrag, ice_pwd, port_offset_ - 2);
679 class TestContentDescription : public cricket::ContentDescription {
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) {
686 virtual ContentDescription* Copy() const {
687 return new TestContentDescription(*this);
690 std::string gingle_content_type;
691 std::string content_type;
694 cricket::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) {
699 cricket::SessionDescription* offer = new cricket::SessionDescription();
700 offer->AddContent(content_name_a, content_type_a,
701 new TestContentDescription(gingle_content_type,
703 cricket::TransportDescription desc(cricket::NS_GINGLE_P2P,
704 std::string(), std::string());
705 offer->AddTransportInfo(cricket::TransportInfo(content_name_a, desc));
707 if (content_name_a != content_name_b) {
708 offer->AddContent(content_name_b, content_type_b,
709 new TestContentDescription(gingle_content_type,
711 offer->AddTransportInfo(cricket::TransportInfo(content_name_b, desc));
716 cricket::SessionDescription* NewTestSessionDescription(
717 const std::string& content_name, const std::string& content_type) {
719 cricket::SessionDescription* offer = new cricket::SessionDescription();
720 offer->AddContent(content_name, content_type,
721 new TestContentDescription(content_type,
723 offer->AddTransportInfo(cricket::TransportInfo
724 (content_name, cricket::TransportDescription(
725 cricket::NS_GINGLE_P2P,
726 std::string(), std::string())));
730 struct TestSessionClient: public cricket::SessionClient,
731 public sigslot::has_slots<> {
733 TestSessionClient() {
736 ~TestSessionClient() {
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();
748 content_type = elem->Name().Namespace();
751 *content = new TestContentDescription(gingle_content_type, content_type);
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);
769 void OnSessionCreate(cricket::Session* session, bool initiate) {
772 void OnSessionDestroy(cricket::Session* session) {
776 struct 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);
785 bool writable() const {
786 return last_writable && channel->writable();
789 bool readable() const {
790 return last_readable && channel->readable();
793 void OnReadableState(cricket::TransportChannel* p) {
794 EXPECT_EQ(channel, p);
795 last_readable = channel->readable();
798 void OnWritableState(cricket::TransportChannel* p) {
799 EXPECT_EQ(channel, p);
800 last_writable = channel->writable();
803 void OnReadPacket(cricket::TransportChannel* p, const char* buf,
804 size_t size, const talk_base::PacketTime& time, int flags) {
805 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));
814 memcpy(last_data, buf, size);
817 void Send(const char* data, size_t size) {
818 talk_base::PacketOptions options;
819 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(),
823 EXPECT_EQ(static_cast<int>(data_with_id.size()), result);
826 cricket::TransportChannel* channel;
827 bool last_readable, last_writable;
829 char last_data[4096];
834 void PrintStanza(const std::string& message,
835 const buzz::XmlElement* stanza) {
836 printf("%s: %s\n", message.c_str(), stanza->Str().c_str());
839 class TestClient : public sigslot::has_slots<> {
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);
858 session_manager->DestroySession(session);
859 EXPECT_EQ(1U, session_destroyed_count);
861 delete session_manager;
863 for (std::deque<buzz::XmlElement*>::iterator it = sent_stanzas.begin();
864 it != sent_stanzas.end(); ++it) {
869 void Construct(cricket::PortAllocator* pa,
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;
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;
895 last_session_state = cricket::BaseSession::STATE_INIT;
896 blow_up_on_error = true;
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);
907 client = new TestSessionClient();
908 session_manager->AddClient(content_type, client);
909 EXPECT_EQ(client, session_manager->GetClient(content_type));
912 uint32 sent_stanza_count() const {
913 return static_cast<uint32>(sent_stanzas.size());
916 const buzz::XmlElement* stanza() const {
917 return last_expected_sent_stanza.get();
920 cricket::BaseSession::State session_state() const {
921 EXPECT_EQ(last_session_state, session->state());
922 return session->state();
925 void SetSessionState(cricket::BaseSession::State state) {
926 session->SetState(state);
927 EXPECT_EQ_WAIT(last_session_state, session->state(), kEventTimeout);
930 void CreateSession() {
931 session_manager->CreateSession(local_name, content_type);
934 void DeliverStanza(const buzz::XmlElement* stanza) {
935 session_manager->OnIncomingMessage(stanza);
938 void DeliverStanza(const std::string& str) {
939 buzz::XmlElement* stanza = buzz::XmlElement::ForStr(str);
940 session_manager->OnIncomingMessage(stanza);
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;
952 void ExpectSentStanza(const std::string& expected) {
953 EXPECT_TRUE(!sent_stanzas.empty()) <<
954 "Found no stanza when expected " << expected;
956 last_expected_sent_stanza.reset(sent_stanzas.front());
957 sent_stanzas.pop_front();
959 std::string actual = last_expected_sent_stanza->Str();
960 EXPECT_EQ(expected, actual);
963 void SkipUnsentStanza() {
964 GetNextOutgoingMessageID();
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());
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());
981 cricket::TransportChannel* GetChannel(const std::string& content_name,
982 int component) const {
983 ASSERT(session != NULL);
984 return session->GetChannel(content_name, component);
987 void OnSessionCreate(cricket::Session* created_session, bool initiate) {
988 session_created_count += 1;
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);
1004 void OnSessionDestroy(cricket::Session *session) {
1005 session_destroyed_count += 1;
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;
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) {
1028 void OnSessionRemoteDescriptionUpdate(cricket::BaseSession* session,
1029 const cricket::ContentInfos& contents) {
1030 session_remote_description_update_count++;
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;
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;
1047 void PrepareCandidates() {
1048 session_manager->OnSignalingReady();
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"));
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());
1068 // Uncommenting this is useful for debugging.
1069 // PrintStanza("OutgoingMessage", elem);
1070 sent_stanzas.push_back(elem);
1073 std::string GetNextOutgoingMessageID() {
1074 int message_id = (*next_message_id)++;
1075 std::ostringstream ost;
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;
1086 chan_a.reset(new ChannelHandler(
1087 session->CreateChannel(content_name_a, channel_name_a, component_a),
1089 chan_b.reset(new ChannelHandler(
1090 session->CreateChannel(content_name_b, channel_name_b, component_b),
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;
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;
1111 talk_base::scoped_ptr<buzz::XmlElement> last_expected_sent_stanza;
1113 cricket::SessionManager* session_manager;
1114 TestSessionClient* client;
1115 cricket::PortAllocator* port_allocator_;
1116 cricket::Session* session;
1117 cricket::BaseSession::State last_session_state;
1118 talk_base::scoped_ptr<ChannelHandler> chan_a;
1119 talk_base::scoped_ptr<ChannelHandler> chan_b;
1120 bool blow_up_on_error;
1124 class SessionTest : public testing::Test {
1126 virtual void SetUp() {
1127 // Seed needed for each test to satisfy expectations.
1128 talk_base::SetRandomTestMode(true);
1131 virtual void TearDown() {
1132 talk_base::SetRandomTestMode(false);
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";
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));
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);
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);
1161 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)));
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;
1192 talk_base::scoped_ptr<TestClient> initiator(
1193 new TestClient(allocator.get(), &next_message_id,
1194 kInitiator, initiator_protocol,
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,
1202 content_name_a, channel_name_a,
1203 content_name_b, channel_name_b));
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());
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));
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);
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);
1234 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer));
1235 EXPECT_EQ(initiator->session->remote_name(), kResponder);
1236 EXPECT_EQ(initiator->session->local_description(), offer);
1238 EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout);
1239 EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE,
1240 initiator->session_state());
1242 initiator->ExpectSentStanza(
1243 IqSet("0", kInitiator, kResponder, initiate_xml));
1245 // Deliver the initiate. Expect ack and session created with
1247 responder->DeliverStanza(initiator->stanza());
1248 responder->ExpectSentStanza(
1249 IqAck("0", kResponder, kInitiator));
1250 EXPECT_EQ(0U, responder->sent_stanza_count());
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());
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));
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));
1274 // Deliver transport-info and expect ack.
1275 responder->DeliverStanza(initiator->stanza());
1276 responder->ExpectSentStanza(
1277 IqAck("1", kResponder, kInitiator));
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());
1286 // Deliver second transport-info message and expect ack.
1287 responder->DeliverStanza(initiator->stanza());
1288 responder->ExpectSentStanza(
1289 IqAck("2", kResponder, kInitiator));
1291 EXPECT_EQ(0U, initiator->sent_stanza_count());
1292 EXPECT_EQ(0U, responder->sent_stanza_count());
1293 initiator->SkipUnsentStanza();
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));
1302 // Deliver reply transport-info and expect ack.
1303 initiator->DeliverStanza(responder->stanza());
1304 initiator->ExpectSentStanza(
1305 IqAck("3", kInitiator, kResponder));
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());
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());
1320 EXPECT_EQ(0U, initiator->sent_stanza_count());
1321 EXPECT_EQ(0U, responder->sent_stanza_count());
1322 responder->SkipUnsentStanza();
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);
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);
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);
1349 EXPECT_TRUE(responder->session->Accept(answer));
1350 EXPECT_EQ(responder->session->local_description(), answer);
1352 responder->ExpectSentStanza(
1353 IqSet("5", kResponder, kInitiator, accept_xml));
1355 EXPECT_EQ(0U, responder->sent_stanza_count());
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());
1364 // Both sessions should be in progress and have functioning
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);
1373 cricket::TransportChannel* initiator_chan_a = initiator->chan_a->channel;
1374 cricket::TransportChannel* initiator_chan_b = initiator->chan_b->channel;
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());
1385 cricket::TransportChannel* responder_chan_a = responder->chan_a->channel;
1386 cricket::TransportChannel* responder_chan_b = responder->chan_b->channel;
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());
1397 TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(),
1398 responder->chan_a.get(), responder->chan_b.get());
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);
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);
1418 LOG(LS_INFO) << "A " << old_content_a->name;
1419 LOG(LS_INFO) << "B " << old_content_b->name;
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);
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);
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
1447 // See session.cc OnDescriptionInfoMessage.
1449 // EXPECT_NE(old_content_desc_a, new_content_desc_a);
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);
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());
1463 responder->SkipUnsentStanza();
1466 initiator->session->Terminate();
1467 initiator->ExpectSentStanza(
1468 IqSet("7", kInitiator, kResponder,
1469 TerminateXml(resulting_protocol,
1470 cricket::STR_TERMINATE_SUCCESS)));
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());
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(
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(
1506 content_name_a, content_type);
1509 TestSession(initiator_protocol, responder_protocol, resulting_protocol,
1512 content_name_a, channel_name_a,
1513 content_name_b, channel_name_b,
1515 transport_info_a_xml, transport_info_b_xml,
1516 transport_info_reply_a_xml, transport_info_reply_b_xml,
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(
1531 gingle_content_type,
1532 content_name, content_type,
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(
1546 gingle_content_type,
1547 content_name, content_type,
1551 TestSession(initiator_protocol, responder_protocol, resulting_protocol,
1552 gingle_content_type,
1554 content_name, channel_name_a,
1555 content_name, channel_name_b,
1557 transport_info_a_xml, transport_info_b_xml,
1558 transport_info_reply_a_xml, transport_info_reply_b_xml,
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";
1574 std::string initiate_xml = InitiateXml(
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(
1593 gingle_content_type,
1594 content_name_a, content_type,
1595 content_name_b, content_type);
1597 TestSession(initiator_protocol, responder_protocol, resulting_protocol,
1598 gingle_content_type,
1600 content_name_a, channel_name_a,
1601 content_name_b, channel_name_b,
1603 transport_info_a_xml, transport_info_b_xml,
1604 transport_info_reply_a_xml, transport_info_reply_b_xml,
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";
1627 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
1628 new TestPortAllocator());
1629 int next_message_id = 0;
1631 talk_base::scoped_ptr<TestClient> initiator(
1632 new TestClient(allocator.get(), &next_message_id,
1633 kInitiator, protocol,
1635 content_name, channel_name_a,
1636 content_name, channel_name_b));
1638 talk_base::scoped_ptr<TestClient> responder(
1639 new TestClient(allocator.get(), &next_message_id,
1640 responder_full, protocol,
1642 content_name, channel_name_a,
1643 content_name, channel_name_b));
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());
1653 EXPECT_TRUE(initiator->HasChannel(content_name, 1));
1654 EXPECT_TRUE(initiator->HasChannel(content_name, 2));
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);
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));
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));
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);
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";
1709 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
1710 new TestPortAllocator());
1711 int next_message_id = 0;
1713 talk_base::scoped_ptr<TestClient> initiator(
1714 new TestClient(allocator.get(), &next_message_id,
1715 kInitiator, protocol,
1717 content_name, channel_name_a,
1718 content_name, channel_name_b));
1720 talk_base::scoped_ptr<TestClient> responder(
1721 new TestClient(allocator.get(), &next_message_id,
1722 responder_full, protocol,
1724 content_name, channel_name_a,
1725 content_name, channel_name_b));
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());
1735 EXPECT_TRUE(initiator->HasChannel(content_name, 1));
1736 EXPECT_TRUE(initiator->HasChannel(content_name, 2));
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);
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));
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));
1758 // Send a redirect to the initiator and expect all of the message
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);
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));
1775 // Deliver the initiate. Expect ack and session created with
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());
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());
1790 EXPECT_TRUE(responder->HasChannel(content_name, 1));
1791 EXPECT_TRUE(responder->HasChannel(content_name, 2));
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));
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));
1805 initiator->DeliverStanza(responder->stanza());
1806 initiator->ExpectSentStanza(
1807 IqAck("4", kInitiator, responder_full));
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);
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);
1826 responder->ExpectSentStanza(
1827 IqSet("5", responder_full, kInitiator, accept_xml));
1828 EXPECT_EQ(0U, responder->sent_stanza_count());
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());
1837 // Both sessions should be in progress and have functioning
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);
1843 TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(),
1844 responder->chan_a.get(), responder->chan_b.get());
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;
1854 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
1855 new TestPortAllocator());
1856 int next_message_id = 0;
1858 talk_base::scoped_ptr<TestClient> initiator(
1859 new TestClient(allocator.get(), &next_message_id,
1860 kInitiator, protocol,
1862 content_name, channel_name_a,
1863 content_name, channel_name_b));
1865 talk_base::scoped_ptr<TestClient> responder(
1866 new TestClient(allocator.get(), &next_message_id,
1867 kResponder, protocol,
1869 content_name, channel_name_a,
1870 content_name, channel_name_b));
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));
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));
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)));
1891 // Fake the delivery the initiate and candidates together.
1892 responder->DeliverStanza(
1893 IqSet("A", kInitiator, kResponder,
1894 JingleInitiateActionXml(
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());
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());
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));
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)));
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)));
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));
1941 responder->ExpectSentStanza(
1942 IqSet("3", kResponder, kInitiator,
1943 AcceptXml(protocol, content_name, content_type)));
1944 EXPECT_EQ(0U, responder->sent_stanza_count());
1946 // Fake the delivery the accept and candidates together.
1947 initiator->DeliverStanza(
1948 IqSet("B", kResponder, kInitiator,
1949 JingleActionXml("session-accept",
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());
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);
1973 // Both sessions should be in progress and have functioning
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);
1981 TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(),
1982 responder->chan_a.get(), responder->chan_b.get());
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";
1991 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
1992 new TestPortAllocator());
1993 int next_message_id = 0;
1995 talk_base::scoped_ptr<TestClient> initiator(
1996 new TestClient(allocator.get(), &next_message_id,
1997 kInitiator, protocol,
2000 content_name, "b"));
2002 talk_base::scoped_ptr<TestClient> responder(
2003 new TestClient(allocator.get(), &next_message_id,
2004 kResponder, protocol,
2007 content_name, "b"));
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());
2019 responder->DeliverStanza(initiator->stanza());
2020 responder->ExpectSentStanza(
2021 IqAck("0", kResponder, kInitiator));
2022 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE,
2023 responder->session_state());
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());
2032 responder->DeliverStanza(initiator->stanza());
2033 responder->ExpectSentStanza(
2034 IqAck("1", kResponder, kInitiator));
2035 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE,
2036 responder->session_state());
2039 // Tests that when the responder rejects, everything behaves
2041 void TestRejection(SignalingProtocol protocol) {
2042 std::string content_name = "main";
2043 std::string content_type = "http://oink.splat/session";
2045 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
2046 new TestPortAllocator());
2047 int next_message_id = 0;
2049 talk_base::scoped_ptr<TestClient> initiator(
2050 new TestClient(allocator.get(), &next_message_id,
2051 kInitiator, protocol,
2054 content_name, "b"));
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());
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());
2075 EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDREJECT,
2076 initiator->session_state());
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";
2091 std::string initiate_xml = InitiateXml(
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(
2110 gingle_content_type,
2111 content_name_a, content_type,
2112 content_name_b, content_type, true);
2114 TestSession(initiator_protocol, responder_protocol, resulting_protocol,
2115 gingle_content_type,
2117 content_name_a, channel_name_a,
2118 content_name_b, channel_name_b,
2120 transport_info_a_xml, transport_info_b_xml,
2121 transport_info_reply_a_xml, transport_info_reply_b_xml,
2126 void TestSendDescriptionInfo() {
2127 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
2128 new TestPortAllocator());
2129 int next_message_id = 0;
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,
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);
2146 cricket::ContentInfos contents;
2147 TestContentDescription content(content_type, content_type);
2149 cricket::ContentInfo(content_name, content_type, &content));
2150 std::string description_info_xml = JingleDescriptionInfoXml(
2151 content_name, content_type);
2153 EXPECT_TRUE(initiator->session->Initiate(kResponder, offer));
2154 initiator->ExpectSentStanza(
2155 IqSet("0", kInitiator, kResponder, initiate_xml));
2157 EXPECT_TRUE(initiator->session->SendDescriptionInfoMessage(contents));
2158 initiator->ExpectSentStanza(
2159 IqSet("1", kInitiator, kResponder, description_info_xml));
2162 void DoTestSignalNewDescription(
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;
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);
2180 void TestCallerSignalNewDescription() {
2181 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
2182 new TestPortAllocator());
2183 int next_message_id = 0;
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,
2194 initiator->CreateSession();
2196 // send offer -> send update offer ->
2197 // receive pr answer -> receive update pr answer ->
2199 DoTestSignalNewDescription(
2200 initiator.get(), cricket::BaseSession::STATE_SENTINITIATE,
2201 cricket::CA_OFFER, cricket::CS_LOCAL);
2203 DoTestSignalNewDescription(
2204 initiator.get(), cricket::BaseSession::STATE_SENTINITIATE,
2205 cricket::CA_OFFER, cricket::CS_LOCAL);
2207 DoTestSignalNewDescription(
2208 initiator.get(), cricket::BaseSession::STATE_RECEIVEDPRACCEPT,
2209 cricket::CA_PRANSWER, cricket::CS_REMOTE);
2211 DoTestSignalNewDescription(
2212 initiator.get(), cricket::BaseSession::STATE_RECEIVEDPRACCEPT,
2213 cricket::CA_PRANSWER, cricket::CS_REMOTE);
2215 DoTestSignalNewDescription(
2216 initiator.get(), cricket::BaseSession::STATE_RECEIVEDACCEPT,
2217 cricket::CA_ANSWER, cricket::CS_REMOTE);
2220 void TestCalleeSignalNewDescription() {
2221 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
2222 new TestPortAllocator());
2223 int next_message_id = 0;
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,
2234 initiator->CreateSession();
2236 // receive offer -> receive update offer ->
2237 // send pr answer -> send update pr answer ->
2239 DoTestSignalNewDescription(
2240 initiator.get(), cricket::BaseSession::STATE_RECEIVEDINITIATE,
2241 cricket::CA_OFFER, cricket::CS_REMOTE);
2243 DoTestSignalNewDescription(
2244 initiator.get(), cricket::BaseSession::STATE_RECEIVEDINITIATE,
2245 cricket::CA_OFFER, cricket::CS_REMOTE);
2247 DoTestSignalNewDescription(
2248 initiator.get(), cricket::BaseSession::STATE_SENTPRACCEPT,
2249 cricket::CA_PRANSWER, cricket::CS_LOCAL);
2251 DoTestSignalNewDescription(
2252 initiator.get(), cricket::BaseSession::STATE_SENTPRACCEPT,
2253 cricket::CA_PRANSWER, cricket::CS_LOCAL);
2255 DoTestSignalNewDescription(
2256 initiator.get(), cricket::BaseSession::STATE_SENTACCEPT,
2257 cricket::CA_ANSWER, cricket::CS_LOCAL);
2260 void TestGetTransportStats() {
2261 talk_base::scoped_ptr<cricket::PortAllocator> allocator(
2262 new TestPortAllocator());
2263 int next_message_id = 0;
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,
2273 initiator->CreateSession();
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());
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.
2286 // Gingle => Gingle = Gingle (with other content)
2287 TEST_F(SessionTest, GingleToGingleOtherContent) {
2288 TestOtherContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
2291 // Gingle => Gingle = Gingle (with audio content)
2292 TEST_F(SessionTest, GingleToGingleAudioContent) {
2293 TestAudioContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
2296 // Gingle => Gingle = Gingle (with video contents)
2297 TEST_F(SessionTest, GingleToGingleVideoContents) {
2298 TestVideoContents(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
2301 // Jingle => Jingle = Jingle (with other content)
2302 TEST_F(SessionTest, JingleToJingleOtherContent) {
2303 TestOtherContent(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
2306 // Jingle => Jingle = Jingle (with audio content)
2307 TEST_F(SessionTest, JingleToJingleAudioContent) {
2308 TestAudioContent(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
2311 // Jingle => Jingle = Jingle (with video contents)
2312 TEST_F(SessionTest, JingleToJingleVideoContents) {
2313 TestVideoContents(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
2316 // Hybrid => Hybrid = Jingle (with other content)
2317 TEST_F(SessionTest, HybridToHybridOtherContent) {
2318 TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
2321 // Hybrid => Hybrid = Jingle (with audio content)
2322 TEST_F(SessionTest, HybridToHybridAudioContent) {
2323 TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
2326 // Hybrid => Hybrid = Jingle (with video contents)
2327 TEST_F(SessionTest, HybridToHybridVideoContents) {
2328 TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
2331 // Gingle => Hybrid = Gingle (with other content)
2332 TEST_F(SessionTest, GingleToHybridOtherContent) {
2333 TestOtherContent(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE);
2336 // Gingle => Hybrid = Gingle (with audio content)
2337 TEST_F(SessionTest, GingleToHybridAudioContent) {
2338 TestAudioContent(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE);
2341 // Gingle => Hybrid = Gingle (with video contents)
2342 TEST_F(SessionTest, GingleToHybridVideoContents) {
2343 TestVideoContents(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE);
2346 // Jingle => Hybrid = Jingle (with other content)
2347 TEST_F(SessionTest, JingleToHybridOtherContent) {
2348 TestOtherContent(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
2351 // Jingle => Hybrid = Jingle (with audio content)
2352 TEST_F(SessionTest, JingleToHybridAudioContent) {
2353 TestAudioContent(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
2356 // Jingle => Hybrid = Jingle (with video contents)
2357 TEST_F(SessionTest, JingleToHybridVideoContents) {
2358 TestVideoContents(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE);
2361 // Hybrid => Gingle = Gingle (with other content)
2362 TEST_F(SessionTest, HybridToGingleOtherContent) {
2363 TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
2366 // Hybrid => Gingle = Gingle (with audio content)
2367 TEST_F(SessionTest, HybridToGingleAudioContent) {
2368 TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
2371 // Hybrid => Gingle = Gingle (with video contents)
2372 TEST_F(SessionTest, HybridToGingleVideoContents) {
2373 TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE);
2376 // Hybrid => Jingle = Jingle (with other content)
2377 TEST_F(SessionTest, HybridToJingleOtherContent) {
2378 TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
2381 // Hybrid => Jingle = Jingle (with audio content)
2382 TEST_F(SessionTest, HybridToJingleAudioContent) {
2383 TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
2386 // Hybrid => Jingle = Jingle (with video contents)
2387 TEST_F(SessionTest, HybridToJingleVideoContents) {
2388 TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE);
2391 TEST_F(SessionTest, GingleEarlyTerminationFromInitiator) {
2392 TestEarlyTerminationFromInitiator(PROTOCOL_GINGLE);
2395 TEST_F(SessionTest, JingleEarlyTerminationFromInitiator) {
2396 TestEarlyTerminationFromInitiator(PROTOCOL_JINGLE);
2399 TEST_F(SessionTest, HybridEarlyTerminationFromInitiator) {
2400 TestEarlyTerminationFromInitiator(PROTOCOL_HYBRID);
2403 TEST_F(SessionTest, GingleRejection) {
2404 TestRejection(PROTOCOL_GINGLE);
2407 TEST_F(SessionTest, JingleRejection) {
2408 TestRejection(PROTOCOL_JINGLE);
2411 TEST_F(SessionTest, GingleGoodRedirect) {
2412 TestGoodRedirect(PROTOCOL_GINGLE);
2415 TEST_F(SessionTest, JingleGoodRedirect) {
2416 TestGoodRedirect(PROTOCOL_JINGLE);
2419 TEST_F(SessionTest, GingleBadRedirect) {
2420 TestBadRedirect(PROTOCOL_GINGLE);
2423 TEST_F(SessionTest, JingleBadRedirect) {
2424 TestBadRedirect(PROTOCOL_JINGLE);
2427 TEST_F(SessionTest, TestCandidatesInInitiateAndAccept) {
2428 TestCandidatesInInitiateAndAccept("Candidates in initiate/accept");
2431 TEST_F(SessionTest, TestTransportMux) {
2435 TEST_F(SessionTest, TestSendDescriptionInfo) {
2436 TestSendDescriptionInfo();
2439 TEST_F(SessionTest, TestCallerSignalNewDescription) {
2440 TestCallerSignalNewDescription();
2443 TEST_F(SessionTest, TestCalleeSignalNewDescription) {
2444 TestCalleeSignalNewDescription();
2447 TEST_F(SessionTest, TestGetTransportStats) {
2448 TestGetTransportStats();