PageRenderTime 100ms CodeModel.GetById 2ms app.highlight 79ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/tests/llmediadataclient_test.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 969 lines | 655 code | 172 blank | 142 comment | 13 complexity | fc5583cbae6fde9be041afb7a14aeb85 MD5 | raw file
  1/** 
  2 * @file llmediadataclient_test.cpp
  3 * @brief LLMediaDatClient tests
  4 *
  5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "linden_common.h"
 28#include "../llviewerprecompiledheaders.h"
 29 
 30#include <iostream>
 31#include "../test/lltut.h"
 32
 33#include "llsdserialize.h"
 34#include "llsdutil.h"
 35#include "llerrorcontrol.h"
 36#include "llhttpstatuscodes.h"
 37
 38#include "../llmediadataclient.h"
 39#include "../llvovolume.h"
 40
 41#include "../../llprimitive/llmediaentry.cpp"
 42#include "../../llprimitive/lltextureentry.cpp"
 43#include "../../llmessage/tests/llcurl_stub.cpp"
 44
 45#if LL_WINDOWS
 46#pragma warning (push)
 47#pragma warning (disable : 4702) // boost::lexical_cast generates this warning
 48#endif
 49#include <boost/lexical_cast.hpp>
 50#if LL_WINDOWS
 51#pragma warning (pop)
 52#endif
 53
 54#define VALID_OBJECT_ID   "3607d5c4-644b-4a8a-871a-8b78471af2a2"
 55#define VALID_OBJECT_ID_1 "11111111-1111-1111-1111-111111111111"
 56#define VALID_OBJECT_ID_2 "22222222-2222-2222-2222-222222222222"
 57#define VALID_OBJECT_ID_3 "33333333-3333-3333-3333-333333333333"
 58#define VALID_OBJECT_ID_4 "44444444-4444-4444-4444-444444444444"
 59
 60#define FAKE_OBJECT_MEDIA_CAP_URL "foo_ObjectMedia"
 61#define FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL "foo_ObjectMediaNavigate"
 62#define FAKE_OBJECT_MEDIA_CAP_URL_503 "foo_ObjectMedia_503"
 63#define FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR "foo_ObjectMediaNavigate_ERROR"
 64
 65#define MEDIA_DATA "\
 66<array>														\
 67<string>http://foo.example.com</string>										\
 68<string>http://bar.example.com</string>										\
 69<string>baz</string>										\
 70</array>"
 71
 72#define _DATA_URLS(ID,INTEREST,NEW,URL1,URL2) "					\
 73<llsd>											\
 74  <map>											\
 75    <key>uuid</key>								\
 76    <string>" ID "</string>						\
 77    <key>interest</key>											\
 78    <real>" INTEREST "</real>											\
 79    <key>cap_urls</key>											\
 80    <map>														\
 81      <key>ObjectMedia</key>									\
 82      <string>" URL1 "</string>			\
 83      <key>ObjectMediaNavigate</key>							\
 84      <string>" URL2 "</string>	\
 85    </map>														\
 86    <key>media_data</key>                                       \
 87	" MEDIA_DATA "												\
 88    <key>is_dead</key>											\
 89	<boolean>false</boolean>									\
 90	<key>is_new</key>											\
 91	<boolean>" NEW "</boolean>									\
 92  </map>														\
 93</llsd>"
 94
 95#define _DATA(ID,INTEREST,NEW) _DATA_URLS(ID,INTEREST,NEW,FAKE_OBJECT_MEDIA_CAP_URL,FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL)
 96
 97const char *DATA = _DATA(VALID_OBJECT_ID,"1.0","true");
 98	
 99#define STR(I) boost::lexical_cast<std::string>(I)
100
101#define LOG_TEST(N) LL_DEBUGS("LLMediaDataClient") << "\n" <<			\
102"================================================================================\n" << \
103"==================================== TEST " #N " ===================================\n" << \
104"================================================================================\n" << LL_ENDL;
105
106LLSD *gPostRecords = NULL;
107F64   gMinimumInterestLevel = (F64)0.0;
108
109// stubs:
110void LLHTTPClient::post(
111		const std::string& url,
112		const LLSD& body,
113		LLHTTPClient::ResponderPtr responder,
114		const LLSD& headers,
115		const F32 timeout)
116{
117	LLSD record;
118	record["url"] = url;
119	record["body"] = body;
120	record["headers"] = headers;
121	record["timeout"] = timeout;
122	gPostRecords->append(record);
123	
124	// Magic URL that triggers a 503:
125	LLSD result;
126	result[LLTextureEntry::OBJECT_ID_KEY] = body[LLTextureEntry::OBJECT_ID_KEY];
127	if ( url == FAKE_OBJECT_MEDIA_CAP_URL_503 )
128	{
129		responder->error(HTTP_SERVICE_UNAVAILABLE, "fake reason");
130		return;
131	}
132	else if (url == FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR) 
133	{
134		LLSD error;
135		error["code"] = LLObjectMediaNavigateClient::ERROR_PERMISSION_DENIED_CODE;
136		result["error"] = error;
137	}	
138	responder->result(result);
139}
140
141const F32 HTTP_REQUEST_EXPIRY_SECS = 60.0f;
142
143class LLMediaDataClientObjectTest : public LLMediaDataClientObject
144{
145public:
146	LLMediaDataClientObjectTest(const char *data) 
147		{
148			std::istringstream d(data);
149			LLSDSerialize::fromXML(mRep, d);
150			mNumBounceBacks = 0;
151            
152           // std::cout << ll_pretty_print_sd(mRep) << std::endl;
153           // std::cout << "ID: " << getID() << std::endl;
154		}
155	LLMediaDataClientObjectTest(const LLSD &rep) 
156		: mRep(rep), mNumBounceBacks(0) {}
157	~LLMediaDataClientObjectTest()
158		{ LL_DEBUGS("LLMediaDataClient") << "~LLMediaDataClientObjectTest" << LL_ENDL; }
159	
160	virtual U8 getMediaDataCount() const 
161		{ return mRep["media_data"].size(); }
162	virtual LLSD getMediaDataLLSD(U8 index) const
163		{ return mRep["media_data"][(LLSD::Integer)index]; }
164	virtual bool isCurrentMediaUrl(U8 index, const std::string &url) const
165		{ return (mRep["media_data"][(LLSD::Integer)index].asString() == url); }
166	virtual LLUUID getID() const 
167		{ return mRep["uuid"]; }
168	virtual void mediaNavigateBounceBack(U8 index)
169		{ mNumBounceBacks++; }	
170	
171	virtual bool hasMedia() const
172		{ return mRep.has("media_data"); }
173	
174	virtual void updateObjectMediaData(LLSD const &media_data_array, const std::string &media_version)
175		{ mRep["media_data"] = media_data_array; mRep["media_version"] = media_version; }
176		
177	virtual F64 getMediaInterest() const
178		{ return (LLSD::Real)mRep["interest"]; }
179	
180	virtual bool isInterestingEnough() const
181		{ return getMediaInterest() > gMinimumInterestLevel; }
182	
183	virtual std::string getCapabilityUrl(const std::string &name) const 
184		{ return mRep["cap_urls"][name]; }
185
186	virtual bool isDead() const
187		{ return mRep["is_dead"]; }
188	
189	virtual U32 getMediaVersion() const
190		{ return (LLSD::Integer)mRep["media_version"]; }
191	
192	virtual bool isNew() const
193		{ return mRep["is_new"]; }
194	
195	void setMediaInterest(F64 val)
196		{ mRep["interest"] = val; }
197
198	int getNumBounceBacks() const
199		{ return mNumBounceBacks; }
200	
201	void markDead()
202		{ mRep["is_dead"] = true; }
203	
204	void markOld()
205		{ mRep["is_new"] = false; }
206	
207private:
208	LLSD mRep;
209	int mNumBounceBacks;
210};
211
212// This special timer delay should ensure that the timer will fire on the very
213// next pump, no matter what (though this does make an assumption about the
214// implementation of LLEventTimer::updateClass()):
215const F32 NO_PERIOD = -1000.0f;
216
217static void pump_timers()
218{
219	LLEventTimer::updateClass();
220}
221
222namespace tut
223{
224    struct mediadataclient
225    {
226		mediadataclient() {
227			gPostRecords = &mLLSD;
228			gMinimumInterestLevel = (F64)0.0;
229			
230// 			LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
231// 			LLError::setClassLevel("LLMediaDataClient", LLError::LEVEL_DEBUG);
232//			LLError::setTagLevel("MediaOnAPrim", LLError::LEVEL_DEBUG);
233		}
234		LLSD mLLSD;
235    };
236    
237	typedef test_group<mediadataclient> mediadataclient_t;
238	typedef mediadataclient_t::object mediadataclient_object_t;
239	tut::mediadataclient_t tut_mediadataclient("LLMediaDataClient");
240    
241    void ensure(const std::string &msg, int value, int expected)
242    {
243        std::string m = msg;
244        m += " value: " + STR(value);
245        m += ", expected: " + STR(expected);
246        ensure(m, value == expected);
247    }
248    
249    void ensure(const std::string &msg, const std::string & value, const std::string & expected)
250    {
251        std::string m = msg;
252        m += " value: " + value;
253        m += ", expected: " + expected;
254        ensure(m, value == expected);
255    }
256    
257    void ensure(const std::string &msg, const LLUUID & value, const LLUUID & expected)
258    {
259        std::string m = msg;
260        m += " value: " + value.asString();
261        m += ", expected: " + expected.asString();
262        ensure(m, value == expected);
263    }
264    
265    void ensure_llsd(const std::string &msg, const LLSD & value, const char *expected)
266    {
267        LLSD expected_llsd;
268        std::istringstream e(expected);
269        LLSDSerialize::fromXML(expected_llsd, e);
270   
271        std::string value_str = ll_pretty_print_sd(value);
272        std::string expected_str = ll_pretty_print_sd(expected_llsd);
273        std::string m = msg;
274        m += " value: " + value_str;
275        m += ", expected: " + expected_str;
276        ensure(m, value_str == expected_str);
277    }
278
279	//////////////////////////////////////////////////////////////////////////////////////////
280	
281	template<> template<>
282	void mediadataclient_object_t::test<1>()
283	{
284		//
285		// Test fetchMedia()
286		//
287		LOG_TEST(1);
288		
289		LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
290		int num_refs_start = o->getNumRefs();
291		{
292			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
293			mdc->fetchMedia(o);
294
295			// Make sure no posts happened yet...
296			ensure("post records", gPostRecords->size(), 0);
297
298			::pump_timers();
299		
300			ensure("post records", gPostRecords->size(), 1);
301			ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
302			ensure("post GET", (*gPostRecords)[0]["body"]["verb"], "GET");
303			ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
304			ensure("queue empty", mdc->isEmpty());
305		}
306		
307		// Make sure everyone's destroyed properly
308		ensure("REF COUNT", o->getNumRefs(), num_refs_start);
309    }
310
311	//////////////////////////////////////////////////////////////////////////////////////////
312
313	template<> template<>
314	void mediadataclient_object_t::test<2>()
315	{
316		//
317		// Test updateMedia()
318		//
319		LOG_TEST(2);
320
321		LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
322		{
323			// queue time w/ no delay ensures that ::pump_timers() will hit the tick()
324			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);  
325			mdc->updateMedia(o);
326			ensure("post records", gPostRecords->size(), 0);
327			::pump_timers();
328		
329			ensure("post records", gPostRecords->size(), 1);
330			ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
331			ensure("post UPDATE", (*gPostRecords)[0]["body"]["verb"], "UPDATE");
332			ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
333			ensure_llsd("post data llsd", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_MEDIA_DATA_KEY], 
334						"<llsd>" MEDIA_DATA "</llsd>");
335			ensure("queue empty", mdc->isEmpty());
336		}
337
338		ensure("REF COUNT", o->getNumRefs(), 1);
339	}
340
341	//////////////////////////////////////////////////////////////////////////////////////////
342
343    template<> template<>
344    void mediadataclient_object_t::test<3>()
345    {
346		//
347		// Test navigate()
348		//
349		LOG_TEST(3);
350
351		LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
352		{		
353			LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(NO_PERIOD,NO_PERIOD);
354			const char *TEST_URL = "http://example.com";
355			mdc->navigate(o, 0, TEST_URL);
356			ensure("post records", gPostRecords->size(), 0);
357			::pump_timers();
358
359			// ensure no bounce back
360			ensure("bounce back", dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o))->getNumBounceBacks(), 0);
361		
362			ensure("post records", gPostRecords->size(), 1);
363			ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL);
364			ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
365			ensure("post data", (*gPostRecords)[0]["body"][LLTextureEntry::TEXTURE_INDEX_KEY], 0);
366			ensure("post data", (*gPostRecords)[0]["body"][LLMediaEntry::CURRENT_URL_KEY], TEST_URL);
367			ensure("queue empty", mdc->isEmpty());
368		}
369		ensure("REF COUNT", o->getNumRefs(), 1);
370    }
371	
372	//////////////////////////////////////////////////////////////////////////////////////////
373
374    template<> template<>
375    void mediadataclient_object_t::test<4>()
376    {
377		//
378		// Test queue ordering
379		//
380		LOG_TEST(4);
381
382		LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(
383			_DATA(VALID_OBJECT_ID_1,"1.0","true"));
384		LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(
385			_DATA(VALID_OBJECT_ID_2,"3.0","true"));
386		LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(
387			_DATA(VALID_OBJECT_ID_3,"2.0","true"));
388		{
389			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);  
390			const char *ORDERED_OBJECT_IDS[] = { VALID_OBJECT_ID_2, VALID_OBJECT_ID_3, VALID_OBJECT_ID_1 };
391			mdc->fetchMedia(o1);
392			mdc->fetchMedia(o2);
393			mdc->fetchMedia(o3);
394
395			// Make sure no posts happened yet...
396			ensure("post records", gPostRecords->size(), 0);
397
398			// tick 3 times...
399			::pump_timers();
400			ensure("post records", gPostRecords->size(), 1);
401			::pump_timers();
402			ensure("post records", gPostRecords->size(), 2);
403			::pump_timers();
404			ensure("post records", gPostRecords->size(), 3);
405		
406			for( int i=0; i < 3; i++ )
407			{
408				ensure("[" + STR(i) + "] post url", (*gPostRecords)[i]["url"], FAKE_OBJECT_MEDIA_CAP_URL);
409				ensure("[" + STR(i) + "] post GET", (*gPostRecords)[i]["body"]["verb"], "GET");
410				ensure("[" + STR(i) + "] post object id", (*gPostRecords)[i]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), 
411					   LLUUID(ORDERED_OBJECT_IDS[i]));
412			}
413
414			ensure("queue empty", mdc->isEmpty());
415		}
416		ensure("refcount of o1", o1->getNumRefs(), 1);
417		ensure("refcount of o2", o2->getNumRefs(), 1);
418		ensure("refcount of o3", o3->getNumRefs(), 1);
419    }
420
421	//////////////////////////////////////////////////////////////////////////////////////////
422
423	template<> template<>
424	void mediadataclient_object_t::test<5>()
425	{
426		//
427		// Test fetchMedia() getting a 503 error
428		//
429		LOG_TEST(5);
430		
431		LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(
432			_DATA_URLS(VALID_OBJECT_ID,
433					   "1.0","true",
434					   FAKE_OBJECT_MEDIA_CAP_URL_503,
435					   FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL));
436		int num_refs_start = o->getNumRefs();
437		{
438			const int NUM_RETRIES = 5;
439			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD,NUM_RETRIES);
440
441			// This should generate a retry
442			mdc->fetchMedia(o);
443
444			// Make sure no posts happened yet...
445			ensure("post records before", gPostRecords->size(), 0);
446
447			// Once, causes retry
448			// Second, fires retry timer
449			// Third, fires queue timer again
450			for (int i=0; i<NUM_RETRIES; ++i)
451			{
452				::pump_timers();  // Should pump (fire) the queue timer, causing a retry timer to be scheduled
453				// XXX This ensure is not guaranteed, because scheduling a timer might actually get it pumped in the same loop
454				//ensure("post records " + STR(i), gPostRecords->size(), i+1);
455				::pump_timers();  // Should pump (fire) the retry timer, scheduling the queue timer
456			}
457
458			// Do some extra pumps to make sure no other timer work occurs.
459			::pump_timers();
460			::pump_timers();
461			::pump_timers();
462			
463			// Make sure there were 2 posts
464			ensure("post records after", gPostRecords->size(), NUM_RETRIES);
465			for (int i=0; i<NUM_RETRIES; ++i)
466			{
467				ensure("[" + STR(i) + "] post url", (*gPostRecords)[i]["url"], FAKE_OBJECT_MEDIA_CAP_URL_503);
468				ensure("[" + STR(i) + "] post GET", (*gPostRecords)[i]["body"]["verb"], "GET");
469				ensure("[" + STR(i) + "] post object id", (*gPostRecords)[i]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
470			}
471			ensure("queue empty", mdc->isEmpty());
472		}
473		
474		// Make sure everyone's destroyed properly
475		ensure("REF COUNT", o->getNumRefs(), num_refs_start);
476    }
477
478    template<> template<>
479    void mediadataclient_object_t::test<6>()
480    {
481		//
482		// Test navigate() with a bounce back
483		//
484		LOG_TEST(6);
485
486		LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(
487			_DATA_URLS(VALID_OBJECT_ID,
488					   "1.0","true",
489					   FAKE_OBJECT_MEDIA_CAP_URL,
490					   FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR));
491		{		
492			LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(NO_PERIOD,NO_PERIOD);
493			const char *TEST_URL = "http://example.com";
494			mdc->navigate(o, 0, TEST_URL);
495			ensure("post records", gPostRecords->size(), 0);
496			::pump_timers();
497
498			// ensure bounce back
499			ensure("bounce back", 
500				   dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o))->getNumBounceBacks(),
501				   1);
502			
503			ensure("post records", gPostRecords->size(), 1);
504			ensure("post url", (*gPostRecords)[0]["url"], FAKE_OBJECT_MEDIA_NAVIGATE_CAP_URL_ERROR);
505			ensure("post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID));
506			ensure("post data", (*gPostRecords)[0]["body"][LLTextureEntry::TEXTURE_INDEX_KEY], 0);
507			ensure("post data", (*gPostRecords)[0]["body"][LLMediaEntry::CURRENT_URL_KEY], TEST_URL);
508			ensure("queue empty", mdc->isEmpty());
509		}
510		ensure("REF COUNT", o->getNumRefs(), 1);
511    }
512
513	template<> template<>
514    void mediadataclient_object_t::test<7>()
515    {
516		// Test LLMediaDataClient::isInQueue()
517		LOG_TEST(7);
518		
519		LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(
520			_DATA(VALID_OBJECT_ID_1,"3.0","true"));
521		LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(
522			_DATA(VALID_OBJECT_ID_2,"1.0","true"));
523		int num_refs_start = o1->getNumRefs();
524		{
525			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
526			
527			ensure("not in queue yet 1", ! mdc->isInQueue(o1));
528			ensure("not in queue yet 2", ! mdc->isInQueue(o2));
529			
530			mdc->fetchMedia(o1);
531			
532			ensure("is in queue", mdc->isInQueue(o1));
533			ensure("is not in queue", ! mdc->isInQueue(o2));
534			
535			::pump_timers();
536			
537			ensure("not in queue anymore", ! mdc->isInQueue(o1));
538			ensure("still is not in queue", ! mdc->isInQueue(o2));
539			
540			ensure("queue empty", mdc->isEmpty());
541		}
542		
543		// Make sure everyone's destroyed properly
544		ensure("REF COUNT", o1->getNumRefs(), num_refs_start);
545		
546	}
547
548	template<> template<>
549    void mediadataclient_object_t::test<8>()
550    {
551		// Test queue handling of objects that are marked dead.
552		LOG_TEST(8);
553		
554		LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_1,"4.0","true"));
555		LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_2,"3.0","true"));
556		LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_3,"2.0","true"));
557		LLMediaDataClientObject::ptr_t o4 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_4,"1.0","true"));
558		{
559			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
560			
561			// queue up all 4 objects
562			mdc->fetchMedia(o1);
563			mdc->fetchMedia(o2);
564			mdc->fetchMedia(o3);
565			mdc->fetchMedia(o4);
566
567			ensure("is in queue 1", mdc->isInQueue(o1));
568			ensure("is in queue 2", mdc->isInQueue(o2));
569			ensure("is in queue 3", mdc->isInQueue(o3));
570			ensure("is in queue 4", mdc->isInQueue(o4));
571			ensure("post records", gPostRecords->size(), 0);
572			
573			// and mark the second and fourth ones dead.  Call removeFromQueue when marking dead, since this is what LLVOVolume will do.
574			dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o2))->markDead();
575			mdc->removeFromQueue(o2);
576			dynamic_cast<LLMediaDataClientObjectTest*>(static_cast<LLMediaDataClientObject*>(o4))->markDead();
577			mdc->removeFromQueue(o4);
578
579			// The removeFromQueue calls should remove the second and fourth ones
580			ensure("is in queue 1", mdc->isInQueue(o1));
581			ensure("is not in queue 2", !mdc->isInQueue(o2));
582			ensure("is in queue 3", mdc->isInQueue(o3));
583			ensure("is not in queue 4", !mdc->isInQueue(o4));
584			ensure("post records", gPostRecords->size(), 0);
585			
586			::pump_timers();
587			
588			// The first tick should process the first item
589			ensure("is not in queue 1", !mdc->isInQueue(o1));
590			ensure("is not in queue 2", !mdc->isInQueue(o2));
591			ensure("is in queue 3", mdc->isInQueue(o3));
592			ensure("is not in queue 4", !mdc->isInQueue(o4));
593			ensure("post records", gPostRecords->size(), 1);
594			
595			::pump_timers();
596			
597			// The second tick should process the third, emptying the queue
598			ensure("is not in queue 3", !mdc->isInQueue(o3));
599			ensure("post records", gPostRecords->size(), 2);
600
601			ensure("queue empty", mdc->isEmpty());
602		}
603		ensure("refcount of o1", o1->getNumRefs(), 1);
604		ensure("refcount of o2", o2->getNumRefs(), 1);
605		ensure("refcount of o3", o3->getNumRefs(), 1);
606		ensure("refcount of o4", o4->getNumRefs(), 1);
607
608	}
609	
610	//////////////////////////////////////////////////////////////////////////////////////////
611
612    template<> template<>
613    void mediadataclient_object_t::test<9>()
614    {
615		//
616		// Test queue re-ordering
617		//
618		LOG_TEST(9);
619		
620		LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_1,"40.0","true"));
621		LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_2,"30.0","true"));
622		LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_3,"20.0","true"));
623		LLMediaDataClientObjectTest *object4 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_4,"10.0","true"));
624		LLMediaDataClientObject::ptr_t o4 = object4;
625		{
626			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
627			
628			// queue up all 4 objects.  They should now be in the queue in
629			// order 1 through 4, with 4 being at the front of the queue
630			mdc->fetchMedia(o1);
631			mdc->fetchMedia(o2);
632			mdc->fetchMedia(o3);
633			mdc->fetchMedia(o4);
634			
635			int tick_num = 0;
636			
637			ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
638			ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
639			ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
640			ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
641			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 0);
642			
643			::pump_timers();
644			++tick_num;
645			
646			// The first tick should remove the first one 
647			ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
648			ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
649			ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
650			ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
651			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 1);
652			
653			// Now, pretend that object 4 moved relative to the avatar such
654			// that it is now closest
655			object4->setMediaInterest(50.0);
656			
657			::pump_timers();
658			++tick_num;
659			
660			// The second tick should still pick off item 2, but then re-sort
661			// have picked off object 4
662			ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
663			ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
664			ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
665			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 2);
666
667			::pump_timers();
668			++tick_num;
669			
670			// The third tick should pick off object 2
671			ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
672			ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
673			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 3);
674
675			// The fourth tick should pick off object 3
676			::pump_timers();
677			++tick_num;
678
679			ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
680			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 4);
681
682			ensure("queue empty", mdc->isEmpty());
683		}
684		ensure("refcount of o1", o1->getNumRefs(), 1);
685		ensure("refcount of o2", o2->getNumRefs(), 1);
686		ensure("refcount of o3", o3->getNumRefs(), 1);
687		ensure("refcount of o4", o4->getNumRefs(), 1);
688    }
689	
690	
691	template<> template<>
692    void mediadataclient_object_t::test<10>()
693    {
694		//
695		// Test using the "round-robin" queue
696		//
697		LOG_TEST(10);
698		
699		LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_1,"1.0","true"));
700		LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_2,"2.0","true"));
701		LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_3,"3.0","false"));
702		LLMediaDataClientObject::ptr_t o4 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_4,"4.0","false"));
703		{
704			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
705			
706			// queue up all 4 objects.  The first two should be in the sorted
707			// queue [2 1], the second in the round-robin queue.  The queues
708			// are serviced interleaved, so we should expect:
709			// 2, 3, 1, 4
710			mdc->fetchMedia(o1);
711			mdc->fetchMedia(o2);
712			mdc->fetchMedia(o3);
713			mdc->fetchMedia(o4);
714			
715			int tick_num = 0;
716			
717			// 0
718			ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
719			ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
720			ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
721			ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
722			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 0);
723			
724			::pump_timers();
725			++tick_num;
726			
727			// 1 The first tick should remove object 2
728			ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
729			ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
730			ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
731			ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
732			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 1);
733			ensure(STR(tick_num) + ". post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_2));
734			
735			::pump_timers();
736			++tick_num;
737			
738			// 2 The second tick should send object 3
739			ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
740			ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
741			ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
742			ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
743			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 2);
744			ensure(STR(tick_num) + ". post object id", (*gPostRecords)[1]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_3));
745			
746			::pump_timers();
747			++tick_num;
748			
749			// 3 The third tick should remove object 1
750			ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
751			ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
752			ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
753			ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
754			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 3);
755			ensure(STR(tick_num) + ". post object id", (*gPostRecords)[2]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_1));
756			
757			::pump_timers();
758			++tick_num;
759			
760			// 4 The fourth tick should send object 4
761			ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
762			ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
763			ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
764			ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
765			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 4);
766			ensure(STR(tick_num) + ". post object id", (*gPostRecords)[3]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_4));
767			
768			::pump_timers();
769			++tick_num;
770						
771			// 5 The fifth tick should not change the state of anything.
772			ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
773			ensure(STR(tick_num) + ". is not in queue 2", !mdc->isInQueue(o2));
774			ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
775			ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
776			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 4);
777			
778			::pump_timers();
779			
780			// Whew....better be empty
781			ensure("queue empty", mdc->isEmpty());
782		}
783		ensure("refcount of o1", o1->getNumRefs(), 1);
784		ensure("refcount of o2", o2->getNumRefs(), 1);
785		ensure("refcount of o3", o3->getNumRefs(), 1);
786		ensure("refcount of o4", o4->getNumRefs(), 1);		
787	}
788	
789	
790	template<> template<>
791	void mediadataclient_object_t::test<11>()
792	{
793		//
794		// Test LLMediaDataClient's destructor
795		//
796		LOG_TEST(11);
797		
798		LLMediaDataClientObject::ptr_t o = new LLMediaDataClientObjectTest(DATA);
799		int num_refs_start = o->getNumRefs();
800		{
801			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
802			mdc->fetchMedia(o);
803			// must tick enough times to clear refcount of mdc
804			::pump_timers();
805		}		
806		// Make sure everyone's destroyed properly
807		ensure("REF COUNT", o->getNumRefs(), num_refs_start);
808	}
809	
810	template<> template<>
811    void mediadataclient_object_t::test<12>()
812    {
813		//
814		// Test the "not interesting enough" call
815		//
816		LOG_TEST(12);
817		
818		LLMediaDataClientObjectTest *object1 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_1,"1.0","true"));
819		LLMediaDataClientObject::ptr_t o1 = object1;
820		LLMediaDataClientObject::ptr_t o2 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_2,"2.0","true"));
821		LLMediaDataClientObject::ptr_t o3 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_3,"3.0","true"));
822		LLMediaDataClientObject::ptr_t o4 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_4,"4.0","true"));
823		{
824			LLPointer<LLObjectMediaDataClient> mdc = new LLObjectMediaDataClient(NO_PERIOD,NO_PERIOD);
825			
826			// queue up all 4 objects.  The first two are "interesting enough".
827			// Firing the timer 4 times should therefore leave them.
828			// Note that they should be sorted 4,3,2,1
829			// Then, we'll make one "interesting enough", fire the timer a few 
830			// times, and make sure only it gets pulled off the queue
831			gMinimumInterestLevel = 2.5;
832			mdc->fetchMedia(o1);
833			mdc->fetchMedia(o2);
834			mdc->fetchMedia(o3);
835			mdc->fetchMedia(o4);
836			
837			int tick_num = 0;
838			
839			// 0
840			ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
841			ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
842			ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
843			ensure(STR(tick_num) + ". is in queue 4", mdc->isInQueue(o4));
844			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 0);
845			
846			::pump_timers();
847			++tick_num;
848			
849			// 1 The first tick should remove object 4
850			ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
851			ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
852			ensure(STR(tick_num) + ". is in queue 3", mdc->isInQueue(o3));
853			ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
854			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 1);
855			ensure(STR(tick_num) + ". post object id", (*gPostRecords)[0]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_4));
856			
857			::pump_timers();
858			++tick_num;
859			
860			// 2 The second tick should send object 3
861			ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
862			ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
863			ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
864			ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
865			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 2);
866			ensure(STR(tick_num) + ". post object id", (*gPostRecords)[1]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_3));
867			
868			::pump_timers();
869			++tick_num;
870			
871			// 3 The third tick should not pull off anything
872			ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
873			ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
874			ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
875			ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
876			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 2);
877
878			::pump_timers();
879			++tick_num;
880			
881			// 4 The fourth tick (for good measure) should not pull off anything
882			ensure(STR(tick_num) + ". is in queue 1", mdc->isInQueue(o1));
883			ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
884			ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
885			ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
886			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 2);
887			
888			// Okay, now futz with object 1's interest, such that it is now 
889			// "interesting enough"
890			object1->setMediaInterest((F64)5.0);
891			
892			// This should sort so that the queue is now [1 2] 
893			::pump_timers();
894			++tick_num;
895			
896			// 5 The fifth tick should now identify objects 3 and 4 as no longer
897			// needing "updating", and remove them from the queue
898			ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
899			ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
900			ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
901			ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
902			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 3);
903			ensure(STR(tick_num) + ". post object id", (*gPostRecords)[2]["body"][LLTextureEntry::OBJECT_ID_KEY].asUUID(), LLUUID(VALID_OBJECT_ID_1));
904			
905			::pump_timers();
906			++tick_num;
907			
908			// 6 The sixth tick should not pull off anything
909			ensure(STR(tick_num) + ". is not in queue 1", !mdc->isInQueue(o1));
910			ensure(STR(tick_num) + ". is in queue 2", mdc->isInQueue(o2));
911			ensure(STR(tick_num) + ". is not in queue 3", !mdc->isInQueue(o3));
912			ensure(STR(tick_num) + ". is not in queue 4", !mdc->isInQueue(o4));
913			ensure(STR(tick_num) + ". post records", gPostRecords->size(), 3);
914			
915			::pump_timers();
916			++tick_num;
917		
918			// Whew....better NOT be empty ... o2 should still be there
919			ensure("queue not empty", !mdc->isEmpty());
920			
921			// But, we need to clear the queue, or else we won't destroy MDC...
922			// this is a strange interplay between the queue timer and the MDC
923			mdc->removeFromQueue(o2);
924			// tick
925			::pump_timers();
926		}
927		ensure("refcount of o1", o1->getNumRefs(), 1);
928		ensure("refcount of o2", o2->getNumRefs(), 1);
929		ensure("refcount of o3", o3->getNumRefs(), 1);
930		ensure("refcount of o4", o4->getNumRefs(), 1);		
931	}
932
933	template<> template<>
934	void mediadataclient_object_t::test<13>()
935	{
936		//
937		// Test supression of redundant navigates.
938		//
939		LOG_TEST(13);
940		
941		LLMediaDataClientObject::ptr_t o1 = new LLMediaDataClientObjectTest(_DATA(VALID_OBJECT_ID_1,"1.0","true"));
942		{
943			LLPointer<LLObjectMediaNavigateClient> mdc = new LLObjectMediaNavigateClient(NO_PERIOD,NO_PERIOD);
944			const char *TEST_URL = "http://foo.example.com";
945			const char *TEST_URL_2 = "http://example.com";
946			mdc->navigate(o1, 0, TEST_URL);
947			mdc->navigate(o1, 1, TEST_URL);
948			mdc->navigate(o1, 0, TEST_URL_2);
949			mdc->navigate(o1, 1, TEST_URL_2);
950			
951			// This should add two requests to the queue, one for face 0 of the object and one for face 1.
952			
953			ensure("before pump: 1 is in queue", mdc->isInQueue(o1));
954
955			::pump_timers();
956
957			ensure("after first pump: 1 is in queue", mdc->isInQueue(o1));
958
959			::pump_timers();
960
961			ensure("after second pump: 1 is not in queue", !mdc->isInQueue(o1));
962
963			ensure("first post has correct url", (*gPostRecords)[0]["body"][LLMediaEntry::CURRENT_URL_KEY].asString(), std::string(TEST_URL_2));
964			ensure("second post has correct url", (*gPostRecords)[1]["body"][LLMediaEntry::CURRENT_URL_KEY].asString(), std::string(TEST_URL_2));
965
966		}		
967	}
968	
969}