summaryrefslogtreecommitdiff
path: root/indra/newview/tests
diff options
context:
space:
mode:
authorpalange <palange@lindenlab.com>2009-10-12 19:03:52 -0400
committerpalange <palange@lindenlab.com>2009-10-12 19:03:52 -0400
commitdbe7135cc4694e906a7d95a935df70f20514c962 (patch)
tree227ed3c9bc717171aeb009067e0f07335bcee8c3 /indra/newview/tests
parentd4b2897700c66354413af42ab055bd1aaa47f91c (diff)
parente3a4e3dc10a96b0822674cea262f41774e55a660 (diff)
merge of login-api
Diffstat (limited to 'indra/newview/tests')
-rw-r--r--indra/newview/tests/llagentaccess_test.cpp2
-rw-r--r--indra/newview/tests/llcapabilitylistener_test.cpp36
-rw-r--r--indra/newview/tests/lldateutil_test.cpp3
-rw-r--r--indra/newview/tests/lllogininstance_test.cpp423
-rw-r--r--indra/newview/tests/llmediadataclient_test.cpp4
-rw-r--r--indra/newview/tests/llviewerhelputil_test.cpp3
-rw-r--r--indra/newview/tests/llxmlrpclistener_test.cpp230
-rw-r--r--indra/newview/tests/test_llxmlrpc_peer.py59
8 files changed, 730 insertions, 30 deletions
diff --git a/indra/newview/tests/llagentaccess_test.cpp b/indra/newview/tests/llagentaccess_test.cpp
index 42872d85fb..e08193f785 100644
--- a/indra/newview/tests/llagentaccess_test.cpp
+++ b/indra/newview/tests/llagentaccess_test.cpp
@@ -29,6 +29,8 @@
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
+
+#include "linden_common.h"
#include "../test/lltut.h"
#include "../llagentaccess.h"
diff --git a/indra/newview/tests/llcapabilitylistener_test.cpp b/indra/newview/tests/llcapabilitylistener_test.cpp
index f66ae9404f..b965379c9c 100644
--- a/indra/newview/tests/llcapabilitylistener_test.cpp
+++ b/indra/newview/tests/llcapabilitylistener_test.cpp
@@ -24,9 +24,9 @@
#include "../test/lltut.h"
#include "../llcapabilityprovider.h"
#include "lluuid.h"
-#include "llerrorcontrol.h"
#include "tests/networkio.h"
#include "tests/commtest.h"
+#include "tests/wrapllerrs.h"
#include "stringize.h"
#if defined(LL_WINDOWS)
@@ -104,28 +104,6 @@ namespace tut
typedef llcapears_group::object llcapears_object;
llcapears_group llsdmgr("llcapabilitylistener");
- struct CaptureError: public LLError::OverrideFatalFunction
- {
- CaptureError():
- LLError::OverrideFatalFunction(boost::bind(&CaptureError::operator(), this, _1))
- {
- LLError::setPrintLocation(false);
- }
-
- struct FatalException: public std::runtime_error
- {
- FatalException(const std::string& what): std::runtime_error(what) {}
- };
-
- void operator()(const std::string& message)
- {
- error = message;
- throw FatalException(message);
- }
-
- std::string error;
- };
-
template<> template<>
void llcapears_object::test<1>()
{
@@ -137,10 +115,10 @@ namespace tut
std::string threw;
try
{
- CaptureError capture;
+ WrapLL_ERRS capture;
regionPump.post(request);
}
- catch (const CaptureError::FatalException& e)
+ catch (const WrapLL_ERRS::FatalException& e)
{
threw = e.what();
}
@@ -184,10 +162,10 @@ namespace tut
std::string threw;
try
{
- CaptureError capture;
+ WrapLL_ERRS capture;
regionPump.post(request);
}
- catch (const CaptureError::FatalException& e)
+ catch (const WrapLL_ERRS::FatalException& e)
{
threw = e.what();
}
@@ -246,10 +224,10 @@ namespace tut
std::string threw;
try
{
- CaptureError capture;
+ WrapLL_ERRS capture;
regionPump.post(request);
}
- catch (const CaptureError::FatalException& e)
+ catch (const WrapLL_ERRS::FatalException& e)
{
threw = e.what();
}
diff --git a/indra/newview/tests/lldateutil_test.cpp b/indra/newview/tests/lldateutil_test.cpp
index 30e39a3bcf..ed753b6ff7 100644
--- a/indra/newview/tests/lldateutil_test.cpp
+++ b/indra/newview/tests/lldateutil_test.cpp
@@ -28,6 +28,9 @@
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
+
+#include "linden_common.h"
+
#include "../test/lltut.h"
#include "../lldateutil.h"
diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp
new file mode 100644
index 0000000000..009be35f64
--- /dev/null
+++ b/indra/newview/tests/lllogininstance_test.cpp
@@ -0,0 +1,423 @@
+/**
+ * @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<std::string>& uris) const
+{
+ uris.push_back(VIEWERLOGIN_URI);
+}
+std::string LLViewerLogin::getGridLabel() const { return VIEWERLOGIN_GRIDLABEL; }
+
+//-----------------------------------------------------------------------------
+#include "../llviewercontrol.h"
+LLControlGroup gSavedSettings("Global");
+std::string gCurrentVersion = "invalid_version";
+
+LLControlGroup::LLControlGroup(const std::string& name) :
+ LLInstanceTracker<LLControlGroup, std::string>(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 "lluicolortable.h"
+void LLUIColorTable::saveUserSettings(void)const {}
+
+//-----------------------------------------------------------------------------
+#include "../llurlsimstring.h"
+LLURLSimString LLURLSimString::sInstance;
+bool LLURLSimString::parse() { return true; }
+
+//-----------------------------------------------------------------------------
+#include "llnotifications.h"
+#include "llfloaterreg.h"
+static std::string gTOSType;
+static LLEventPump * gTOSReplyPump = NULL;
+
+//static
+LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus)
+{
+ gTOSType = name;
+ gTOSReplyPump = &LLEventPumps::instance().obtain(key["reply_pump"]);
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// LLNotifications
+class MockNotifications : public LLNotificationsInterface
+{
+ boost::function<void (const LLSD&, const LLSD&)> 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 = ""; // Set to invalid value.
+ gTOSReplyPump = 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(&notifications);
+ }
+
+ LLLoginInstance* logininstance;
+ LLSD credentials;
+ MockNotifications notifications;
+ };
+
+ typedef test_group<lllogininstance_data> 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["change"] = "connect";
+ 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["change"] = "disconnect";
+ 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["change"] = "fail.login";
+ response["progress"] = 0.0;
+ response["transfer_rate"] = 7;
+ response["data"]["reason"] = "tos";
+ gTestPump.post(response);
+
+ ensure_equals("TOS Dialog type", gTOSType, "message_tos");
+ ensure("TOS callback given", gTOSReplyPump != 0);
+ gTOSReplyPump->post(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.
+ gTOSReplyPump->post(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, "message_critical");
+ ensure("TOS callback given", gTOSReplyPump != 0);
+ gTOSReplyPump->post(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["change"] = "fail.login";
+ 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["change"] = "fail.login";
+ 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["change"] = "fail.login";
+ 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["change"] = "fail.login";
+ 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);
+ }
+}
diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp
index 135c5ab501..a884ed0265 100644
--- a/indra/newview/tests/llmediadataclient_test.cpp
+++ b/indra/newview/tests/llmediadataclient_test.cpp
@@ -29,11 +29,13 @@
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
-
+#include "../llviewerprecompiledheaders.h"
+
#include <iostream>
#include "../test/lltut.h"
#include "llsdserialize.h"
+#include "llsdutil.h"
#include "llerrorcontrol.h"
#include "llhttpstatuscodes.h"
diff --git a/indra/newview/tests/llviewerhelputil_test.cpp b/indra/newview/tests/llviewerhelputil_test.cpp
index 40f7d532bc..988d28c301 100644
--- a/indra/newview/tests/llviewerhelputil_test.cpp
+++ b/indra/newview/tests/llviewerhelputil_test.cpp
@@ -30,6 +30,9 @@
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
+// Precompiled header
+#include "../llviewerprecompiledheaders.h"
+
#include "../test/lltut.h"
#include "../llviewerhelputil.h"
diff --git a/indra/newview/tests/llxmlrpclistener_test.cpp b/indra/newview/tests/llxmlrpclistener_test.cpp
new file mode 100644
index 0000000000..c94ba0a3e8
--- /dev/null
+++ b/indra/newview/tests/llxmlrpclistener_test.cpp
@@ -0,0 +1,230 @@
+/*
+ * @file llxmlrpclistener_test.cpp
+ * @author Nat Goodspeed
+ * @date 2009-03-20
+ * @brief Test for llxmlrpclistener.
+ *
+ * $LicenseInfo:firstyear=2009&license=internal$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "../llviewerprecompiledheaders.h"
+// associated header
+#include "../llxmlrpclistener.h"
+// STL headers
+#include <iomanip>
+// std headers
+// external library headers
+// other Linden headers
+#include "../test/lltut.h"
+#include "../llxmlrpctransaction.h"
+#include "llevents.h"
+#include "lleventfilter.h"
+#include "llsd.h"
+#include "llcontrol.h"
+#include "tests/wrapllerrs.h"
+
+LLControlGroup gSavedSettings("Global");
+
+/*****************************************************************************
+* TUT
+*****************************************************************************/
+namespace tut
+{
+ struct data
+ {
+ data():
+ pumps(LLEventPumps::instance()),
+ uri("http://127.0.0.1:8000")
+ {
+ // These variables are required by machinery used by
+ // LLXMLRPCTransaction. The values reflect reality for this test
+ // executable; hopefully these values are correct.
+ gSavedSettings.declareBOOL("BrowserProxyEnabled", FALSE, "", FALSE); // don't persist
+ gSavedSettings.declareBOOL("NoVerifySSLCert", TRUE, "", FALSE); // don't persist
+ }
+
+ // LLEventPump listener signature
+ bool captureReply(const LLSD& r)
+ {
+ reply = r;
+ return false;
+ }
+
+ LLSD reply;
+ LLEventPumps& pumps;
+ std::string uri;
+ };
+ typedef test_group<data> llxmlrpclistener_group;
+ typedef llxmlrpclistener_group::object object;
+ llxmlrpclistener_group llxmlrpclistenergrp("llxmlrpclistener");
+
+ template<> template<>
+ void object::test<1>()
+ {
+ set_test_name("request validation");
+ WrapLL_ERRS capture;
+ LLSD request;
+ request["uri"] = uri;
+ std::string threw;
+ try
+ {
+ pumps.obtain("LLXMLRPCTransaction").post(request);
+ }
+ catch (const WrapLL_ERRS::FatalException& e)
+ {
+ threw = e.what();
+ }
+ ensure_contains("threw exception", threw, "missing params");
+ ensure_contains("identified missing", threw, "method");
+ ensure_contains("identified missing", threw, "reply");
+ }
+
+ template<> template<>
+ void object::test<2>()
+ {
+ set_test_name("param types validation");
+ WrapLL_ERRS capture;
+ LLSD request;
+ request["uri"] = uri;
+ request["method"] = "hello";
+ request["reply"] = "reply";
+ LLSD& params(request["params"]);
+ params["who"]["specifically"] = "world"; // LLXMLRPCListener only handles scalar params
+ std::string threw;
+ try
+ {
+ pumps.obtain("LLXMLRPCTransaction").post(request);
+ }
+ catch (const WrapLL_ERRS::FatalException& e)
+ {
+ threw = e.what();
+ }
+ ensure_contains("threw exception", threw, "unknown type");
+ }
+
+ template<> template<>
+ void object::test<3>()
+ {
+ set_test_name("success case");
+ LLSD request;
+ request["uri"] = uri;
+ request["method"] = "hello";
+ request["reply"] = "reply";
+ LLSD& params(request["params"]);
+ params["who"] = "world";
+ // Set up a timeout filter so we don't spin forever waiting.
+ LLEventTimeout watchdog;
+ // Connect the timeout filter to the reply pump.
+ LLTempBoundListener temp(
+ pumps.obtain("reply").
+ listen("watchdog", boost::bind(&LLEventTimeout::post, boost::ref(watchdog), _1)));
+ // Now connect our target listener to the timeout filter.
+ watchdog.listen("captureReply", boost::bind(&data::captureReply, this, _1));
+ // Kick off the request...
+ reply.clear();
+ pumps.obtain("LLXMLRPCTransaction").post(request);
+ // Set the timer
+ F32 timeout(10);
+ watchdog.eventAfter(timeout, LLSD().insert("timeout", 0));
+ // and pump "mainloop" until we get something, whether from
+ // LLXMLRPCListener or from the watchdog filter.
+ LLTimer timer;
+ F32 start = timer.getElapsedTimeF32();
+ LLEventPump& mainloop(pumps.obtain("mainloop"));
+ while (reply.isUndefined())
+ {
+ mainloop.post(LLSD());
+ }
+ ensure("timeout works", (timer.getElapsedTimeF32() - start) < (timeout + 1));
+ ensure_equals(reply["responses"]["hi_there"].asString(), "Hello, world!");
+ }
+
+ template<> template<>
+ void object::test<4>()
+ {
+ set_test_name("bogus method");
+ LLSD request;
+ request["uri"] = uri;
+ request["method"] = "goodbye";
+ request["reply"] = "reply";
+ LLSD& params(request["params"]);
+ params["who"] = "world";
+ // Set up a timeout filter so we don't spin forever waiting.
+ LLEventTimeout watchdog;
+ // Connect the timeout filter to the reply pump.
+ LLTempBoundListener temp(
+ pumps.obtain("reply").
+ listen("watchdog", boost::bind(&LLEventTimeout::post, boost::ref(watchdog), _1)));
+ // Now connect our target listener to the timeout filter.
+ watchdog.listen("captureReply", boost::bind(&data::captureReply, this, _1));
+ // Kick off the request...
+ reply.clear();
+ pumps.obtain("LLXMLRPCTransaction").post(request);
+ // Set the timer
+ F32 timeout(10);
+ watchdog.eventAfter(timeout, LLSD().insert("timeout", 0));
+ // and pump "mainloop" until we get something, whether from
+ // LLXMLRPCListener or from the watchdog filter.
+ LLTimer timer;
+ F32 start = timer.getElapsedTimeF32();
+ LLEventPump& mainloop(pumps.obtain("mainloop"));
+ while (reply.isUndefined())
+ {
+ mainloop.post(LLSD());
+ }
+ ensure("timeout works", (timer.getElapsedTimeF32() - start) < (timeout + 1));
+ ensure_equals("XMLRPC error", reply["status"].asString(), "XMLRPCError");
+ }
+
+ template<> template<>
+ void object::test<5>()
+ {
+ set_test_name("bad type");
+ LLSD request;
+ request["uri"] = uri;
+ request["method"] = "getdict";
+ request["reply"] = "reply";
+ (void)request["params"];
+ // Set up a timeout filter so we don't spin forever waiting.
+ LLEventTimeout watchdog;
+ // Connect the timeout filter to the reply pump.
+ LLTempBoundListener temp(
+ pumps.obtain("reply").
+ listen("watchdog", boost::bind(&LLEventTimeout::post, boost::ref(watchdog), _1)));
+ // Now connect our target listener to the timeout filter.
+ watchdog.listen("captureReply", boost::bind(&data::captureReply, this, _1));
+ // Kick off the request...
+ reply.clear();
+ pumps.obtain("LLXMLRPCTransaction").post(request);
+ // Set the timer
+ F32 timeout(10);
+ watchdog.eventAfter(timeout, LLSD().insert("timeout", 0));
+ // and pump "mainloop" until we get something, whether from
+ // LLXMLRPCListener or from the watchdog filter.
+ LLTimer timer;
+ F32 start = timer.getElapsedTimeF32();
+ LLEventPump& mainloop(pumps.obtain("mainloop"));
+ while (reply.isUndefined())
+ {
+ mainloop.post(LLSD());
+ }
+ ensure("timeout works", (timer.getElapsedTimeF32() - start) < (timeout + 1));
+ ensure_equals(reply["status"].asString(), "BadType");
+ ensure_contains("bad type", reply["responses"]["nested_dict"].asString(), "bad XMLRPC type");
+ }
+} // namespace tut
+
+/*****************************************************************************
+* Resolve link errors: use real machinery here, since we intend to exchange
+* actual XML with a peer process.
+*****************************************************************************/
+// Including llxmlrpctransaction.cpp drags in the static LLXMLRPCListener
+// instantiated there. That's why it works to post requests to the LLEventPump
+// named "LLXMLRPCTransaction".
+#include "../llxmlrpctransaction.cpp"
+#include "llcontrol.cpp"
+#include "llxmltree.cpp"
+#include "llxmlparser.cpp"
diff --git a/indra/newview/tests/test_llxmlrpc_peer.py b/indra/newview/tests/test_llxmlrpc_peer.py
new file mode 100644
index 0000000000..cb8f7d26c4
--- /dev/null
+++ b/indra/newview/tests/test_llxmlrpc_peer.py
@@ -0,0 +1,59 @@
+#!/usr/bin/python
+"""\
+@file test_llxmlrpc_peer.py
+@author Nat Goodspeed
+@date 2008-10-09
+@brief This script asynchronously runs the executable (with args) specified on
+ the command line, returning its result code. While that executable is
+ running, we provide dummy local services for use by C++ tests.
+
+$LicenseInfo:firstyear=2008&license=viewergpl$
+Copyright (c) 2008, Linden Research, Inc.
+$/LicenseInfo$
+"""
+
+import os
+import sys
+from threading import Thread
+from SimpleXMLRPCServer import SimpleXMLRPCServer
+
+mydir = os.path.dirname(__file__) # expected to be .../indra/newview/tests/
+sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python"))
+sys.path.insert(1, os.path.join(mydir, os.pardir, os.pardir, "llmessage", "tests"))
+from testrunner import run, debug
+
+class TestServer(SimpleXMLRPCServer):
+ def _dispatch(self, method, params):
+ try:
+ func = getattr(self, method)
+ except AttributeError:
+ raise Exception('method "%s" is not supported' % method)
+ else:
+ # LLXMLRPCListener constructs XMLRPC parameters that arrive as a
+ # 1-tuple containing a dict.
+ return func(**(params[0]))
+
+ def hello(self, who):
+ # LLXMLRPCListener expects a dict return.
+ return {"hi_there": "Hello, %s!" % who}
+
+ def getdict(self):
+ return dict(nested_dict=dict(a=17, b=5))
+
+ def log_request(self, code, size=None):
+ # For present purposes, we don't want the request splattered onto
+ # stderr, as it would upset devs watching the test run
+ pass
+
+ def log_error(self, format, *args):
+ # Suppress error output as well
+ pass
+
+class ServerRunner(Thread):
+ def run(self):
+ server = TestServer(('127.0.0.1', 8000))
+ debug("Starting XMLRPC server...\n")
+ server.serve_forever()
+
+if __name__ == "__main__":
+ sys.exit(run(server=ServerRunner(name="xmlrpc"), *sys.argv[1:]))