From 9538328d5f7cf0f0be5dd77b8e27032e09104fff Mon Sep 17 00:00:00 2001 From: "Mark Palange (Mani)" Date: Fri, 24 Jul 2009 15:08:16 -0700 Subject: Adding LLLoginInstance unit test. - Added LLNotificationsInterface class. - Removed LLLoginInstance use of LLNotifications EventAPI --- indra/newview/lllogininstance.cpp | 15 +- indra/newview/lllogininstance.h | 7 +- indra/newview/llstartup.cpp | 3 +- indra/newview/tests/lllogininstance_test.cpp | 413 +++++++++++++++++++++++++++ 4 files changed, 430 insertions(+), 8 deletions(-) create mode 100644 indra/newview/tests/lllogininstance_test.cpp (limited to 'indra/newview') diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index bf42129fc1..c08cc2baae 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -59,6 +59,7 @@ std::string construct_start_string(); LLLoginInstance::LLLoginInstance() : mLoginModule(new LLLogin()), + mNotifications(NULL), mLoginState("offline"), mUserInteraction(true), mSkipOptionalUpdate(false), @@ -345,10 +346,13 @@ void LLLoginInstance::updateApp(bool mandatory, const std::string& auth_msg) #endif } - // *NOTE:Mani - for reference -// LLNotifications::instance().add(notification_name, args, payload, -// boost::bind(&LLLoginInstance::updateDialogCallback, this, _1, _2)); + if(mNotifications) + { + mNotifications->add(notification_name, args, payload, + boost::bind(&LLLoginInstance::updateDialogCallback, this, _1, _2)); + } + /* *NOTE:Mani Experiment with Event API interface. if(!mUpdateAppResponse) { bool make_unique = true; @@ -368,12 +372,11 @@ void LLLoginInstance::updateApp(bool mandatory, const std::string& auth_msg) event["reply"] = mUpdateAppResponse->getName(); LLEventPumps::getInstance()->obtain("LLNotifications").post(event); + */ } -bool LLLoginInstance::updateDialogCallback(const LLSD& event) +bool LLLoginInstance::updateDialogCallback(const LLSD& notification, const LLSD& response) { - LLSD notification = event["notification"]; - LLSD response = event["response"]; S32 option = LLNotification::getSelectedOption(notification, response); std::string update_exe_path; bool mandatory = notification["payload"]["mandatory"].asBoolean(); diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h index afe96acd1e..47d52a6184 100644 --- a/indra/newview/lllogininstance.h +++ b/indra/newview/lllogininstance.h @@ -37,6 +37,7 @@ #include class LLLogin; class LLEventStream; +class LLNotificationsInterface; // This class hosts the login module and is used to // negotiate user authentication attempts. @@ -73,13 +74,15 @@ public: void setSerialNumber(const std::string& sn) { mSerialNumber = sn; } void setLastExecEvent(int lee) { mLastExecEvent = lee; } + void setNotificationsInterface(LLNotificationsInterface* ni) { mNotifications = ni; } + typedef boost::function UpdaterLauncherCallback; void setUpdaterLauncher(const UpdaterLauncherCallback& ulc) { mUpdaterLauncher = ulc; } private: void constructAuthParams(const LLSD& credentials); void updateApp(bool mandatory, const std::string& message); - bool updateDialogCallback(const LLSD& event); + bool updateDialogCallback(const LLSD& notification, const LLSD& response); bool handleLoginEvent(const LLSD& event); bool handleLoginFailure(const LLSD& event); @@ -90,6 +93,8 @@ private: void attemptComplete() { mAttemptComplete = true; } // In the future an event? boost::scoped_ptr mLoginModule; + LLNotificationsInterface* mNotifications; + std::string mLoginState; LLSD mRequestData; LLSD mResponseData; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index dac6f8423a..eb585f8fe3 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -966,6 +966,7 @@ bool idle_startup() // Setting initial values... LLLoginInstance* login = LLLoginInstance::getInstance(); + login->setNotificationsInterface(LLNotifications::getInstance()); if(gNoRender) { // HACK, skip optional updates if you're running drones @@ -975,7 +976,7 @@ bool idle_startup() login->setUserInteraction(show_connect_box); login->setSerialNumber(LLAppViewer::instance()->getSerialNumber()); login->setLastExecEvent(gLastExecEvent); - login->setUpdaterLauncher(boost::bind(LLAppViewer::launchUpdater, LLAppViewer::instance())); + login->setUpdaterLauncher(boost::bind(&LLAppViewer::launchUpdater, LLAppViewer::instance())); // This call to LLLoginInstance::connect() starts the // authentication process. diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp new file mode 100644 index 0000000000..19cf9cd961 --- /dev/null +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -0,0 +1,413 @@ +/** + * @file lllogininstance_test.cpp + * @brief Test for lllogininstance.cpp. + * + * $LicenseInfo:firstyear=2008&license=internal$ + * Copyright (c) 2008, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "../llviewerprecompiledheaders.h" +// Own header +#include "../lllogininstance.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "../test/lltut.h" +#include "llevents.h" + +#if defined(LL_WINDOWS) +#pragma warning(disable: 4355) // using 'this' in base-class ctor initializer expr +#endif + +// Constants +const std::string VIEWERLOGIN_URI("viewerlogin_uri"); +const std::string VIEWERLOGIN_GRIDLABEL("viewerlogin_grid"); + +const std::string APPVIEWER_SERIALNUMBER("appviewer_serialno"); + +// Link seams. + +//----------------------------------------------------------------------------- +static LLEventStream gTestPump("test_pump"); + +#include "lllogin.h" +static std::string gLoginURI; +static LLSD gLoginCreds; +static bool gDisconnectCalled = false; +class LLLogin::Impl +{ +}; +LLLogin::LLLogin() {} +LLLogin::~LLLogin() {} +LLEventPump& LLLogin::getEventPump() { return gTestPump; } +void LLLogin::connect(const std::string& uri, const LLSD& credentials) +{ + gLoginURI = uri; + gLoginCreds = credentials; +} + +void LLLogin::disconnect() +{ + gDisconnectCalled = true; +} + +//----------------------------------------------------------------------------- +#include "../llviewernetwork.h" +unsigned char gMACAddress[MAC_ADDRESS_BYTES] = {'1','2','3','4','5','6'}; /* Flawfinder: ignore */ + +LLViewerLogin::LLViewerLogin() {} +LLViewerLogin::~LLViewerLogin() {} +void LLViewerLogin::getLoginURIs(std::vector& uris) const +{ + uris.push_back(VIEWERLOGIN_URI); +} +std::string LLViewerLogin::getGridLabel() const { return VIEWERLOGIN_GRIDLABEL; } + +//----------------------------------------------------------------------------- +#include "../llviewercontrol.h" +LLControlGroup gSavedSettings("Global"); +LLControlGroup gSavedSkinSettings("Skinning"); +std::string gCurrentVersion = "invalid_version"; + +LLControlGroup::LLControlGroup(const std::string& name) : + LLInstanceTracker(name){} +LLControlGroup::~LLControlGroup() {} +void LLControlGroup::setBOOL(const std::string& name, BOOL val) {} +BOOL LLControlGroup::getBOOL(const std::string& name) { return FALSE; } +U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only) { return 1; } +void LLControlGroup::setString(const std::string& name, const std::string& val) {} +std::string LLControlGroup::getString(const std::string& name) { return "test_string"; } +BOOL LLControlGroup::declareBOOL(const std::string& name, BOOL initial_val, const std::string& comment, BOOL persist) { return TRUE; } +BOOL LLControlGroup::declareString(const std::string& name, const std::string &initial_val, const std::string& comment, BOOL persist) { return TRUE; } + +//----------------------------------------------------------------------------- +#include "../llurlsimstring.h" +LLURLSimString LLURLSimString::sInstance; +bool LLURLSimString::parse() { return true; } + +//----------------------------------------------------------------------------- +#include "../llfloatertos.h" +static LLFloaterTOS::ETOSType gTOSType; +static LLFloaterTOS::YesNoCallback gTOSCallback; +LLFloaterTOS* LLFloaterTOS::show(LLFloaterTOS::ETOSType type, + const std::string & message, + const YesNoCallback& callback) +{ + gTOSType = type; + gTOSCallback = callback; + return NULL; +} + +//----------------------------------------------------------------------------- +// LLNotifications +class MockNotifications : public LLNotificationsInterface +{ + boost::function mResponder; + int mAddedCount; + +public: + MockNotifications() : + mResponder(0), + mAddedCount(0) + { + } + + virtual ~MockNotifications() {} + + /* virtual */ LLNotificationPtr add( + const std::string& name, + const LLSD& substitutions, + const LLSD& payload, + LLNotificationFunctorRegistry::ResponseFunctor functor) + { + mResponder = functor; + mAddedCount++; + return LLNotificationPtr((LLNotification*)NULL); + } + + void sendYesResponse() + { + LLSD notification; + LLSD response; + response = 1; + mResponder(notification, response); + } + + void sendNoResponse() + { + LLSD notification; + LLSD response; + response = 2; + mResponder(notification, response); + } + + void sendBogusResponse() + { + LLSD notification; + LLSD response; + response = 666; + mResponder(notification, response); + } + + int addedCount() { return mAddedCount; } +}; + +S32 LLNotification::getSelectedOption(const LLSD& notification, const LLSD& response) +{ + return response.asInteger(); +} + +// misc +std::string xml_escape_string(const std::string& in) +{ + return in; +} + +/***************************************************************************** +* TUT +*****************************************************************************/ +namespace tut +{ + struct lllogininstance_data + { + lllogininstance_data() : logininstance(LLLoginInstance::getInstance()) + { + // Global initialization + gLoginURI.clear(); + gLoginCreds.clear(); + gDisconnectCalled = false; + + // gTOSType = -1; // Set to invalid value. + gTOSCallback = 0; // clear the callback. + + + gSavedSettings.declareBOOL("NoInventoryLibrary", FALSE, "", FALSE); + gSavedSettings.declareBOOL("ConnectAsGod", FALSE, "", FALSE); + gSavedSettings.declareBOOL("UseDebugMenus", FALSE, "", FALSE); + gSavedSettings.declareBOOL("ForceMandatoryUpdate", FALSE, "", FALSE); + gSavedSettings.declareString("ClientSettingsFile", "test_settings.xml", "", FALSE); + gSavedSettings.declareString("VersionChannelName", "test_version_string", "", FALSE); + gSavedSettings.declareString("NextLoginLocation", "", "", FALSE); + gSavedSettings.declareBOOL("LoginLastLocation", FALSE, "", FALSE); + + credentials["first"] = "testfirst"; + credentials["last"] = "testlast"; + credentials["passwd"] = "testpass"; + + logininstance->setNotificationsInterface(¬ifications); + } + + LLLoginInstance* logininstance; + LLSD credentials; + MockNotifications notifications; + }; + + typedef test_group lllogininstance_group; + typedef lllogininstance_group::object lllogininstance_object; + lllogininstance_group llsdmgr("lllogininstance"); + + template<> template<> + void lllogininstance_object::test<1>() + { + set_test_name("Test Simple Success And Disconnect"); + + // Test default connect. + logininstance->connect(credentials); + + ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); + + // Dummy success response. + LLSD response; + response["state"] = "online"; + response["progress"] = 1.0; + response["transfer_rate"] = 7; + response["data"] = "test_data"; + + gTestPump.post(response); + + ensure("Success response", logininstance->authSuccess()); + ensure_equals("Test Response Data", logininstance->getResponse().asString(), "test_data"); + + logininstance->disconnect(); + + ensure_equals("Called Login Module Disconnect", gDisconnectCalled, true); + + response.clear(); + response["state"] = "offline"; + response["progress"] = 0.0; + response["transfer_rate"] = 0; + response["data"] = "test_data"; + + gTestPump.post(response); + + ensure("Disconnected", !(logininstance->authSuccess())); + } + + template<> template<> + void lllogininstance_object::test<2>() + { + set_test_name("Test User TOS/Critical message Interaction"); + + const std::string test_uri = "testing-uri"; + + // Test default connect. + logininstance->connect(test_uri, credentials); + + // connect should call LLLogin::connect to init gLoginURI and gLoginCreds. + ensure_equals("Default connect uri", gLoginURI, "testing-uri"); + ensure_equals("Default for agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), false); + ensure_equals("Default for read critical", gLoginCreds["params"]["read_critical"].asBoolean(), false); + + // TOS failure response. + LLSD response; + response["state"] = "offline"; + response["progress"] = 0.0; + response["transfer_rate"] = 7; + response["data"]["reason"] = "tos"; + gTestPump.post(response); + + ensure_equals("TOS Dialog type", gTOSType, LLFloaterTOS::TOS_TOS); + ensure("TOS callback given", gTOSCallback != 0); + gTOSCallback(false); // Call callback denying TOS. + ensure("No TOS, failed auth", logininstance->authFailure()); + + // Start again. + logininstance->connect(test_uri, credentials); + gTestPump.post(response); // Fail for tos again. + gTOSCallback(true); // Accept tos, should reconnect w/ agree_to_tos. + ensure_equals("Accepted agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), true); + ensure("Incomplete login status", !logininstance->authFailure() && !logininstance->authSuccess()); + + // Fail connection, attempt connect again. + // The new request should have reset agree to tos to default. + response["data"]["reason"] = "key"; // bad creds. + gTestPump.post(response); + ensure("TOS auth failure", logininstance->authFailure()); + + logininstance->connect(test_uri, credentials); + ensure_equals("Reset to default for agree to tos", gLoginCreds["params"]["agree_to_tos"].asBoolean(), false); + + // Critical Message failure response. + logininstance->connect(test_uri, credentials); + response["data"]["reason"] = "critical"; // Change response to "critical message" + gTestPump.post(response); + + ensure_equals("TOS Dialog type", gTOSType, LLFloaterTOS::TOS_CRITICAL_MESSAGE); + ensure("TOS callback given", gTOSCallback != 0); + gTOSCallback(true); + ensure_equals("Accepted read critical message", gLoginCreds["params"]["read_critical"].asBoolean(), true); + ensure("Incomplete login status", !logininstance->authFailure() && !logininstance->authSuccess()); + + // Fail then attempt new connection + response["data"]["reason"] = "key"; // bad creds. + gTestPump.post(response); + ensure("TOS auth failure", logininstance->authFailure()); + logininstance->connect(test_uri, credentials); + ensure_equals("Default for agree to tos", gLoginCreds["params"]["read_critical"].asBoolean(), false); + } + + template<> template<> + void lllogininstance_object::test<3>() + { + set_test_name("Test Mandatory Update User Accepts"); + + // Part 1 - Mandatory Update, with User accepts response. + // Test connect with update needed. + logininstance->connect(credentials); + + ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); + + // Update needed failure response. + LLSD response; + response["state"] = "offline"; + response["progress"] = 0.0; + response["transfer_rate"] = 7; + response["data"]["reason"] = "update"; + gTestPump.post(response); + + ensure_equals("Notification added", notifications.addedCount(), 1); + + notifications.sendYesResponse(); + + ensure("Disconnected", !(logininstance->authSuccess())); + } + + template<> template<> + void lllogininstance_object::test<4>() + { + set_test_name("Test Mandatory Update User Decline"); + + // Test connect with update needed. + logininstance->connect(credentials); + + ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); + + // Update needed failure response. + LLSD response; + response["state"] = "offline"; + response["progress"] = 0.0; + response["transfer_rate"] = 7; + response["data"]["reason"] = "update"; + gTestPump.post(response); + + ensure_equals("Notification added", notifications.addedCount(), 1); + notifications.sendNoResponse(); + + ensure("Disconnected", !(logininstance->authSuccess())); + } + + template<> template<> + void lllogininstance_object::test<6>() + { + set_test_name("Test Optional Update User Accept"); + + // Part 3 - Mandatory Update, with bogus response. + // Test connect with update needed. + logininstance->connect(credentials); + + ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); + + // Update needed failure response. + LLSD response; + response["state"] = "offline"; + response["progress"] = 0.0; + response["transfer_rate"] = 7; + response["data"]["reason"] = "optional"; + gTestPump.post(response); + + ensure_equals("Notification added", notifications.addedCount(), 1); + notifications.sendYesResponse(); + + ensure("Disconnected", !(logininstance->authSuccess())); + } + + template<> template<> + void lllogininstance_object::test<7>() + { + set_test_name("Test Optional Update User Denies"); + + // Part 3 - Mandatory Update, with bogus response. + // Test connect with update needed. + logininstance->connect(credentials); + + ensure_equals("Default connect uri", gLoginURI, VIEWERLOGIN_URI); + + // Update needed failure response. + LLSD response; + response["state"] = "offline"; + response["progress"] = 0.0; + response["transfer_rate"] = 7; + response["data"]["reason"] = "optional"; + gTestPump.post(response); + + ensure_equals("Notification added", notifications.addedCount(), 1); + notifications.sendNoResponse(); + + // User skips, should be reconnecting. + ensure_equals("reconnect uri", gLoginURI, VIEWERLOGIN_URI); + ensure_equals("skipping optional update", gLoginCreds["params"]["skipoptional"].asBoolean(), true); + } +} -- cgit v1.2.3