/indra/viewer_components/login/tests/lllogin_test.cpp
C++ | 498 lines | 337 code | 86 blank | 75 comment | 6 complexity | 34db368de3ecac6e40a44550d19e82b4 MD5 | raw file
Possible License(s): LGPL-2.1
- /**
- * @file lllogin_test.cpp
- * @author Mark Palange
- * @date 2009-02-26
- * @brief Tests of lllogin.cpp.
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2009-2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
- #if LL_WINDOWS
- #pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
- #endif
- // Precompiled header
- #include "linden_common.h"
- // associated header
- #include "../lllogin.h"
- // STL headers
- // std headers
- #include <iostream>
- // external library headers
- // other Linden headers
- #include "llsd.h"
- #include "../../../test/lltut.h"
- //#define DEBUG_ON
- #include "../../../test/debug.h"
- #include "llevents.h"
- #include "stringize.h"
- #if LL_WINDOWS
- #define skipwin(arg) skip(arg)
- #define skipmac(arg)
- #define skiplinux(arg)
- #elif LL_DARWIN
- #define skipwin(arg)
- #define skipmac(arg) skip(arg)
- #define skiplinux(arg)
- #elif LL_LINUX
- #define skipwin(arg)
- #define skipmac(arg)
- #define skiplinux(arg) skip(arg)
- #endif
- /*****************************************************************************
- * Helper classes
- *****************************************************************************/
- // This is a listener to receive results from lllogin.
- class LoginListener: public LLEventTrackable
- {
- std::string mName;
- LLSD mLastEvent;
- Debug mDebug;
- public:
- LoginListener(const std::string& name) :
- mName(name),
- mDebug(stringize(*this))
- {}
- bool call(const LLSD& event)
- {
- mDebug(STRINGIZE("LoginListener called!: " << event));
-
- mLastEvent = event;
- return false;
- }
- LLBoundListener listenTo(LLEventPump& pump)
- {
- return pump.listen(mName, boost::bind(&LoginListener::call, this, _1));
- }
- LLSD lastEvent() const { return mLastEvent; }
- friend std::ostream& operator<<(std::ostream& out, const LoginListener& listener)
- {
- return out << "LoginListener(" << listener.mName << ')';
- }
- };
- class LLAresListener: public LLEventTrackable
- {
- std::string mName;
- LLSD mEvent;
- bool mImmediateResponse;
- bool mMultipleURIResponse;
- Debug mDebug;
-
- public:
- LLAresListener(const std::string& name,
- bool i = false,
- bool m = false
- ) :
- mName(name),
- mImmediateResponse(i),
- mMultipleURIResponse(m),
- mDebug(stringize(*this))
- {}
- bool handle_event(const LLSD& event)
- {
- mDebug(STRINGIZE("LLAresListener called!: " << event));
- mEvent = event;
- if(mImmediateResponse)
- {
- sendReply();
- }
- return false;
- }
- void sendReply()
- {
- if(mEvent["op"].asString() == "rewriteURI")
- {
- LLSD result;
- if(mMultipleURIResponse)
- {
- result.append(LLSD("login.foo.com"));
- }
- result.append(mEvent["uri"]);
- LLEventPumps::instance().obtain(mEvent["reply"]).post(result);
- }
- }
- LLBoundListener listenTo(LLEventPump& pump)
- {
- return pump.listen(mName, boost::bind(&LLAresListener::handle_event, this, _1));
- }
- friend std::ostream& operator<<(std::ostream& out, const LLAresListener& listener)
- {
- return out << "LLAresListener(" << listener.mName << ')';
- }
- };
- class LLXMLRPCListener: public LLEventTrackable
- {
- std::string mName;
- LLSD mEvent;
- bool mImmediateResponse;
- LLSD mResponse;
- Debug mDebug;
- public:
- LLXMLRPCListener(const std::string& name,
- bool i = false,
- const LLSD& response = LLSD()
- ) :
- mName(name),
- mImmediateResponse(i),
- mResponse(response),
- mDebug(stringize(*this))
- {
- if(mResponse.isUndefined())
- {
- mResponse["status"] = "Complete"; // StatusComplete
- mResponse["errorcode"] = 0;
- mResponse["error"] = "dummy response";
- mResponse["transfer_rate"] = 0;
- mResponse["responses"]["login"] = true;
- }
- }
- void setResponse(const LLSD& r)
- {
- mResponse = r;
- }
- bool handle_event(const LLSD& event)
- {
- mDebug(STRINGIZE("LLXMLRPCListener called!: " << event));
- mEvent = event;
- if(mImmediateResponse)
- {
- sendReply();
- }
- return false;
- }
- void sendReply()
- {
- LLEventPumps::instance().obtain(mEvent["reply"]).post(mResponse);
- }
- LLBoundListener listenTo(LLEventPump& pump)
- {
- return pump.listen(mName, boost::bind(&LLXMLRPCListener::handle_event, this, _1));
- }
- friend std::ostream& operator<<(std::ostream& out, const LLXMLRPCListener& listener)
- {
- return out << "LLXMLRPCListener(" << listener.mName << ')';
- }
- };
- /*****************************************************************************
- * TUT
- *****************************************************************************/
- namespace tut
- {
- struct llviewerlogin_data
- {
- llviewerlogin_data() :
- pumps(LLEventPumps::instance())
- {}
- LLEventPumps& pumps;
- };
- typedef test_group<llviewerlogin_data> llviewerlogin_group;
- typedef llviewerlogin_group::object llviewerlogin_object;
- llviewerlogin_group llviewerlogingrp("LLViewerLogin");
- template<> template<>
- void llviewerlogin_object::test<1>()
- {
- DEBUG;
- // Testing login with immediate responses from Ares and XMLPRC
- // The response from both requests will come before the post request exits.
- // This tests an edge case of the login state handling.
- LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
- LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
- bool respond_immediately = true;
- // Have 'dummy ares' respond immediately.
- LLAresListener dummyLLAres("dummy_llares", respond_immediately);
- dummyLLAres.listenTo(llaresPump);
- // Have dummy XMLRPC respond immediately.
- LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc", respond_immediately);
- dummyXMLRPC.listenTo(xmlrpcPump);
- LLLogin login;
- LoginListener listener("test_ear");
- listener.listenTo(login.getEventPump());
- LLSD credentials;
- credentials["first"] = "foo";
- credentials["last"] = "bar";
- credentials["passwd"] = "secret";
- login.connect("login.bar.com", credentials);
- ensure_equals("Online state", listener.lastEvent()["state"].asString(), "online");
- }
- template<> template<>
- void llviewerlogin_object::test<2>()
- {
- DEBUG;
- // Tests a successful login in with delayed responses.
- // Also includes 'failure' that cause the login module
- // to re-attempt connection, once from a basic failure
- // and once from the 'indeterminate' response.
- set_test_name("LLLogin multiple srv uris w/ success");
- // Testing normal login procedure.
- LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
- LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
- bool respond_immediately = false;
- bool multiple_addresses = true;
- LLAresListener dummyLLAres("dummy_llares", respond_immediately, multiple_addresses);
- dummyLLAres.listenTo(llaresPump);
- LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
- dummyXMLRPC.listenTo(xmlrpcPump);
- LLLogin login;
- LoginListener listener("test_ear");
- listener.listenTo(login.getEventPump());
- LLSD credentials;
- credentials["first"] = "foo";
- credentials["last"] = "bar";
- credentials["passwd"] = "secret";
- login.connect("login.bar.com", credentials);
- ensure_equals("SRV state", listener.lastEvent()["change"].asString(), "srvrequest");
- dummyLLAres.sendReply();
- // Test Authenticating State prior to first response.
- ensure_equals("Auth state 1", listener.lastEvent()["change"].asString(), "authenticating");
- ensure_equals("Attempt 1", listener.lastEvent()["data"]["attempt"].asInteger(), 1);
- ensure_equals("URI 1", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.foo.com");
- // First send emulated LLXMLRPCListener failure,
- // this should return login to the authenticating step and increase the attempt
- // count.
- LLSD data;
- data["status"] = "OtherError";
- data["errorcode"] = 0;
- data["error"] = "dummy response";
- data["transfer_rate"] = 0;
- dummyXMLRPC.setResponse(data);
- dummyXMLRPC.sendReply();
- ensure_equals("Fail back to authenticate 1", listener.lastEvent()["change"].asString(), "authenticating");
- ensure_equals("Attempt 2", listener.lastEvent()["data"]["attempt"].asInteger(), 2);
- ensure_equals("URI 2", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.bar.com");
- // Now send the 'indeterminate' response.
- data.clear();
- data["status"] = "Complete"; // StatusComplete
- data["errorcode"] = 0;
- data["error"] = "dummy response";
- data["transfer_rate"] = 0;
- data["responses"]["login"] = "indeterminate";
- data["responses"]["next_url"] = "login.indeterminate.com";
- data["responses"]["next_method"] = "test_login_method";
- dummyXMLRPC.setResponse(data);
- dummyXMLRPC.sendReply();
- ensure_equals("Fail back to authenticate 2", listener.lastEvent()["change"].asString(), "authenticating");
- ensure_equals("Attempt 3", listener.lastEvent()["data"]["attempt"].asInteger(), 3);
- ensure_equals("URI 3", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.indeterminate.com");
- ensure_equals("Method 3", listener.lastEvent()["data"]["request"]["method"].asString(), "test_login_method");
- // Finally let the auth succeed.
- data.clear();
- data["status"] = "Complete"; // StatusComplete
- data["errorcode"] = 0;
- data["error"] = "dummy response";
- data["transfer_rate"] = 0;
- data["responses"]["login"] = "true";
- dummyXMLRPC.setResponse(data);
- dummyXMLRPC.sendReply();
- ensure_equals("Success state", listener.lastEvent()["state"].asString(), "online");
- login.disconnect();
- ensure_equals("Disconnected state", listener.lastEvent()["state"].asString(), "offline");
- }
- template<> template<>
- void llviewerlogin_object::test<3>()
- {
- DEBUG;
- // Test completed response, that fails to login.
- set_test_name("LLLogin valid response, failure (eg. bad credentials)");
- // Testing normal login procedure.
- LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
- LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
- LLAresListener dummyLLAres("dummy_llares");
- dummyLLAres.listenTo(llaresPump);
- LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
- dummyXMLRPC.listenTo(xmlrpcPump);
- LLLogin login;
- LoginListener listener("test_ear");
- listener.listenTo(login.getEventPump());
- LLSD credentials;
- credentials["first"] = "who";
- credentials["last"] = "what";
- credentials["passwd"] = "badpasswd";
- login.connect("login.bar.com", credentials);
- ensure_equals("SRV state", listener.lastEvent()["change"].asString(), "srvrequest");
- dummyLLAres.sendReply();
- ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating");
- // Send the failed auth request reponse
- LLSD data;
- data["status"] = "Complete";
- data["errorcode"] = 0;
- data["error"] = "dummy response";
- data["transfer_rate"] = 0;
- data["responses"]["login"] = "false";
- dummyXMLRPC.setResponse(data);
- dummyXMLRPC.sendReply();
- ensure_equals("Failed to offline", listener.lastEvent()["state"].asString(), "offline");
- }
- template<> template<>
- void llviewerlogin_object::test<4>()
- {
- DEBUG;
- // Test incomplete response, that end the attempt.
- set_test_name("LLLogin valid response, failure (eg. bad credentials)");
- // Testing normal login procedure.
- LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
- LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
- LLAresListener dummyLLAres("dummy_llares");
- dummyLLAres.listenTo(llaresPump);
- LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
- dummyXMLRPC.listenTo(xmlrpcPump);
- LLLogin login;
- LoginListener listener("test_ear");
- listener.listenTo(login.getEventPump());
- LLSD credentials;
- credentials["first"] = "these";
- credentials["last"] = "don't";
- credentials["passwd"] = "matter";
- login.connect("login.bar.com", credentials);
- ensure_equals("SRV state", listener.lastEvent()["change"].asString(), "srvrequest");
- dummyLLAres.sendReply();
- ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating");
- // Send the failed auth request reponse
- LLSD data;
- data["status"] = "OtherError";
- data["errorcode"] = 0;
- data["error"] = "dummy response";
- data["transfer_rate"] = 0;
- dummyXMLRPC.setResponse(data);
- dummyXMLRPC.sendReply();
- ensure_equals("Failed to offline", listener.lastEvent()["state"].asString(), "offline");
- }
- template<> template<>
- void llviewerlogin_object::test<5>()
- {
- DEBUG;
- // Test SRV request timeout.
- set_test_name("LLLogin SRV timeout testing");
- // Testing normal login procedure.
- LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
- LLAresListener dummyLLAres("dummy_llares");
- dummyLLAres.listenTo(llaresPump);
- LLLogin login;
- LoginListener listener("test_ear");
- listener.listenTo(login.getEventPump());
- LLSD credentials;
- credentials["first"] = "these";
- credentials["last"] = "don't";
- credentials["passwd"] = "matter";
- credentials["cfg_srv_timeout"] = 0.0f;
- login.connect("login.bar.com", credentials);
- ensure_equals("SRV State", listener.lastEvent()["change"].asString(), "srvrequest");
- // Get the mainloop eventpump, which needs a pinging in order to drive the
- // SRV timeout.
- LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
- LLSD frame_event;
- mainloop.post(frame_event);
- // In this state we have NOT sent a reply from LLAresListener -- in
- // fact there's no such object. Nonetheless, we expect the timeout to
- // have stepped the login module forward to try to authenticate with
- // the original URI.
- ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating");
- ensure_equals("Attempt", listener.lastEvent()["data"]["attempt"].asInteger(), 1);
- ensure_equals("URI", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.bar.com");
- // EXT-4193: if the SRV reply isn't lost but merely late, and if it
- // arrives just at the moment we're expecting the XMLRPC reply, the
- // original code got confused and crashed. Drive that case here. We
- // observe that without the fix, this call DOES repro.
- dummyLLAres.sendReply();
- }
- }