1 /* 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 28 #include <iostream> 29 #include <sstream> 30 #include <string> 31 #include "buzz/chatroommodule.h" 32 #include "buzz/constants.h" 33 #include "buzz/xmlelement.h" 34 #include "buzz/xmppengine.h" 35 #include "common/common.h" 36 #include "engine/util_unittest.h" 37 #include "test/unittest-inl.h" 38 #include "test/unittest.h" 39 40 #define TEST_OK(x) TEST_EQ((x),XMPP_RETURN_OK) 41 #define TEST_BADARGUMENT(x) TEST_EQ((x),XMPP_RETURN_BADARGUMENT) 42 43 namespace buzz { 44 45 class MultiUserChatModuleTest; 46 47 static void 48 WriteEnteredStatus(std::ostream& os, XmppChatroomEnteredStatus status) { 49 switch(status) { 50 case XMPP_CHATROOM_ENTERED_SUCCESS: 51 os<<"success"; 52 break; 53 case XMPP_CHATROOM_ENTERED_FAILURE_NICKNAME_CONFLICT: 54 os<<"failure(nickname conflict)"; 55 break; 56 case XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_REQUIRED: 57 os<<"failure(password required)"; 58 break; 59 case XMPP_CHATROOM_ENTERED_FAILURE_PASSWORD_INCORRECT: 60 os<<"failure(password incorrect)"; 61 break; 62 case XMPP_CHATROOM_ENTERED_FAILURE_NOT_A_MEMBER: 63 os<<"failure(not a member)"; 64 break; 65 case XMPP_CHATROOM_ENTERED_FAILURE_MEMBER_BANNED: 66 os<<"failure(member banned)"; 67 break; 68 case XMPP_CHATROOM_ENTERED_FAILURE_MAX_USERS: 69 os<<"failure(max users)"; 70 break; 71 case XMPP_CHATROOM_ENTERED_FAILURE_ROOM_LOCKED: 72 os<<"failure(room locked)"; 73 break; 74 case XMPP_CHATROOM_ENTERED_FAILURE_UNSPECIFIED: 75 os<<"failure(unspecified)"; 76 break; 77 default: 78 os<<"unknown"; 79 break; 80 } 81 } 82 83 static void 84 WriteExitedStatus(std::ostream& os, XmppChatroomExitedStatus status) { 85 switch (status) { 86 case XMPP_CHATROOM_EXITED_REQUESTED: 87 os<<"requested"; 88 break; 89 case XMPP_CHATROOM_EXITED_BANNED: 90 os<<"banned"; 91 break; 92 case XMPP_CHATROOM_EXITED_KICKED: 93 os<<"kicked"; 94 break; 95 case XMPP_CHATROOM_EXITED_NOT_A_MEMBER: 96 os<<"not member"; 97 break; 98 case XMPP_CHATROOM_EXITED_SYSTEM_SHUTDOWN: 99 os<<"system shutdown"; 100 break; 101 case XMPP_CHATROOM_EXITED_UNSPECIFIED: 102 os<<"unspecified"; 103 break; 104 default: 105 os<<"unknown"; 106 break; 107 } 108 } 109 110 //! This session handler saves all calls to a string. These are events and 111 //! data delivered form the engine to application code. 112 class XmppTestChatroomHandler : public XmppChatroomHandler { 113 public: 114 XmppTestChatroomHandler() {} 115 virtual ~XmppTestChatroomHandler() {} 116 117 void ChatroomEnteredStatus(XmppChatroomModule* room, 118 XmppChatroomEnteredStatus status) { 119 RTC_UNUSED(room); 120 ss_ <<"[ChatroomEnteredStatus status: "; 121 WriteEnteredStatus(ss_, status); 122 ss_ <<"]"; 123 } 124 125 126 void ChatroomExitedStatus(XmppChatroomModule* room, 127 XmppChatroomExitedStatus status) { 128 RTC_UNUSED(room); 129 ss_ <<"[ChatroomExitedStatus status: "; 130 WriteExitedStatus(ss_, status); 131 ss_ <<"]"; 132 } 133 134 void MemberEntered(XmppChatroomModule* room, 135 const XmppChatroomMember* entered_member) { 136 RTC_UNUSED(room); 137 ss_ << "[MemberEntered " << entered_member->member_jid().Str() << "]"; 138 } 139 140 void MemberExited(XmppChatroomModule* room, 141 const XmppChatroomMember* exited_member) { 142 RTC_UNUSED(room); 143 ss_ << "[MemberExited " << exited_member->member_jid().Str() << "]"; 144 } 145 146 void MemberChanged(XmppChatroomModule* room, 147 const XmppChatroomMember* changed_member) { 148 RTC_UNUSED(room); 149 ss_ << "[MemberChanged " << changed_member->member_jid().Str() << "]"; 150 } 151 152 virtual void MessageReceived(XmppChatroomModule* room, const XmlElement& message) { 153 RTC_UNUSED2(room, message); 154 } 155 156 157 std::string Str() { 158 return ss_.str(); 159 } 160 161 std::string StrClear() { 162 std::string result = ss_.str(); 163 ss_.str(""); 164 return result; 165 } 166 167 private: 168 std::stringstream ss_; 169 }; 170 171 //! This is the class that holds all of the unit test code for the 172 //! roster module 173 class XmppChatroomModuleTest : public UnitTest { 174 public: 175 XmppChatroomModuleTest() {} 176 177 void TestEnterExitChatroom() { 178 std::stringstream dump; 179 180 // Configure the engine 181 scoped_ptr<XmppEngine> engine(XmppEngine::Create()); 182 XmppTestHandler handler(engine.get()); 183 184 // Configure the module and handler 185 scoped_ptr<XmppChatroomModule> chatroom(XmppChatroomModule::Create()); 186 187 // Configure the module handler 188 chatroom->RegisterEngine(engine.get()); 189 190 // Set up callbacks 191 engine->SetOutputHandler(&handler); 192 engine->AddStanzaHandler(&handler); 193 engine->SetSessionHandler(&handler); 194 195 // Set up minimal login info 196 engine->SetUser(Jid("david@my-server")); 197 engine->SetPassword("david"); 198 199 // Do the whole login handshake 200 RunLogin(this, engine.get(), &handler); 201 TEST_EQ("", handler.OutputActivity()); 202 203 // Get the chatroom and set the handler 204 XmppTestChatroomHandler chatroom_handler; 205 chatroom->set_chatroom_handler(static_cast<XmppChatroomHandler*>(&chatroom_handler)); 206 207 // try to enter the chatroom 208 TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_NOT_IN_ROOM); 209 chatroom->set_nickname("thirdwitch"); 210 chatroom->set_chatroom_jid(Jid("darkcave@my-server")); 211 chatroom->RequestEnterChatroom("", XMPP_CONNECTION_STATUS_UNKNOWN, "en"); 212 TEST_EQ(chatroom_handler.StrClear(), ""); 213 TEST_EQ(handler.OutputActivity(), 214 "<presence to=\"darkcave@my-server/thirdwitch\">" 215 "<muc:x xmlns:muc=\"http://jabber.org/protocol/muc\"/>" 216 "</presence>"); 217 TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_REQUESTED_ENTER); 218 219 // simulate the server and test the client 220 std::string input; 221 input = "<presence from=\"darkcave@my-server/firstwitch\" to=\"david@my-server\">" 222 "<x xmlns=\"http://jabber.org/protocol/muc#user\">" 223 "<item affiliation=\"owner\" role=\"participant\"/>" 224 "</x>" 225 "</presence>"; 226 TEST_OK(engine->HandleInput(input.c_str(), input.length())); 227 TEST_EQ(chatroom_handler.StrClear(), ""); 228 TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_REQUESTED_ENTER); 229 230 input = "<presence from=\"darkcave@my-server/secondwitch\" to=\"david@my-server\">" 231 "<x xmlns=\"http://jabber.org/protocol/muc#user\">" 232 "<item affiliation=\"member\" role=\"participant\"/>" 233 "</x>" 234 "</presence>"; 235 TEST_OK(engine->HandleInput(input.c_str(), input.length())); 236 TEST_EQ(chatroom_handler.StrClear(), ""); 237 TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_REQUESTED_ENTER); 238 239 input = "<presence from=\"darkcave@my-server/thirdwitch\" to=\"david@my-server\">" 240 "<x xmlns=\"http://jabber.org/protocol/muc#user\">" 241 "<item affiliation=\"member\" role=\"participant\"/>" 242 "</x>" 243 "</presence>"; 244 TEST_OK(engine->HandleInput(input.c_str(), input.length())); 245 TEST_EQ(chatroom_handler.StrClear(), 246 "[ChatroomEnteredStatus status: success]"); 247 TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_IN_ROOM); 248 249 // simulate somebody else entering the room after we entered 250 input = "<presence from=\"darkcave@my-server/fourthwitch\" to=\"david@my-server\">" 251 "<x xmlns=\"http://jabber.org/protocol/muc#user\">" 252 "<item affiliation=\"member\" role=\"participant\"/>" 253 "</x>" 254 "</presence>"; 255 TEST_OK(engine->HandleInput(input.c_str(), input.length())); 256 TEST_EQ(chatroom_handler.StrClear(), "[MemberEntered darkcave@my-server/fourthwitch]"); 257 TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_IN_ROOM); 258 259 // simulate somebody else leaving the room after we entered 260 input = "<presence from=\"darkcave@my-server/secondwitch\" to=\"david@my-server\" type=\"unavailable\">" 261 "<x xmlns=\"http://jabber.org/protocol/muc#user\">" 262 "<item affiliation=\"member\" role=\"participant\"/>" 263 "</x>" 264 "</presence>"; 265 TEST_OK(engine->HandleInput(input.c_str(), input.length())); 266 TEST_EQ(chatroom_handler.StrClear(), "[MemberExited darkcave@my-server/secondwitch]"); 267 TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_IN_ROOM); 268 269 // try to leave the room 270 chatroom->RequestExitChatroom(); 271 TEST_EQ(chatroom_handler.StrClear(), ""); 272 TEST_EQ(handler.OutputActivity(), 273 "<presence to=\"darkcave@my-server/thirdwitch\" type=\"unavailable\"/>"); 274 TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_REQUESTED_EXIT); 275 276 // simulate the server and test the client 277 input = "<presence from=\"darkcave@my-server/thirdwitch\" to=\"david@my-server\" type=\"unavailable\">" 278 "<x xmlns=\"http://jabber.org/protocol/muc#user\">" 279 "<item affiliation=\"member\" role=\"participant\"/>" 280 "</x>" 281 "</presence>"; 282 TEST_OK(engine->HandleInput(input.c_str(), input.length())); 283 TEST_EQ(chatroom_handler.StrClear(), 284 "[ChatroomExitedStatus status: requested]"); 285 TEST_EQ(chatroom->state(), XMPP_CHATROOM_STATE_NOT_IN_ROOM); 286 } 287 288 }; 289 290 // A global function that creates the test suite for this set of tests. 291 TestBase* ChatroomModuleTest_Create() { 292 TestSuite* suite = new TestSuite("ChatroomModuleTest"); 293 ADD_TEST(suite, XmppChatroomModuleTest, TestEnterExitChatroom); 294 return suite; 295 } 296 297 } 298