summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorRick Pasetto <rick@lindenlab.com>2009-10-09 18:56:36 -0700
committerRick Pasetto <rick@lindenlab.com>2009-10-09 18:56:36 -0700
commitd4b2897700c66354413af42ab055bd1aaa47f91c (patch)
treec496bd8785b94bb60bca33ea59758c5929341451 /indra
parent8d1f3f735194775b754011de1f6000ccb6d1039e (diff)
Unit tests for LLMediaDataClient
This required a bit of refactoring of LLMediaDataClient: - Created LLMediaDataClientObject ABC, which now has a concrete impl in LLVOVolume - Created unit test with 6 tests (for now), testing - LLObjectMediaDataClient::fetchMedia() - LLObjectMediaDataClient::updateMedia() - LLObjectMediaNavigateClient::navigate() - queue ordering - retries - nav bounce back - Also ensures that ref counting works properly (this is important, because ownership is tricky with smart pointers put into queues, peeled off into timers that fire and auto destruct, and HTTP responders that also auto-destruct) - Had to fix LLCurl::Responder's stub, which was not initializing the ref count to 0, causing the ref counting tests to fail (boy, that was hard to find!). Reviewed by Callum
Diffstat (limited to 'indra')
-rw-r--r--indra/llmessage/tests/llcurl_stub.cpp1
-rw-r--r--indra/newview/CMakeLists.txt1
-rw-r--r--indra/newview/app_settings/settings.xml11
-rw-r--r--indra/newview/llmediadataclient.cpp135
-rw-r--r--indra/newview/llmediadataclient.h85
-rw-r--r--indra/newview/llvovolume.cpp81
-rw-r--r--indra/newview/llvovolume.h1
-rw-r--r--indra/newview/tests/llmediadataclient_test.cpp481
8 files changed, 713 insertions, 83 deletions
diff --git a/indra/llmessage/tests/llcurl_stub.cpp b/indra/llmessage/tests/llcurl_stub.cpp
index 5dc5932fde..e6a5ad9946 100644
--- a/indra/llmessage/tests/llcurl_stub.cpp
+++ b/indra/llmessage/tests/llcurl_stub.cpp
@@ -22,6 +22,7 @@
#include "linden_common.h"
LLCurl::Responder::Responder()
+ : mReferenceCount(0)
{
}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 9f0a0111f5..e0ca0a760f 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1540,6 +1540,7 @@ include(LLAddBuildTest)
SET(viewer_TEST_SOURCE_FILES
llagentaccess.cpp
lldateutil.cpp
+ llmediadataclient.cpp
llviewerhelputil.cpp
)
set_source_files_properties(
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 806f96a654..dc0e5ffa1d 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -5294,6 +5294,17 @@
<key>Value</key>
<integer>13</integer>
</map>
+ <key>PrimMediaMaxRetries</key>
+ <map>
+ <key>Comment</key>
+ <string>Maximum number of retries for media queries.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>4</integer>
+ </map>
<key>PrimMediaRequestQueueDelay</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp
index 4dde381e97..e69c85f245 100644
--- a/indra/newview/llmediadataclient.cpp
+++ b/indra/newview/llmediadataclient.cpp
@@ -41,7 +41,6 @@
#include "llmediaentry.h"
#include "lltextureentry.h"
#include "llviewerregion.h"
-#include "llvovolume.h"
//
// When making a request
@@ -54,7 +53,9 @@
// - Any request that gets a 503 still goes through the retry logic
//
-// Some helpful logging macros
+const F32 LLMediaDataClient::QUEUE_TIMER_DELAY = 1.0; // seconds(s)
+const F32 LLMediaDataClient::UNAVAILABLE_RETRY_TIMER_DELAY = 5.0; // secs
+const U32 LLMediaDataClient::MAX_RETRIES = 4;
//////////////////////////////////////////////////////////////////////////////////////
//
@@ -65,7 +66,7 @@
LLMediaDataClient::Request::Request(const std::string &cap_name,
const LLSD& sd_payload,
- LLVOVolume *obj,
+ LLMediaDataClientObject *obj,
LLMediaDataClient *mdc)
: mCapName(cap_name),
mPayload(sd_payload),
@@ -78,6 +79,7 @@ LLMediaDataClient::Request::Request(const std::string &cap_name,
LLMediaDataClient::Request::~Request()
{
+ LL_DEBUGS("LLMediaDataClient") << "~Request" << (*this) << LL_ENDL;
mMDC = NULL;
mObject = NULL;
}
@@ -85,7 +87,7 @@ LLMediaDataClient::Request::~Request()
std::string LLMediaDataClient::Request::getCapability() const
{
- return getObject()->getRegion()->getCapability(getCapName());
+ return getObject()->getCapabilityUrl(getCapName());
}
// Helper function to get the "type" of request, which just pokes around to
@@ -137,6 +139,17 @@ void LLMediaDataClient::Request::reEnqueue() const
mMDC->enqueue(this);
}
+F32 LLMediaDataClient::Request::getRetryTimerDelay() const
+{
+ return (mMDC == NULL) ? LLMediaDataClient::UNAVAILABLE_RETRY_TIMER_DELAY :
+ mMDC->mRetryTimerDelay;
+}
+
+U32 LLMediaDataClient::Request::getMaxNumRetries() const
+{
+ return (mMDC == NULL) ? LLMediaDataClient::MAX_RETRIES : mMDC->mMaxNumRetries;
+}
+
std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &r)
{
s << "<request>"
@@ -163,6 +176,7 @@ LLMediaDataClient::Responder::RetryTimer::RetryTimer(F32 time, Responder *mdr)
// virtual
LLMediaDataClient::Responder::RetryTimer::~RetryTimer()
{
+ LL_DEBUGS("LLMediaDataClient") << "~RetryTimer" << *(mResponder->getRequest()) << LL_ENDL;
mResponder = NULL;
}
@@ -190,28 +204,31 @@ LLMediaDataClient::Responder::Responder(const request_ptr_t &request)
LLMediaDataClient::Responder::~Responder()
{
+ LL_DEBUGS("LLMediaDataClient") << "~Responder" << *(getRequest()) << LL_ENDL;
mRequest = NULL;
}
/*virtual*/
void LLMediaDataClient::Responder::error(U32 status, const std::string& reason)
{
- extern LLControlGroup gSavedSettings;
-
if (status == HTTP_SERVICE_UNAVAILABLE)
{
- F32 retry_timeout = gSavedSettings.getF32("PrimMediaRetryTimerDelay");
- if (retry_timeout <= 0.0)
- {
- retry_timeout = (F32)UNAVAILABLE_RETRY_TIMER_DELAY;
- }
- LL_INFOS("LLMediaDataClient") << *mRequest << "got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL;
+ F32 retry_timeout = mRequest->getRetryTimerDelay();
mRequest->incRetryCount();
- // Start timer (instances are automagically tracked by
- // InstanceTracker<> and LLEventTimer)
- new RetryTimer(F32(retry_timeout/*secs*/), this);
+ if (mRequest->getRetryCount() < mRequest->getMaxNumRetries())
+ {
+ LL_INFOS("LLMediaDataClient") << *mRequest << "got SERVICE_UNAVAILABLE...retrying in " << retry_timeout << " seconds" << LL_ENDL;
+
+ // Start timer (instances are automagically tracked by
+ // InstanceTracker<> and LLEventTimer)
+ new RetryTimer(F32(retry_timeout/*secs*/), this);
+ }
+ else {
+ LL_INFOS("LLMediaDataClient") << *mRequest << "got SERVICE_UNAVAILABLE...retry count " <<
+ mRequest->getRetryCount() << " exceeds " << mRequest->getMaxNumRetries() << ", not retrying" << LL_ENDL;
+ }
}
else {
std::string msg = boost::lexical_cast<std::string>(status) + ": " + reason;
@@ -252,29 +269,25 @@ bool LLMediaDataClient::Comparator::operator() (const request_ptr_t &o1, const r
// Calculate the scores for each.
F64 o1_score = Comparator::getObjectScore(o1->getObject());
F64 o2_score = Comparator::getObjectScore(o2->getObject());
-
- return ( o1_score > o2_score );
+
+ // XXX Weird: a higher score should go earlier, but by observation I notice
+ // that this causes further-away objects load first. This is counterintuitive
+ // to the priority_queue Comparator, which states that this function should
+ // return 'true' if o1 should be *before* o2.
+ // In other words, I'd have expected that the following should return
+ // ( o1_score > o2_score).
+ return ( o1_score < o2_score );
}
// static
-F64 LLMediaDataClient::Comparator::getObjectScore(const ll_vo_volume_ptr_t &obj)
+F64 LLMediaDataClient::Comparator::getObjectScore(const LLMediaDataClientObject::ptr_t &obj)
{
// *TODO: make this less expensive?
- F32 dist = obj->getRenderPosition().length() + 0.1; // avoids div by 0
+ F64 dist = obj->getDistanceFromAvatar() + 0.1; // avoids div by 0
// square the distance so that they are in the same "unit magnitude" as
// the interest (which is an area)
dist *= dist;
- F64 interest = (F64)1;
- int i = 0;
- int end = obj->getNumTEs();
- for ( ; i < end; ++i)
- {
- const viewer_media_t &impl = obj->getMediaImpl(i);
- if (!impl.isNull())
- {
- interest += impl->getInterest();
- }
- }
+ F64 interest = obj->getTotalMediaInterest() + 1.0;
return interest/dist;
}
@@ -282,7 +295,7 @@ F64 LLMediaDataClient::Comparator::getObjectScore(const ll_vo_volume_ptr_t &obj)
//////////////////////////////////////////////////////////////////////////////////////
//
// LLMediaDataClient::PriorityQueue
-// Queue of LLVOVolume smart pointers to request media for.
+// Queue of LLMediaDataClientObject smart pointers to request media for.
//
//////////////////////////////////////////////////////////////////////////////////////
@@ -304,7 +317,7 @@ std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::PriorityQueue
//////////////////////////////////////////////////////////////////////////////////////
//
// LLMediaDataClient::QueueTimer
-// Queue of LLVOVolume smart pointers to request media for.
+// Queue of LLMediaDataClientObject smart pointers to request media for.
//
//////////////////////////////////////////////////////////////////////////////////////
@@ -316,6 +329,7 @@ LLMediaDataClient::QueueTimer::QueueTimer(F32 time, LLMediaDataClient *mdc)
LLMediaDataClient::QueueTimer::~QueueTimer()
{
+ LL_DEBUGS("LLMediaDataClient") << "~QueueTimer" << LL_ENDL;
mMDC->setIsRunning(false);
mMDC = NULL;
}
@@ -343,10 +357,10 @@ BOOL LLMediaDataClient::QueueTimer::tick()
// Peel one off of the items from the queue, and execute request
request_ptr_t request = queue.top();
llassert(!request.isNull());
- const ll_vo_volume_ptr_t &object = request->getObject();
+ const LLMediaDataClientObject *object = request->getObject();
bool performed_request = false;
- llassert(!object.isNull());
- if (!object.isNull() && object->hasMedia())
+ llassert(NULL != object);
+ if (NULL != object && object->hasMedia())
{
std::string url = request->getCapability();
if (!url.empty())
@@ -368,12 +382,13 @@ BOOL LLMediaDataClient::QueueTimer::tick()
LL_INFOS("LLMediaDataClient") << "Not Sending request for " << *request << " hasMedia() is false!" << LL_ENDL;
}
}
- bool exceeded_retries = request->getRetryCount() > LLMediaDataClient::MAX_RETRIES;
+ bool exceeded_retries = request->getRetryCount() > mMDC->mMaxNumRetries;
if (performed_request || exceeded_retries) // Try N times before giving up
{
if (exceeded_retries)
{
- LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for " << LLMediaDataClient::MAX_RETRIES << " tries...popping object id " << object->getID() << LL_ENDL;
+ LL_WARNS("LLMediaDataClient") << "Could not send request " << *request << " for "
+ << mMDC->mMaxNumRetries << " tries...popping object id " << object->getID() << LL_ENDL;
// XXX Should we bring up a warning dialog??
}
queue.pop();
@@ -390,15 +405,9 @@ void LLMediaDataClient::startQueueTimer()
{
if (! mQueueTimerIsRunning)
{
- extern LLControlGroup gSavedSettings;
- F32 queue_timer_delay = gSavedSettings.getF32("PrimMediaRequestQueueDelay");
- if (queue_timer_delay <= 0.0f)
- {
- queue_timer_delay = (F32)LLMediaDataClient::QUEUE_TIMER_DELAY;
- }
- LL_INFOS("LLMediaDataClient") << "starting queue timer (delay=" << queue_timer_delay << " seconds)" << LL_ENDL;
+ LL_INFOS("LLMediaDataClient") << "starting queue timer (delay=" << mQueueTimerDelay << " seconds)" << LL_ENDL;
// LLEventTimer automagically takes care of the lifetime of this object
- new QueueTimer(queue_timer_delay, this);
+ new QueueTimer(mQueueTimerDelay, this);
}
}
@@ -407,9 +416,9 @@ void LLMediaDataClient::stopQueueTimer()
mQueueTimerIsRunning = false;
}
-void LLMediaDataClient::request(LLVOVolume *object, const LLSD &payload)
+void LLMediaDataClient::request(const LLMediaDataClientObject::ptr_t &object, const LLSD &payload)
{
- if (NULL == object || ! object->hasMedia()) return;
+ if (object.isNull() || ! object->hasMedia()) return;
// Push the object on the priority queue
enqueue(new Request(getCapabilityName(), payload, object, this));
@@ -432,7 +441,13 @@ void LLMediaDataClient::enqueue(const Request *request)
//
//////////////////////////////////////////////////////////////////////////////////////
-LLMediaDataClient::LLMediaDataClient()
+LLMediaDataClient::LLMediaDataClient(F32 queue_timer_delay,
+ F32 retry_timer_delay,
+ U32 max_retries)
+ : mQueueTimerDelay(queue_timer_delay),
+ mRetryTimerDelay(retry_timer_delay),
+ mMaxNumRetries(max_retries),
+ mQueueTimerIsRunning(false)
{
pRequestQueue = new PriorityQueue();
}
@@ -442,12 +457,17 @@ LLMediaDataClient::~LLMediaDataClient()
stopQueueTimer();
// This should clear the queue, and hopefully call all the destructors.
- LL_DEBUGS("LLMediaDataClient") << "destructor: queue: " <<
+ LL_DEBUGS("LLMediaDataClient") << "~LLMediaDataClient destructor: queue: " <<
(pRequestQueue->empty() ? "<empty> " : "<not empty> ") << (*pRequestQueue) << LL_ENDL;
delete pRequestQueue;
pRequestQueue = NULL;
}
+bool LLMediaDataClient::isEmpty() const
+{
+ return (NULL == pRequestQueue) ? true : pRequestQueue->empty();
+}
+
//////////////////////////////////////////////////////////////////////////////////////
//
// LLObjectMediaDataClient
@@ -465,7 +485,7 @@ const char *LLObjectMediaDataClient::getCapabilityName() const
return "ObjectMedia";
}
-void LLObjectMediaDataClient::fetchMedia(LLVOVolume *object)
+void LLObjectMediaDataClient::fetchMedia(LLMediaDataClientObject *object)
{
LLSD sd_payload;
sd_payload["verb"] = "GET";
@@ -473,18 +493,17 @@ void LLObjectMediaDataClient::fetchMedia(LLVOVolume *object)
request(object, sd_payload);
}
-void LLObjectMediaDataClient::updateMedia(LLVOVolume *object)
+void LLObjectMediaDataClient::updateMedia(LLMediaDataClientObject *object)
{
LLSD sd_payload;
sd_payload["verb"] = "UPDATE";
sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID();
LLSD object_media_data;
- for (int i=0; i < object->getNumTEs(); i++) {
- LLTextureEntry *texture_entry = object->getTE(i);
- llassert((texture_entry->getMediaData() != NULL) == texture_entry->hasMedia());
- const LLSD &media_data =
- (texture_entry->getMediaData() == NULL) ? LLSD() : texture_entry->getMediaData()->asLLSD();
- object_media_data.append(media_data);
+ int i = 0;
+ int end = object->getMediaDataCount();
+ for ( ; i < end ; ++i)
+ {
+ object_media_data.append(object->getMediaDataLLSD(i));
}
sd_payload[LLTextureEntry::OBJECT_MEDIA_DATA_KEY] = object_media_data;
@@ -548,7 +567,7 @@ const char *LLObjectMediaNavigateClient::getCapabilityName() const
return "ObjectMediaNavigate";
}
-void LLObjectMediaNavigateClient::navigate(LLVOVolume *object, U8 texture_index, const std::string &url)
+void LLObjectMediaNavigateClient::navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url)
{
LLSD sd_payload;
sd_payload[LLTextureEntry::OBJECT_ID_KEY] = object->getID();
diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h
index 949e7239be..9d0aa0981e 100644
--- a/indra/newview/llmediadataclient.h
+++ b/indra/newview/llmediadataclient.h
@@ -36,12 +36,36 @@
#include "llhttpclient.h"
#include <queue>
#include "llrefcount.h"
+#include "llpointer.h"
#include "lltimer.h"
-// Forward decls
-class LLVOVolume;
-typedef LLPointer<LLVOVolume> ll_vo_volume_ptr_t;
+// Link seam for LLVOVolume
+class LLMediaDataClientObject : public LLRefCount
+{
+public:
+ // Get the number of media data items
+ virtual U8 getMediaDataCount() const = 0;
+ // Get the media data at index, as an LLSD
+ virtual LLSD getMediaDataLLSD(U8 index) const = 0;
+ // Get this object's UUID
+ virtual LLUUID getID() const = 0;
+ // Navigate back to previous URL
+ virtual void mediaNavigateBounceBack(U8 index) = 0;
+ // Does this object have media?
+ virtual bool hasMedia() const = 0;
+ // Update the object's media data to the given array
+ virtual void updateObjectMediaData(LLSD const &media_data_array) = 0;
+ // Return the distance from the object to the avatar
+ virtual F64 getDistanceFromAvatar() const = 0;
+ // Return the total "interest" of the media (on-screen area)
+ virtual F64 getTotalMediaInterest() const = 0;
+ // Return the given cap url
+ virtual std::string getCapabilityUrl(const std::string &name) const = 0;
+
+ // smart pointer
+ typedef LLPointer<LLMediaDataClientObject> ptr_t;
+};
// This object creates a priority queue for requests.
// Abstracts the Cap URL, the request, and the responder
@@ -50,15 +74,23 @@ class LLMediaDataClient : public LLRefCount
public:
LOG_CLASS(LLMediaDataClient);
- const static int QUEUE_TIMER_DELAY = 1; // seconds(s)
- const static int MAX_RETRIES = 4;
+ const static F32 QUEUE_TIMER_DELAY;// = 1.0; // seconds(s)
+ const static F32 UNAVAILABLE_RETRY_TIMER_DELAY;// = 5.0; // secs
+ const static U32 MAX_RETRIES;// = 4;
// Constructor
- LLMediaDataClient();
+ LLMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
+ F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
+ U32 max_retries = MAX_RETRIES);
// Make the request
- void request(LLVOVolume *object, const LLSD &payload);
-
+ void request(const LLMediaDataClientObject::ptr_t &object, const LLSD &payload);
+
+ F32 getRetryTimerDelay() const { return mRetryTimerDelay; }
+
+ // Returns true iff the queue is empty
+ bool isEmpty() const;
+
protected:
// Destructor
virtual ~LLMediaDataClient(); // use unref
@@ -73,10 +105,10 @@ protected:
NAVIGATE
};
- Request(const std::string &cap_name, const LLSD& sd_payload, LLVOVolume *obj, LLMediaDataClient *mdc);
+ Request(const std::string &cap_name, const LLSD& sd_payload, LLMediaDataClientObject *obj, LLMediaDataClient *mdc);
const std::string &getCapName() const { return mCapName; }
const LLSD &getPayload() const { return mPayload; }
- LLVOVolume *getObject() const { return mObject; }
+ LLMediaDataClientObject *getObject() const { return mObject; }
U32 getNum() const { return mNum; }
@@ -92,6 +124,9 @@ protected:
// Re-enqueue thyself
void reEnqueue() const;
+ F32 getRetryTimerDelay() const;
+ U32 getMaxNumRetries() const;
+
public:
friend std::ostream& operator<<(std::ostream &s, const Request &q);
@@ -101,7 +136,7 @@ protected:
private:
std::string mCapName;
LLSD mPayload;
- ll_vo_volume_ptr_t mObject;
+ LLMediaDataClientObject::ptr_t mObject;
// Simple tracking
const U32 mNum;
static U32 sNum;
@@ -115,8 +150,6 @@ protected:
// Responder
class Responder : public LLHTTPClient::Responder
{
- static const int UNAVAILABLE_RETRY_TIMER_DELAY = 5; // secs
-
public:
Responder(const request_ptr_t &request);
//If we get back an error (not found, etc...), handle it here
@@ -163,7 +196,7 @@ private:
public:
bool operator() (const request_ptr_t &o1, const request_ptr_t &o2) const;
private:
- static F64 getObjectScore(const ll_vo_volume_ptr_t &obj);
+ static F64 getObjectScore(const LLMediaDataClientObject::ptr_t &obj);
};
// PriorityQueue
@@ -194,6 +227,10 @@ private:
void startQueueTimer();
void stopQueueTimer();
void setIsRunning(bool val) { mQueueTimerIsRunning = val; }
+
+ const F32 mQueueTimerDelay;
+ const F32 mRetryTimerDelay;
+ const U32 mMaxNumRetries;
bool mQueueTimerIsRunning;
@@ -205,11 +242,15 @@ private:
class LLObjectMediaDataClient : public LLMediaDataClient
{
public:
- LLObjectMediaDataClient() {}
+ LLObjectMediaDataClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
+ F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
+ U32 max_retries = MAX_RETRIES)
+ : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries)
+ {}
~LLObjectMediaDataClient() {}
- void fetchMedia(LLVOVolume *object);
- void updateMedia(LLVOVolume *object);
+ void fetchMedia(LLMediaDataClientObject *object);
+ void updateMedia(LLMediaDataClientObject *object);
protected:
// Subclasses must override this factory method to return a new responder
@@ -231,14 +272,18 @@ protected:
// MediaDataResponder specific for the ObjectMediaNavigate cap
class LLObjectMediaNavigateClient : public LLMediaDataClient
{
+public:
// NOTE: from llmediaservice.h
static const int ERROR_PERMISSION_DENIED_CODE = 8002;
-public:
- LLObjectMediaNavigateClient() {}
+ LLObjectMediaNavigateClient(F32 queue_timer_delay = QUEUE_TIMER_DELAY,
+ F32 retry_timer_delay = UNAVAILABLE_RETRY_TIMER_DELAY,
+ U32 max_retries = MAX_RETRIES)
+ : LLMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries)
+ {}
~LLObjectMediaNavigateClient() {}
- void navigate(LLVOVolume *object, U8 texture_index, const std::string &url);
+ void navigate(LLMediaDataClientObject *object, U8 texture_index, const std::string &url);
protected:
// Subclasses must override this factory method to return a new responder
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 83e65af054..1704f63376 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -91,6 +91,57 @@ LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient =
static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles");
static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes");
+// Implementation class of LLMediaDataClientObject. See llmediadataclient.h
+class LLMediaDataClientObjectImpl : public LLMediaDataClientObject
+{
+public:
+ LLMediaDataClientObjectImpl(LLVOVolume *obj) : mObject(obj) {}
+ LLMediaDataClientObjectImpl() { mObject = NULL; }
+
+ virtual U8 getMediaDataCount() const
+ { return mObject->getNumTEs(); }
+
+ virtual LLSD getMediaDataLLSD(U8 index) const
+ {
+ LLSD result;
+ LLTextureEntry *te = mObject->getTE(index);
+ if (NULL != te)
+ {
+ llassert((te->getMediaData() != NULL) == te->hasMedia());
+ if (te->getMediaData() != NULL)
+ {
+ result = te->getMediaData()->asLLSD();
+ }
+ }
+ return result;
+ }
+
+ virtual LLUUID getID() const
+ { return mObject->getID(); }
+
+ virtual void mediaNavigateBounceBack(U8 index)
+ { mObject->mediaNavigateBounceBack(index); }
+
+ virtual bool hasMedia() const
+ { return mObject->hasMedia(); }
+
+ virtual void updateObjectMediaData(LLSD const &data)
+ { mObject->updateObjectMediaData(data); }
+
+ virtual F64 getDistanceFromAvatar() const
+ { return mObject->getRenderPosition().length(); }
+
+ virtual F64 getTotalMediaInterest() const
+ { return mObject->getTotalMediaInterest(); }
+
+ virtual std::string getCapabilityUrl(const std::string &name) const
+ { return mObject->getRegion()->getCapability(name); }
+
+private:
+ LLPointer<LLVOVolume> mObject;
+};
+
+
LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
: LLViewerObject(id, pcode, regionp),
mVolumeImpl(NULL)
@@ -134,8 +185,12 @@ LLVOVolume::~LLVOVolume()
// static
void LLVOVolume::initClass()
{
- sObjectMediaClient = new LLObjectMediaDataClient();
- sObjectMediaNavigateClient = new LLObjectMediaNavigateClient();
+ // gSavedSettings better be around
+ const F32 queue_timer_delay = gSavedSettings.getF32("PrimMediaRequestQueueDelay");
+ const F32 retry_timer_delay = gSavedSettings.getF32("PrimMediaRetryTimerDelay");
+ const U32 max_retries = gSavedSettings.getU32("PrimMediaMaxRetries");
+ sObjectMediaClient = new LLObjectMediaDataClient(queue_timer_delay, retry_timer_delay, max_retries);
+ sObjectMediaNavigateClient = new LLObjectMediaNavigateClient(queue_timer_delay, retry_timer_delay, max_retries);
}
// static
@@ -1634,7 +1689,7 @@ bool LLVOVolume::hasMedia() const
void LLVOVolume::requestMediaDataUpdate()
{
- sObjectMediaClient->fetchMedia(this);
+ sObjectMediaClient->fetchMedia(new LLMediaDataClientObjectImpl(this));
}
void LLVOVolume::cleanUpMediaImpls()
@@ -1834,7 +1889,7 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
llinfos << "broadcasting navigate with URI " << new_location << llendl;
- sObjectMediaNavigateClient->navigate(this, face_index, new_location);
+ sObjectMediaNavigateClient->navigate(new LLMediaDataClientObjectImpl(this), face_index, new_location);
}
}
break;
@@ -1860,7 +1915,7 @@ void LLVOVolume::mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin,
void LLVOVolume::sendMediaDataUpdate()
{
- sObjectMediaClient->updateMedia(this);
+ sObjectMediaClient->updateMedia(new LLMediaDataClientObjectImpl(this));
}
void LLVOVolume::removeMediaImpl(S32 texture_index)
@@ -1953,6 +2008,22 @@ viewer_media_t LLVOVolume::getMediaImpl(U8 face_id) const
return NULL;
}
+F64 LLVOVolume::getTotalMediaInterest() const
+{
+ F64 interest = (F64)0.0;
+ int i = 0;
+ const int end = getNumTEs();
+ for ( ; i < end; ++i)
+ {
+ const viewer_media_t &impl = getMediaImpl(i);
+ if (!impl.isNull())
+ {
+ interest += impl->getInterest();
+ }
+ }
+ return interest;
+}
+
S32 LLVOVolume::getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id)
{
S32 end = (S32)mMediaImplList.size() ;
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index bb2b890000..90dfa2204b 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -255,6 +255,7 @@ public:
viewer_media_t getMediaImpl(U8 face_id) const;
S32 getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S32 start_face_id);
+ F64 getTotalMediaInterest() const;
bool hasMedia() const;
diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp
new file mode 100644
index 0000000000..135c5ab501
--- /dev/null
+++ b/indra/newview/tests/llmediadataclient_test.cpp
@@ -0,0 +1,481 @@
+/**
+ * @file llmediadataclient_test.cpp
+ * @brief LLMediaDatClient tests
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include <iostream>
+#include "../test/lltut.h"
+
+#include "llsdserialize.h"
+#include "llerrorcontrol.h"
+#include "llhttpstatuscodes.h"
+
+#include "../llmediadataclient.h"
+#include "../llvovolume.h"
+
+#include "../../llprimitive/llmediaentry.cpp"
+#include "../../llprimitive/lltextureentry.cpp"
+#include "../../llmessage/tests/llcurl_stub.cpp"
+
+#include <boost/lexical_cast.hpp>
+
+#define VALID_OBJECT_ID "3607d5c4-644b-4a8a-871a-8b78471af2a2"
+#define VALID_OBJECT_ID_1 "11111111-1111-1111-1111-111111111111"
+#define VALID_OBJECT_ID_2 "22222222-2222-2222-2222-222222222222"
+#define VALID_OBJECT_ID_3 "33333333-3333-3333-3333-333333333333"
+#define VALID_OBJECT_ID_4 "44444444-4444-4444-4444-444444444444"
+
+#define FAKE_OBJECT_MEDIA_CAP_URL "foo_ObjectMedia"
+#define FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL "foo_ObjectMediaNavigate"
+#define FAKE_OBJECT_MEDIA_CAP_URL_503 "foo_ObjectMedia_503"
+#define FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR "foo_ObjectMediaNavigate_ERROR"
+
+#define MEDIA_DATA "\
+<array> \
+<string>foo</string> \
+<string>bar</string> \
+<string>baz</string> \
+</array>"
+
+#define _DATA_URLS(ID,DIST,INT,URL1,URL2) " \
+<llsd> \
+ <map> \
+ <key>uuid</key> \
+ <string>" ID "</string> \
+ <key>distance</key> \
+ <real>" DIST "</real> \
+ <key>interest</key> \
+ <real>" INT "</real> \
+ <key>cap_urls</key> \
+ <map> \
+ <key>ObjectMedia</key> \
+ <string>" URL1 "</string> \
+ <key>ObjectMediaNavigate</key> \
+ <string>" URL2 "</string> \
+ </map> \
+ <key>media_data</key> \
+ " MEDIA_DATA " \
+ </map> \
+</llsd>"
+
+#define _DATA(ID,DIST,INT) _DATA_URLS(ID,DIST,INT,FAKE_OBJECT_MEDIA_CAP_URL,FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL)
+
+const char *DATA = _DATA(VALID_OBJECT_ID,"1.0","1.0");
+
+#define STR(I) boost::lexical_cast<std::string>(I)
+
+#define LOG_TEST(N) LL_DEBUGS("LLMediaDataClient") << "\n" << \
+"================================================================================\n" << \
+"===================================== TEST " #N " ===================================\n" << \
+"================================================================================\n" << LL_ENDL;
+
+LLSD *gPostRecords = NULL;
+
+// stubs:
+void LLHTTPClient::post(
+ const std::string& url,
+ const LLSD& body,
+ LLHTTPClient::ResponderPtr responder,
+ const LLSD& headers,
+ const F32 timeout)
+{
+ LLSD record;
+ record["url"] = url;
+ record["body"] = body;
+ record["headers"] = headers;
+ record["timeout"] = timeout;
+ gPostRecords->append(record);
+
+ // Magic URL that triggers a 503:
+ if ( url == FAKE_OBJECT_MEDIA_CAP_URL_503 )
+ {
+ responder->error(HTTP_SERVICE_UNAVAILABLE, "fake reason");
+ }
+ else if (url == FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR)
+ {
+ LLSD result;
+ LLSD error;
+ error["code"] = LLObjectMediaNavigateClient::ERROR_PERMISSION_DENIED_CODE;
+ result["error"] = error;
+ responder->result(result);
+ }
+ else {
+ responder->result(LLSD());
+ }
+}
+
+const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
+
+class LLMediaDataClientObjectTest : public LLMediaDataClientObject
+{
+public:
+ LLMediaDataClientObjectTest(const char *data)
+ {
+ std::istringstream d(data);
+ LLSDSerialize::fromXML(mRep, d);
+ mNumBounceBacks = 0;
+
+ // std::cout << ll_pretty_print_sd(mRep) << std::endl;
+ // std::cout << "ID: " << getID() << std::endl;
+ }
+ LLMediaDataClientObjectTest(const LLSD &rep)
+ : mRep(rep), mNumBounceBacks(0) {}
+ ~LLMediaDataClientObjectTest()
+ { LL_DEBUGS("LLMediaDataClient") << "~LLMediaDataClientObjectTest" << LL_ENDL; }
+
+ virtual U8 getMediaDataCount() const
+ { return mRep["media_data"].size(); }
+ virtual LLSD getMediaDataLLSD(U8 index) const
+ { return mRep["media_data"][(LLSD::Integer)index]; }
+ virtual LLUUID getID() const
+ { return mRep["uuid"]; }
+ virtual void mediaNavigateBounceBack(U8 index)
+ {
+ mNumBounceBacks++;
+ }
+
+ virtual bool hasMedia() const
+ { return mRep.has("media_data"); }
+
+ virtual void updateObjectMediaData(LLSD const &media_data_array)
+ { mRep["media_data"] = media_data_array; }
+
+ virtual F64 getDistanceFromAvatar() const
+ { return (LLSD::Real)mRep["distance"]; }
+
+ virtual F64 getTotalMediaInterest() const
+ { return (LLSD::Real)mRep["interest"]; }
+
+ virtual std::string getCapabilityUrl(const std::string &name) const
+ { return mRep["cap_urls"][name]; }
+
+ int getNumBounceBacks() const
+ { return mNumBounceBacks; }
+
+private:
+ LLSD mRep;
+ int mNumBounceBacks;
+};
+
+
+namespace tut
+{
+ struct mediadataclient
+ {
+ mediadataclient() {
+ gPostRecords = &mLLSD;
+
+// LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
+// LLError::setClassLevel("LLMediaDataClient", LLError::LEVEL_DEBUG);
+// LLError::setTagLevel("MediaOnAPrim", LLError::LEVEL_DEBUG);
+ }
+ LLSD mLLSD;
+ };
+
+ typedef test_group<mediadataclient> mediadataclient_t;
+ typedef mediadataclient_t::object mediadataclient_object_t;
+ tut::mediadataclient_t tut_mediadataclient("mediadataclient");
+
+ void ensure(const std::string &msg, int value, int expected)
+ {
+ std::string m = msg;
+ m += " value: " + STR(value);
+ m += ", expected: " + STR(expected);
+ ensure(m, value == expected);
+ }
+
+ void ensure(const std::string &msg, const std::string & value, const std::string & expected)
+ {
+ std::string m = msg;
+ m += " value: " + value;
+ m += ", expected: " + expected;
+ ensure(m, value == expected);
+ }
+
+ void ensure(const std::string &msg, const LLUUID & value, const LLUUID & expected)
+ {
+ std::string m = msg;
+ m += " value: " + value.asString();
+ m += ", expected: " + expected.asString();
+ ensure(m, value == expected);
+ }
+
+ void ensure_llsd(const std::string &msg, const LLSD & value, const char *expected)
+ {
+ LLSD expected_llsd;
+ std::istringstream e(expected);
+ LLSDSerialize::fromXML(expected_llsd, e);
+
+ std::string value_str = ll_pretty_print_sd(value);
+ std::string expected_str = ll_pretty_print_sd(expected_llsd);
+ std::string m = msg;
+ m += " value: " + value_str;
+ m += ", expected: " + expected_str;
+ ensure(m, value_str == expected_str);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<1>()
+ {
+ //
+ // Test fetchMedia()
+ //
+ LOG_TEST(1);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
+ int num_refs_start = o->getNumRefs();
+ {
+ // queue time w/ no delay ensures that LLEventTimer::updateClass() will hit the tick()
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,4);
+ mdc->fetchMedia(o);
+
+ // Make sure no posts happened yet...
+ ensure("post records", gPostRecords->size(), 0);
+
+ LLEventTimer::updateClass();
+
+ ensure("post records", gPostRecords->size(), 1);
+ ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
+ ensure("post GET", (*gPostRecords)[0]["body"]["verb"], "GET");
+ ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+ ensure("queue empty", mdc->isEmpty());
+ }
+
+ // Make sure everyone's destroyed properly
+ ensure("REF COUNT", o->getNumRefs(), num_refs_start);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<2>()
+ {
+ //
+ // Test updateMedia()
+ //
+ LOG_TEST(2);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
+ {
+ // queue time w/ no delay ensures that LLEventTimer::updateClass() will hit the tick()
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,4);
+ mdc->updateMedia(o);
+ ensure("post records", gPostRecords->size(), 0);
+ LLEventTimer::updateClass();
+
+ ensure("post records", gPostRecords->size(), 1);
+ ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
+ ensure("post UPDATE", (*gPostRecords)[0]["body"]["verb"], "UPDATE");
+ ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+ ensure_llsd("post data llsd", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_MEDIA_DATA_KEY],
+ "<llsd>" MEDIA_DATA "</llsd>");
+ ensure("queue empty", mdc->isEmpty());
+ }
+
+ ensure("REF COUNT", o->getNumRefs(), 1);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<3>()
+ {
+ //
+ // Test navigate()
+ //
+ LOG_TEST(3);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
+ {
+ LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(0,0,4);
+ const char *TEST_URL = "http://example.com";
+ mdc->navigate(o, 0, TEST_URL);
+ ensure("post records", gPostRecords->size(), 0);
+ LLEventTimer::updateClass();
+
+ // ensure no bounce back
+ ensure("bounce back", dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o))->getNumBounceBacks(), 0);
+
+ ensure("post records", gPostRecords->size(), 1);
+ ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL);
+ ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+ ensure("post data", (*gPostRecords)[0]["body"][LLTextureEntry::TEXTURE_INDEX_KEY], 0);
+ ensure("post data", (*gPostRecords)[0]["body"][LLMediaEntry::CURRENT_URL_KEY], TEST_URL);
+ ensure("queue empty", mdc->isEmpty());
+ }
+ ensure("REF COUNT", o->getNumRefs(), 1);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<4>()
+ {
+ //
+ // Test queue ordering
+ //
+ LOG_TEST(4);
+
+ LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(
+ _DATA(VALID_OBJECT_ID_1,"3.0","1.0"));
+ LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(
+ _DATA(VALID_OBJECT_ID_2,"1.0","1.0"));
+ LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(
+ _DATA(VALID_OBJECT_ID_3,"2.0","1.0"));
+ {
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,4);
+ const char *ORDERED_OBJECT_IDS[] = { VALID_OBJECT_ID_2, VALID_OBJECT_ID_3, VALID_OBJECT_ID_1 };
+ mdc->fetchMedia(o1);
+ mdc->fetchMedia(o2);
+ mdc->fetchMedia(o3);
+
+ // Make sure no posts happened yet...
+ ensure("post records", gPostRecords->size(), 0);
+
+ // tick 3 times...
+ LLEventTimer::updateClass();
+ ensure("post records", gPostRecords->size(), 1);
+ LLEventTimer::updateClass();
+ ensure("post records", gPostRecords->size(), 2);
+ LLEventTimer::updateClass();
+ ensure("post records", gPostRecords->size(), 3);
+
+ for( int i=0; i < 3; i++ )
+ {
+ ensure("[" + STR(i) + "] post url", (*gPostRecords)[i]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
+ ensure("[" + STR(i) + "] post GET", (*gPostRecords)[i]["body"]["verb"], "GET");
+ ensure("[" + STR(i) + "] post object id", (*gPostRecords)[i]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(),
+ LLUUID(ORDERED_OBJECT_IDS[i]));
+ }
+
+ ensure("queue empty", mdc->isEmpty());
+ }
+ ensure("refcount of o1", o1->getNumRefs(), 1);
+ ensure("refcount of o2", o2->getNumRefs(), 1);
+ ensure("refcount of o3", o3->getNumRefs(), 1);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ template<> template<>
+ void mediadataclient_object_t::test<5>()
+ {
+ //
+ // Test fetchMedia() getting a 503 error
+ //
+ LOG_TEST(5);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(
+ _DATA_URLS(VALID_OBJECT_ID,
+ "1.0",
+ "1.0",
+ FAKE_OBJECT_MEDIA_CAP_URL_503,
+ FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL));
+ int num_refs_start = o->getNumRefs();
+ {
+ const int NUM_RETRIES = 5;
+ LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(0,0,NUM_RETRIES);
+
+ // This should generate a retry
+ mdc->fetchMedia(o);
+
+ // Make sure no posts happened yet...
+ ensure("post records before", gPostRecords->size(), 0);
+
+ // Once, causes retry
+ // Second, fires retry timer
+ // Third, fires queue timer again
+ for (int i=0; i<NUM_RETRIES; ++i)
+ {
+ LLEventTimer::updateClass();
+ ensure("post records " + STR(i), gPostRecords->size(), i+1);
+ LLEventTimer::updateClass();
+ }
+
+ // Do some extre pumps to make sure no other timer work occurs.
+ LLEventTimer::updateClass();
+ LLEventTimer::updateClass();
+ LLEventTimer::updateClass();
+
+ // Make sure there were 2 posts
+ ensure("post records after", gPostRecords->size(), NUM_RETRIES);
+ for (int i=0; i<NUM_RETRIES; ++i)
+ {
+ ensure("[" + STR(i) + "] post url", (*gPostRecords)[i]["url"], FAKE_OBJECT_MEDIA_CAP_URL_503);
+ ensure("[" + STR(i) + "] post GET", (*gPostRecords)[i]["body"]["verb"], "GET");
+ ensure("[" + STR(i) + "] post object id", (*gPostRecords)[i]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+ }
+ ensure("queue empty", mdc->isEmpty());
+ }
+
+ // Make sure everyone's destroyed properly
+ ensure("REF COUNT", o->getNumRefs(), num_refs_start);
+ }
+
+ template<> template<>
+ void mediadataclient_object_t::test<6>()
+ {
+ //
+ // Test navigate() with a bounce back
+ //
+ LOG_TEST(6);
+
+ LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(
+ _DATA_URLS(VALID_OBJECT_ID,
+ "1.0",
+ "1.0",
+ FAKE_OBJECT_MEDIA_CAP_URL,
+ FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR));
+ {
+ LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(0,0,4);
+ const char *TEST_URL = "http://example.com";
+ mdc->navigate(o, 0, TEST_URL);
+ ensure("post records", gPostRecords->size(), 0);
+ LLEventTimer::updateClass();
+
+ // ensure bounce back
+ ensure("bounce back",
+ dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o))->getNumBounceBacks(),
+ 1);
+
+ ensure("post records", gPostRecords->size(), 1);
+ ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR);
+ ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
+ ensure("post data", (*gPostRecords)[0]["body"][LLTextureEntry::TEXTURE_INDEX_KEY], 0);
+ ensure("post data", (*gPostRecords)[0]["body"][LLMediaEntry::CURRENT_URL_KEY], TEST_URL);
+ ensure("queue empty", mdc->isEmpty());
+ }
+ ensure("REF COUNT", o->getNumRefs(), 1);
+ }
+
+
+}