diff options
Diffstat (limited to 'indra/newview/tests')
-rw-r--r-- | indra/newview/tests/llsimplestat_test.cpp | 428 | ||||
-rw-r--r-- | indra/newview/tests/llviewerassetstats_test.cpp | 753 |
2 files changed, 1181 insertions, 0 deletions
diff --git a/indra/newview/tests/llsimplestat_test.cpp b/indra/newview/tests/llsimplestat_test.cpp new file mode 100644 index 0000000000..5efc9cf857 --- /dev/null +++ b/indra/newview/tests/llsimplestat_test.cpp @@ -0,0 +1,428 @@ +/** + * @file llsimplestats_test.cpp + * @date 2010-10-22 + * @brief Test cases for some of llsimplestat.h + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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 "linden_common.h" + +#include <tut/tut.hpp> + +#include "lltut.h" +#include "../llsimplestat.h" +#include "llsd.h" +#include "llmath.h" + +// @brief Used as a pointer cast type to get access to LLSimpleStatCounter +class TutStatCounter: public LLSimpleStatCounter +{ +public: + TutStatCounter(); // Not defined + ~TutStatCounter(); // Not defined + void operator=(const TutStatCounter &); // Not defined + + void setRawCount(U32 c) { mCount = c; } + U32 getRawCount() const { return mCount; } +}; + + +namespace tut +{ + struct stat_counter_index + {}; + typedef test_group<stat_counter_index> stat_counter_index_t; + typedef stat_counter_index_t::object stat_counter_index_object_t; + tut::stat_counter_index_t tut_stat_counter_index("stat_counter_test"); + + // Testing LLSimpleStatCounter's external interface + template<> template<> + void stat_counter_index_object_t::test<1>() + { + LLSimpleStatCounter c1; + ensure("Initialized counter is zero", (0 == c1.getCount())); + + ensure("Counter increment return is 1", (1 == ++c1)); + ensure("Counter increment return is 2", (2 == ++c1)); + + ensure("Current counter is 2", (2 == c1.getCount())); + + c1.reset(); + ensure("Counter is 0 after reset", (0 == c1.getCount())); + + ensure("Counter increment return is 1", (1 == ++c1)); + } + + // Testing LLSimpleStatCounter's internal state + template<> template<> + void stat_counter_index_object_t::test<2>() + { + LLSimpleStatCounter c1; + TutStatCounter * tc1 = (TutStatCounter *) &c1; + + ensure("Initialized private counter is zero", (0 == tc1->getRawCount())); + + ++c1; + ++c1; + + ensure("Current private counter is 2", (2 == tc1->getRawCount())); + + c1.reset(); + ensure("Raw counter is 0 after reset", (0 == tc1->getRawCount())); + } + + // Testing LLSimpleStatCounter's wrapping behavior + template<> template<> + void stat_counter_index_object_t::test<3>() + { + LLSimpleStatCounter c1; + TutStatCounter * tc1 = (TutStatCounter *) &c1; + + tc1->setRawCount(U32_MAX); + ensure("Initialized private counter is zero", (U32_MAX == c1.getCount())); + + ensure("Increment of max value wraps to 0", (0 == ++c1)); + } + + // Testing LLSimpleStatMMM's external behavior + template<> template<> + void stat_counter_index_object_t::test<4>() + { + LLSimpleStatMMM<> m1; + typedef LLSimpleStatMMM<>::Value lcl_float; + lcl_float zero(0); + + // Freshly-constructed + ensure("Constructed MMM<> has 0 count", (0 == m1.getCount())); + ensure("Constructed MMM<> has 0 min", (zero == m1.getMin())); + ensure("Constructed MMM<> has 0 max", (zero == m1.getMax())); + ensure("Constructed MMM<> has 0 mean no div-by-zero", (zero == m1.getMean())); + + // Single insert + m1.record(1.0); + ensure("Single insert MMM<> has 1 count", (1 == m1.getCount())); + ensure("Single insert MMM<> has 1.0 min", (1.0 == m1.getMin())); + ensure("Single insert MMM<> has 1.0 max", (1.0 == m1.getMax())); + ensure("Single insert MMM<> has 1.0 mean", (1.0 == m1.getMean())); + + // Second insert + m1.record(3.0); + ensure("2nd insert MMM<> has 2 count", (2 == m1.getCount())); + ensure("2nd insert MMM<> has 1.0 min", (1.0 == m1.getMin())); + ensure("2nd insert MMM<> has 3.0 max", (3.0 == m1.getMax())); + ensure_approximately_equals("2nd insert MMM<> has 2.0 mean", m1.getMean(), lcl_float(2.0), 1); + + // Third insert + m1.record(5.0); + ensure("3rd insert MMM<> has 3 count", (3 == m1.getCount())); + ensure("3rd insert MMM<> has 1.0 min", (1.0 == m1.getMin())); + ensure("3rd insert MMM<> has 5.0 max", (5.0 == m1.getMax())); + ensure_approximately_equals("3rd insert MMM<> has 3.0 mean", m1.getMean(), lcl_float(3.0), 1); + + // Fourth insert + m1.record(1000000.0); + ensure("4th insert MMM<> has 4 count", (4 == m1.getCount())); + ensure("4th insert MMM<> has 1.0 min", (1.0 == m1.getMin())); + ensure("4th insert MMM<> has 100000.0 max", (1000000.0 == m1.getMax())); + ensure_approximately_equals("4th insert MMM<> has 250002.0 mean", m1.getMean(), lcl_float(250002.0), 1); + + // Reset + m1.reset(); + ensure("Reset MMM<> has 0 count", (0 == m1.getCount())); + ensure("Reset MMM<> has 0 min", (zero == m1.getMin())); + ensure("Reset MMM<> has 0 max", (zero == m1.getMax())); + ensure("Reset MMM<> has 0 mean no div-by-zero", (zero == m1.getMean())); + } + + // Testing LLSimpleStatMMM's response to large values + template<> template<> + void stat_counter_index_object_t::test<5>() + { + LLSimpleStatMMM<> m1; + typedef LLSimpleStatMMM<>::Value lcl_float; + lcl_float zero(0); + + // Insert overflowing values + const lcl_float bignum(F32_MAX / 2); + + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(zero); + + ensure("Overflowed MMM<> has 8 count", (8 == m1.getCount())); + ensure("Overflowed MMM<> has 0 min", (zero == m1.getMin())); + ensure("Overflowed MMM<> has huge max", (bignum == m1.getMax())); + ensure("Overflowed MMM<> has fetchable mean", (1.0 == m1.getMean() || true)); + // We should be infinte but not interested in proving the IEEE standard here. + LLSD sd1(m1.getMean()); + // std::cout << "Thingy: " << m1.getMean() << " and as LLSD: " << sd1 << std::endl; + ensure("Overflowed MMM<> produces LLSDable Real", (sd1.isReal())); + } + + // Testing LLSimpleStatMMM<F32>'s external behavior + template<> template<> + void stat_counter_index_object_t::test<6>() + { + LLSimpleStatMMM<F32> m1; + typedef LLSimpleStatMMM<F32>::Value lcl_float; + lcl_float zero(0); + + // Freshly-constructed + ensure("Constructed MMM<F32> has 0 count", (0 == m1.getCount())); + ensure("Constructed MMM<F32> has 0 min", (zero == m1.getMin())); + ensure("Constructed MMM<F32> has 0 max", (zero == m1.getMax())); + ensure("Constructed MMM<F32> has 0 mean no div-by-zero", (zero == m1.getMean())); + + // Single insert + m1.record(1.0); + ensure("Single insert MMM<F32> has 1 count", (1 == m1.getCount())); + ensure("Single insert MMM<F32> has 1.0 min", (1.0 == m1.getMin())); + ensure("Single insert MMM<F32> has 1.0 max", (1.0 == m1.getMax())); + ensure("Single insert MMM<F32> has 1.0 mean", (1.0 == m1.getMean())); + + // Second insert + m1.record(3.0); + ensure("2nd insert MMM<F32> has 2 count", (2 == m1.getCount())); + ensure("2nd insert MMM<F32> has 1.0 min", (1.0 == m1.getMin())); + ensure("2nd insert MMM<F32> has 3.0 max", (3.0 == m1.getMax())); + ensure_approximately_equals("2nd insert MMM<F32> has 2.0 mean", m1.getMean(), lcl_float(2.0), 1); + + // Third insert + m1.record(5.0); + ensure("3rd insert MMM<F32> has 3 count", (3 == m1.getCount())); + ensure("3rd insert MMM<F32> has 1.0 min", (1.0 == m1.getMin())); + ensure("3rd insert MMM<F32> has 5.0 max", (5.0 == m1.getMax())); + ensure_approximately_equals("3rd insert MMM<F32> has 3.0 mean", m1.getMean(), lcl_float(3.0), 1); + + // Fourth insert + m1.record(1000000.0); + ensure("4th insert MMM<F32> has 4 count", (4 == m1.getCount())); + ensure("4th insert MMM<F32> has 1.0 min", (1.0 == m1.getMin())); + ensure("4th insert MMM<F32> has 1000000.0 max", (1000000.0 == m1.getMax())); + ensure_approximately_equals("4th insert MMM<F32> has 250002.0 mean", m1.getMean(), lcl_float(250002.0), 1); + + // Reset + m1.reset(); + ensure("Reset MMM<F32> has 0 count", (0 == m1.getCount())); + ensure("Reset MMM<F32> has 0 min", (zero == m1.getMin())); + ensure("Reset MMM<F32> has 0 max", (zero == m1.getMax())); + ensure("Reset MMM<F32> has 0 mean no div-by-zero", (zero == m1.getMean())); + } + + // Testing LLSimpleStatMMM's response to large values + template<> template<> + void stat_counter_index_object_t::test<7>() + { + LLSimpleStatMMM<F32> m1; + typedef LLSimpleStatMMM<F32>::Value lcl_float; + lcl_float zero(0); + + // Insert overflowing values + const lcl_float bignum(F32_MAX / 2); + + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(zero); + + ensure("Overflowed MMM<F32> has 8 count", (8 == m1.getCount())); + ensure("Overflowed MMM<F32> has 0 min", (zero == m1.getMin())); + ensure("Overflowed MMM<F32> has huge max", (bignum == m1.getMax())); + ensure("Overflowed MMM<F32> has fetchable mean", (1.0 == m1.getMean() || true)); + // We should be infinte but not interested in proving the IEEE standard here. + LLSD sd1(m1.getMean()); + // std::cout << "Thingy: " << m1.getMean() << " and as LLSD: " << sd1 << std::endl; + ensure("Overflowed MMM<F32> produces LLSDable Real", (sd1.isReal())); + } + + // Testing LLSimpleStatMMM<F64>'s external behavior + template<> template<> + void stat_counter_index_object_t::test<8>() + { + LLSimpleStatMMM<F64> m1; + typedef LLSimpleStatMMM<F64>::Value lcl_float; + lcl_float zero(0); + + // Freshly-constructed + ensure("Constructed MMM<F64> has 0 count", (0 == m1.getCount())); + ensure("Constructed MMM<F64> has 0 min", (zero == m1.getMin())); + ensure("Constructed MMM<F64> has 0 max", (zero == m1.getMax())); + ensure("Constructed MMM<F64> has 0 mean no div-by-zero", (zero == m1.getMean())); + + // Single insert + m1.record(1.0); + ensure("Single insert MMM<F64> has 1 count", (1 == m1.getCount())); + ensure("Single insert MMM<F64> has 1.0 min", (1.0 == m1.getMin())); + ensure("Single insert MMM<F64> has 1.0 max", (1.0 == m1.getMax())); + ensure("Single insert MMM<F64> has 1.0 mean", (1.0 == m1.getMean())); + + // Second insert + m1.record(3.0); + ensure("2nd insert MMM<F64> has 2 count", (2 == m1.getCount())); + ensure("2nd insert MMM<F64> has 1.0 min", (1.0 == m1.getMin())); + ensure("2nd insert MMM<F64> has 3.0 max", (3.0 == m1.getMax())); + ensure_approximately_equals("2nd insert MMM<F64> has 2.0 mean", m1.getMean(), lcl_float(2.0), 1); + + // Third insert + m1.record(5.0); + ensure("3rd insert MMM<F64> has 3 count", (3 == m1.getCount())); + ensure("3rd insert MMM<F64> has 1.0 min", (1.0 == m1.getMin())); + ensure("3rd insert MMM<F64> has 5.0 max", (5.0 == m1.getMax())); + ensure_approximately_equals("3rd insert MMM<F64> has 3.0 mean", m1.getMean(), lcl_float(3.0), 1); + + // Fourth insert + m1.record(1000000.0); + ensure("4th insert MMM<F64> has 4 count", (4 == m1.getCount())); + ensure("4th insert MMM<F64> has 1.0 min", (1.0 == m1.getMin())); + ensure("4th insert MMM<F64> has 1000000.0 max", (1000000.0 == m1.getMax())); + ensure_approximately_equals("4th insert MMM<F64> has 250002.0 mean", m1.getMean(), lcl_float(250002.0), 1); + + // Reset + m1.reset(); + ensure("Reset MMM<F64> has 0 count", (0 == m1.getCount())); + ensure("Reset MMM<F64> has 0 min", (zero == m1.getMin())); + ensure("Reset MMM<F64> has 0 max", (zero == m1.getMax())); + ensure("Reset MMM<F64> has 0 mean no div-by-zero", (zero == m1.getMean())); + } + + // Testing LLSimpleStatMMM's response to large values + template<> template<> + void stat_counter_index_object_t::test<9>() + { + LLSimpleStatMMM<F64> m1; + typedef LLSimpleStatMMM<F64>::Value lcl_float; + lcl_float zero(0); + + // Insert overflowing values + const lcl_float bignum(F64_MAX / 2); + + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(zero); + + ensure("Overflowed MMM<F64> has 8 count", (8 == m1.getCount())); + ensure("Overflowed MMM<F64> has 0 min", (zero == m1.getMin())); + ensure("Overflowed MMM<F64> has huge max", (bignum == m1.getMax())); + ensure("Overflowed MMM<F64> has fetchable mean", (1.0 == m1.getMean() || true)); + // We should be infinte but not interested in proving the IEEE standard here. + LLSD sd1(m1.getMean()); + // std::cout << "Thingy: " << m1.getMean() << " and as LLSD: " << sd1 << std::endl; + ensure("Overflowed MMM<F64> produces LLSDable Real", (sd1.isReal())); + } + + // Testing LLSimpleStatMMM<U64>'s external behavior + template<> template<> + void stat_counter_index_object_t::test<10>() + { + LLSimpleStatMMM<U64> m1; + typedef LLSimpleStatMMM<U64>::Value lcl_int; + lcl_int zero(0); + + // Freshly-constructed + ensure("Constructed MMM<U64> has 0 count", (0 == m1.getCount())); + ensure("Constructed MMM<U64> has 0 min", (zero == m1.getMin())); + ensure("Constructed MMM<U64> has 0 max", (zero == m1.getMax())); + ensure("Constructed MMM<U64> has 0 mean no div-by-zero", (zero == m1.getMean())); + + // Single insert + m1.record(1); + ensure("Single insert MMM<U64> has 1 count", (1 == m1.getCount())); + ensure("Single insert MMM<U64> has 1 min", (1 == m1.getMin())); + ensure("Single insert MMM<U64> has 1 max", (1 == m1.getMax())); + ensure("Single insert MMM<U64> has 1 mean", (1 == m1.getMean())); + + // Second insert + m1.record(3); + ensure("2nd insert MMM<U64> has 2 count", (2 == m1.getCount())); + ensure("2nd insert MMM<U64> has 1 min", (1 == m1.getMin())); + ensure("2nd insert MMM<U64> has 3 max", (3 == m1.getMax())); + ensure("2nd insert MMM<U64> has 2 mean", (2 == m1.getMean())); + + // Third insert + m1.record(5); + ensure("3rd insert MMM<U64> has 3 count", (3 == m1.getCount())); + ensure("3rd insert MMM<U64> has 1 min", (1 == m1.getMin())); + ensure("3rd insert MMM<U64> has 5 max", (5 == m1.getMax())); + ensure("3rd insert MMM<U64> has 3 mean", (3 == m1.getMean())); + + // Fourth insert + m1.record(U64L(1000000000000)); + ensure("4th insert MMM<U64> has 4 count", (4 == m1.getCount())); + ensure("4th insert MMM<U64> has 1 min", (1 == m1.getMin())); + ensure("4th insert MMM<U64> has 1000000000000ULL max", (U64L(1000000000000) == m1.getMax())); + ensure("4th insert MMM<U64> has 250000000002ULL mean", (U64L( 250000000002) == m1.getMean())); + + // Reset + m1.reset(); + ensure("Reset MMM<U64> has 0 count", (0 == m1.getCount())); + ensure("Reset MMM<U64> has 0 min", (zero == m1.getMin())); + ensure("Reset MMM<U64> has 0 max", (zero == m1.getMax())); + ensure("Reset MMM<U64> has 0 mean no div-by-zero", (zero == m1.getMean())); + } + + // Testing LLSimpleStatMMM's response to large values + template<> template<> + void stat_counter_index_object_t::test<11>() + { + LLSimpleStatMMM<U64> m1; + typedef LLSimpleStatMMM<U64>::Value lcl_int; + lcl_int zero(0); + + // Insert overflowing values + const lcl_int bignum(U64L(0xffffffffffffffff) / 2); + + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(bignum); + m1.record(zero); + + ensure("Overflowed MMM<U64> has 8 count", (8 == m1.getCount())); + ensure("Overflowed MMM<U64> has 0 min", (zero == m1.getMin())); + ensure("Overflowed MMM<U64> has huge max", (bignum == m1.getMax())); + ensure("Overflowed MMM<U64> has fetchable mean", (zero == m1.getMean() || true)); + } +} diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp new file mode 100644 index 0000000000..153056b3cd --- /dev/null +++ b/indra/newview/tests/llviewerassetstats_test.cpp @@ -0,0 +1,753 @@ +/** + * @file llviewerassetstats_tut.cpp + * @date 2010-10-28 + * @brief Test cases for some of newview/llviewerassetstats.cpp + * + * $LicenseInfo:firstyear=2010&license=viewergpl$ + * + * Copyright (c) 2010, 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 "linden_common.h" + +#include <tut/tut.hpp> +#include <iostream> + +#include "lltut.h" +#include "../llviewerassetstats.h" +#include "lluuid.h" +#include "llsdutil.h" + +static const char * all_keys[] = +{ + "duration", + "get_other", + "get_texture_temp_http", + "get_texture_temp_udp", + "get_texture_non_temp_http", + "get_texture_non_temp_udp", + "get_wearable_udp", + "get_sound_udp", + "get_gesture_udp" +}; + +static const char * resp_keys[] = +{ + "get_other", + "get_texture_temp_http", + "get_texture_temp_udp", + "get_texture_non_temp_http", + "get_texture_non_temp_udp", + "get_wearable_udp", + "get_sound_udp", + "get_gesture_udp" +}; + +static const char * sub_keys[] = +{ + "dequeued", + "enqueued", + "resp_count", + "resp_max", + "resp_min", + "resp_mean" +}; + +static const LLUUID region1("4e2d81a3-6263-6ffe-ad5c-8ce04bee07e8"); +static const LLUUID region2("68762cc8-b68b-4e45-854b-e830734f2d4a"); +static const U64 region1_handle(0x00000401000003f7ULL); +static const U64 region2_handle(0x000003f800000420ULL); +static const std::string region1_handle_str("00000401000003f7"); +static const std::string region2_handle_str("000003f800000420"); + +#if 0 +static bool +is_empty_map(const LLSD & sd) +{ + return sd.isMap() && 0 == sd.size(); +} +#endif + +static bool +is_single_key_map(const LLSD & sd, const std::string & key) +{ + return sd.isMap() && 1 == sd.size() && sd.has(key); +} + +static bool +is_double_key_map(const LLSD & sd, const std::string & key1, const std::string & key2) +{ + return sd.isMap() && 2 == sd.size() && sd.has(key1) && sd.has(key2); +} + +static bool +is_no_stats_map(const LLSD & sd) +{ + return is_double_key_map(sd, "duration", "regions"); +} + +namespace tut +{ + struct tst_viewerassetstats_index + {}; + typedef test_group<tst_viewerassetstats_index> tst_viewerassetstats_index_t; + typedef tst_viewerassetstats_index_t::object tst_viewerassetstats_index_object_t; + tut::tst_viewerassetstats_index_t tut_tst_viewerassetstats_index("tst_viewerassetstats_test"); + + // Testing free functions without global stats allocated + template<> template<> + void tst_viewerassetstats_index_object_t::test<1>() + { + // Check that helpers aren't bothered by missing global stats + ensure("Global gViewerAssetStatsMain should be NULL", (NULL == gViewerAssetStatsMain)); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); + + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + + LLViewerAssetStatsFF::record_response_main(LLViewerAssetType::AT_GESTURE, false, false, 12300000ULL); + } + + // Create a non-global instance and check the structure + template<> template<> + void tst_viewerassetstats_index_object_t::test<2>() + { + ensure("Global gViewerAssetStatsMain should be NULL", (NULL == gViewerAssetStatsMain)); + + LLViewerAssetStats * it = new LLViewerAssetStats(); + + ensure("Global gViewerAssetStatsMain should still be NULL", (NULL == gViewerAssetStatsMain)); + + LLSD sd_full = it->asLLSD(); + + // Default (NULL) region ID doesn't produce LLSD results so should + // get an empty map back from output + ensure("Stat-less LLSD initially", is_no_stats_map(sd_full)); + + // Once the region is set, we will get a response even with no data collection + it->setRegion(region1_handle); + sd_full = it->asLLSD(); + ensure("Correct single-key LLSD map root", is_double_key_map(sd_full, "duration", "regions")); + ensure("Correct single-key LLSD map regions", is_single_key_map(sd_full["regions"], region1_handle_str)); + + LLSD sd = sd_full["regions"][region1_handle_str]; + + delete it; + + // Check the structure of the LLSD + for (int i = 0; i < LL_ARRAY_SIZE(all_keys); ++i) + { + std::string line = llformat("Has '%s' key", all_keys[i]); + ensure(line, sd.has(all_keys[i])); + } + + for (int i = 0; i < LL_ARRAY_SIZE(resp_keys); ++i) + { + for (int j = 0; j < LL_ARRAY_SIZE(sub_keys); ++j) + { + std::string line = llformat("Key '%s' has '%s' key", resp_keys[i], sub_keys[j]); + ensure(line, sd[resp_keys[i]].has(sub_keys[j])); + } + } + } + + // Create a non-global instance and check some content + template<> template<> + void tst_viewerassetstats_index_object_t::test<3>() + { + LLViewerAssetStats * it = new LLViewerAssetStats(); + it->setRegion(region1_handle); + + LLSD sd = it->asLLSD(); + ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str)); + sd = sd[region1_handle_str]; + + delete it; + + // Check a few points on the tree for content + ensure("sd[get_texture_temp_http][dequeued] is 0", (0 == sd["get_texture_temp_http"]["dequeued"].asInteger())); + ensure("sd[get_sound_udp][resp_min] is 0", (0.0 == sd["get_sound_udp"]["resp_min"].asReal())); + } + + // Create a global instance and verify free functions do something useful + template<> template<> + void tst_viewerassetstats_index_object_t::test<4>() + { + gViewerAssetStatsMain = new LLViewerAssetStats(); + LLViewerAssetStatsFF::set_region_main(region1_handle); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + + LLSD sd = gViewerAssetStatsMain->asLLSD(); + ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str)); + sd = sd["regions"][region1_handle_str]; + + // Check a few points on the tree for content + ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); + ensure("sd[get_texture_temp_udp][enqueued] is 0", (0 == sd["get_texture_temp_udp"]["enqueued"].asInteger())); + ensure("sd[get_texture_non_temp_http][enqueued] is 0", (0 == sd["get_texture_non_temp_http"]["enqueued"].asInteger())); + ensure("sd[get_texture_temp_http][enqueued] is 0", (0 == sd["get_texture_temp_http"]["enqueued"].asInteger())); + ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); + + // Reset and check zeros... + // Reset leaves current region in place + gViewerAssetStatsMain->reset(); + sd = gViewerAssetStatsMain->asLLSD()["regions"][region1_handle_str]; + + delete gViewerAssetStatsMain; + gViewerAssetStatsMain = NULL; + + ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); + ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); + } + + // Create two global instances and verify no interactions + template<> template<> + void tst_viewerassetstats_index_object_t::test<5>() + { + gViewerAssetStatsThread1 = new LLViewerAssetStats(); + gViewerAssetStatsMain = new LLViewerAssetStats(); + LLViewerAssetStatsFF::set_region_main(region1_handle); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + + LLSD sd = gViewerAssetStatsThread1->asLLSD(); + ensure("Other collector is empty", is_no_stats_map(sd)); + sd = gViewerAssetStatsMain->asLLSD(); + ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str)); + sd = sd["regions"][region1_handle_str]; + + // Check a few points on the tree for content + ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); + ensure("sd[get_texture_temp_udp][enqueued] is 0", (0 == sd["get_texture_temp_udp"]["enqueued"].asInteger())); + ensure("sd[get_texture_non_temp_http][enqueued] is 0", (0 == sd["get_texture_non_temp_http"]["enqueued"].asInteger())); + ensure("sd[get_texture_temp_http][enqueued] is 0", (0 == sd["get_texture_temp_http"]["enqueued"].asInteger())); + ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); + + // Reset and check zeros... + // Reset leaves current region in place + gViewerAssetStatsMain->reset(); + sd = gViewerAssetStatsMain->asLLSD()["regions"][region1_handle_str]; + + delete gViewerAssetStatsMain; + gViewerAssetStatsMain = NULL; + delete gViewerAssetStatsThread1; + gViewerAssetStatsThread1 = NULL; + + ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); + ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); + } + + // Check multiple region collection + template<> template<> + void tst_viewerassetstats_index_object_t::test<6>() + { + gViewerAssetStatsMain = new LLViewerAssetStats(); + + LLViewerAssetStatsFF::set_region_main(region1_handle); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + + LLViewerAssetStatsFF::set_region_main(region2_handle); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); + + LLSD sd = gViewerAssetStatsMain->asLLSD(); + + // std::cout << sd << std::endl; + + ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions")); + ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1_handle_str, region2_handle_str)); + LLSD sd1 = sd["regions"][region1_handle_str]; + LLSD sd2 = sd["regions"][region2_handle_str]; + + // Check a few points on the tree for content + ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger())); + ensure("sd1[get_texture_temp_udp][enqueued] is 0", (0 == sd1["get_texture_temp_udp"]["enqueued"].asInteger())); + ensure("sd1[get_texture_non_temp_http][enqueued] is 0", (0 == sd1["get_texture_non_temp_http"]["enqueued"].asInteger())); + ensure("sd1[get_texture_temp_http][enqueued] is 0", (0 == sd1["get_texture_temp_http"]["enqueued"].asInteger())); + ensure("sd1[get_gesture_udp][dequeued] is 0", (0 == sd1["get_gesture_udp"]["dequeued"].asInteger())); + + // Check a few points on the tree for content + ensure("sd2[get_gesture_udp][enqueued] is 4", (4 == sd2["get_gesture_udp"]["enqueued"].asInteger())); + ensure("sd2[get_gesture_udp][dequeued] is 0", (0 == sd2["get_gesture_udp"]["dequeued"].asInteger())); + ensure("sd2[get_texture_non_temp_udp][enqueued] is 0", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger())); + + // Reset and check zeros... + // Reset leaves current region in place + gViewerAssetStatsMain->reset(); + sd = gViewerAssetStatsMain->asLLSD(); + ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2_handle_str)); + sd2 = sd["regions"][region2_handle_str]; + + delete gViewerAssetStatsMain; + gViewerAssetStatsMain = NULL; + + ensure("sd2[get_texture_non_temp_udp][enqueued] is reset", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger())); + ensure("sd2[get_gesture_udp][enqueued] is reset", (0 == sd2["get_gesture_udp"]["enqueued"].asInteger())); + } + + // Check multiple region collection jumping back-and-forth between regions + template<> template<> + void tst_viewerassetstats_index_object_t::test<7>() + { + gViewerAssetStatsMain = new LLViewerAssetStats(); + + LLViewerAssetStatsFF::set_region_main(region1_handle); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + + LLViewerAssetStatsFF::set_region_main(region2_handle); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); + + LLViewerAssetStatsFF::set_region_main(region1_handle); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, true, true); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, true, true); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + + LLViewerAssetStatsFF::set_region_main(region2_handle); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false); + + LLSD sd = gViewerAssetStatsMain->asLLSD(); + + ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions")); + ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1_handle_str, region2_handle_str)); + LLSD sd1 = sd["regions"][region1_handle_str]; + LLSD sd2 = sd["regions"][region2_handle_str]; + + // Check a few points on the tree for content + ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger())); + ensure("sd1[get_texture_temp_udp][enqueued] is 0", (0 == sd1["get_texture_temp_udp"]["enqueued"].asInteger())); + ensure("sd1[get_texture_non_temp_http][enqueued] is 0", (0 == sd1["get_texture_non_temp_http"]["enqueued"].asInteger())); + ensure("sd1[get_texture_temp_http][enqueued] is 1", (1 == sd1["get_texture_temp_http"]["enqueued"].asInteger())); + ensure("sd1[get_gesture_udp][dequeued] is 0", (0 == sd1["get_gesture_udp"]["dequeued"].asInteger())); + + // Check a few points on the tree for content + ensure("sd2[get_gesture_udp][enqueued] is 8", (8 == sd2["get_gesture_udp"]["enqueued"].asInteger())); + ensure("sd2[get_gesture_udp][dequeued] is 0", (0 == sd2["get_gesture_udp"]["dequeued"].asInteger())); + ensure("sd2[get_texture_non_temp_udp][enqueued] is 0", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger())); + + // Reset and check zeros... + // Reset leaves current region in place + gViewerAssetStatsMain->reset(); + sd = gViewerAssetStatsMain->asLLSD(); + ensure("Correct single-key LLSD map root", is_double_key_map(sd, "duration", "regions")); + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2_handle_str)); + sd2 = sd["regions"][region2_handle_str]; + + delete gViewerAssetStatsMain; + gViewerAssetStatsMain = NULL; + + ensure("sd2[get_texture_non_temp_udp][enqueued] is reset", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger())); + ensure("sd2[get_gesture_udp][enqueued] is reset", (0 == sd2["get_gesture_udp"]["enqueued"].asInteger())); + } + + // Non-texture assets ignore transport and persistence flags + template<> template<> + void tst_viewerassetstats_index_object_t::test<8>() + { + gViewerAssetStatsThread1 = new LLViewerAssetStats(); + gViewerAssetStatsMain = new LLViewerAssetStats(); + LLViewerAssetStatsFF::set_region_main(region1_handle); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, true); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, true); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, true, false); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, true, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, true, true); + LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, true, true); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, false, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, false, true); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, true, false); + + LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, true, true); + + LLSD sd = gViewerAssetStatsThread1->asLLSD(); + ensure("Other collector is empty", is_no_stats_map(sd)); + sd = gViewerAssetStatsMain->asLLSD(); + ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration")); + ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str)); + sd = sd["regions"][region1_handle_str]; + + // Check a few points on the tree for content + ensure("sd[get_gesture_udp][enqueued] is 0", (0 == sd["get_gesture_udp"]["enqueued"].asInteger())); + ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); + + ensure("sd[get_wearable_udp][enqueued] is 4", (4 == sd["get_wearable_udp"]["enqueued"].asInteger())); + ensure("sd[get_wearable_udp][dequeued] is 4", (4 == sd["get_wearable_udp"]["dequeued"].asInteger())); + + ensure("sd[get_other][enqueued] is 4", (4 == sd["get_other"]["enqueued"].asInteger())); + ensure("sd[get_other][dequeued] is 0", (0 == sd["get_other"]["dequeued"].asInteger())); + + // Reset and check zeros... + // Reset leaves current region in place + gViewerAssetStatsMain->reset(); + sd = gViewerAssetStatsMain->asLLSD()["regions"][region1_handle_str]; + + delete gViewerAssetStatsMain; + gViewerAssetStatsMain = NULL; + delete gViewerAssetStatsThread1; + gViewerAssetStatsThread1 = NULL; + + ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger())); + ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger())); + } + + // Check that the LLSD merger knows what it's doing (basic test) + template<> template<> + void tst_viewerassetstats_index_object_t::test<9>() + { + LLSD::String reg1_name = region1_handle_str; + LLSD::String reg2_name = region2_handle_str; + + LLSD reg1_stats = LLSD::emptyMap(); + LLSD reg2_stats = LLSD::emptyMap(); + + LLSD & tmp_other1 = reg1_stats["get_other"]; + tmp_other1["enqueued"] = 4; + tmp_other1["dequeued"] = 4; + tmp_other1["resp_count"] = 8; + tmp_other1["resp_max"] = F64(23.2892); + tmp_other1["resp_min"] = F64(0.2829); + tmp_other1["resp_mean"] = F64(2.298928); + + LLSD & tmp_other2 = reg2_stats["get_other"]; + tmp_other2["enqueued"] = 8; + tmp_other2["dequeued"] = 7; + tmp_other2["resp_count"] = 3; + tmp_other2["resp_max"] = F64(6.5); + tmp_other2["resp_min"] = F64(0.01); + tmp_other2["resp_mean"] = F64(4.1); + + { + LLSD src = LLSD::emptyMap(); + LLSD dst = LLSD::emptyMap(); + + src["regions"][reg1_name] = reg1_stats; + src["duration"] = 24; + dst["regions"][reg2_name] = reg2_stats; + dst["duration"] = 36; + + LLViewerAssetStats::mergeRegionsLLSD(src, dst); + + ensure("region 1 in merged stats", llsd_equals(reg1_stats, dst["regions"][reg1_name])); + ensure("region 2 still in merged stats", llsd_equals(reg2_stats, dst["regions"][reg2_name])); + } + + { + LLSD src = LLSD::emptyMap(); + LLSD dst = LLSD::emptyMap(); + + src["regions"][reg1_name] = reg1_stats; + src["duration"] = 24; + dst["regions"][reg1_name] = reg2_stats; + dst["duration"] = 36; + + LLViewerAssetStats::mergeRegionsLLSD(src, dst); + + ensure("src not ruined", llsd_equals(reg1_stats, src["regions"][reg1_name])); + ensure_equals("added enqueued counts", dst["regions"][reg1_name]["get_other"]["enqueued"].asInteger(), 12); + ensure_equals("added dequeued counts", dst["regions"][reg1_name]["get_other"]["dequeued"].asInteger(), 11); + ensure_equals("added response counts", dst["regions"][reg1_name]["get_other"]["resp_count"].asInteger(), 11); + ensure_approximately_equals("min'd minimum response times", dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), 0.01, 20); + ensure_approximately_equals("max'd maximum response times", dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), 23.2892, 20); + ensure_approximately_equals("weighted mean of means", dst["regions"][reg1_name]["get_other"]["resp_mean"].asReal(), 2.7901295, 20); + } + } + + // Maximum merges are interesting when one side contributes nothing + template<> template<> + void tst_viewerassetstats_index_object_t::test<10>() + { + LLSD::String reg1_name = region1_handle_str; + LLSD::String reg2_name = region2_handle_str; + + LLSD reg1_stats = LLSD::emptyMap(); + LLSD reg2_stats = LLSD::emptyMap(); + + LLSD & tmp_other1 = reg1_stats["get_other"]; + tmp_other1["enqueued"] = 4; + tmp_other1["dequeued"] = 4; + tmp_other1["resp_count"] = 7; + tmp_other1["resp_max"] = F64(-23.2892); + tmp_other1["resp_min"] = F64(-123.2892); + tmp_other1["resp_mean"] = F64(-58.28298); + + LLSD & tmp_other2 = reg2_stats["get_other"]; + tmp_other2["enqueued"] = 8; + tmp_other2["dequeued"] = 7; + tmp_other2["resp_count"] = 0; + tmp_other2["resp_max"] = F64(0); + tmp_other2["resp_min"] = F64(0); + tmp_other2["resp_mean"] = F64(0); + + { + LLSD src = LLSD::emptyMap(); + LLSD dst = LLSD::emptyMap(); + + src["regions"][reg1_name] = reg1_stats; + src["duration"] = 24; + dst["regions"][reg1_name] = reg2_stats; + dst["duration"] = 36; + + LLViewerAssetStats::mergeRegionsLLSD(src, dst); + + ensure_approximately_equals("dst maximum with count 0 does not contribute to merged maximum", + dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20); + } + + { + LLSD src = LLSD::emptyMap(); + LLSD dst = LLSD::emptyMap(); + + src["regions"][reg1_name] = reg2_stats; + src["duration"] = 24; + dst["regions"][reg1_name] = reg1_stats; + dst["duration"] = 36; + + LLViewerAssetStats::mergeRegionsLLSD(src, dst); + + ensure_approximately_equals("src maximum with count 0 does not contribute to merged maximum", + dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20); + } + } + + // Minimum merges are interesting when one side contributes nothing + template<> template<> + void tst_viewerassetstats_index_object_t::test<11>() + { + LLSD::String reg1_name = region1_handle_str; + LLSD::String reg2_name = region2_handle_str; + + LLSD reg1_stats = LLSD::emptyMap(); + LLSD reg2_stats = LLSD::emptyMap(); + + LLSD & tmp_other1 = reg1_stats["get_other"]; + tmp_other1["enqueued"] = 4; + tmp_other1["dequeued"] = 4; + tmp_other1["resp_count"] = 7; + tmp_other1["resp_max"] = F64(123.2892); + tmp_other1["resp_min"] = F64(23.2892); + tmp_other1["resp_mean"] = F64(58.28298); + + LLSD & tmp_other2 = reg2_stats["get_other"]; + tmp_other2["enqueued"] = 8; + tmp_other2["dequeued"] = 7; + tmp_other2["resp_count"] = 0; + tmp_other2["resp_max"] = F64(0); + tmp_other2["resp_min"] = F64(0); + tmp_other2["resp_mean"] = F64(0); + + { + LLSD src = LLSD::emptyMap(); + LLSD dst = LLSD::emptyMap(); + + src["regions"][reg1_name] = reg1_stats; + src["duration"] = 24; + dst["regions"][reg1_name] = reg2_stats; + dst["duration"] = 36; + + LLViewerAssetStats::mergeRegionsLLSD(src, dst); + + ensure_approximately_equals("dst minimum with count 0 does not contribute to merged minimum", + dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20); + } + + { + LLSD src = LLSD::emptyMap(); + LLSD dst = LLSD::emptyMap(); + + src["regions"][reg1_name] = reg2_stats; + src["duration"] = 24; + dst["regions"][reg1_name] = reg1_stats; + dst["duration"] = 36; + + LLViewerAssetStats::mergeRegionsLLSD(src, dst); + + ensure_approximately_equals("src minimum with count 0 does not contribute to merged minimum", + dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20); + } + } + + // resp_count missing is taken as '0' for maximum calculation + template<> template<> + void tst_viewerassetstats_index_object_t::test<12>() + { + LLSD::String reg1_name = region1_handle_str; + LLSD::String reg2_name = region2_handle_str; + + LLSD reg1_stats = LLSD::emptyMap(); + LLSD reg2_stats = LLSD::emptyMap(); + + LLSD & tmp_other1 = reg1_stats["get_other"]; + tmp_other1["enqueued"] = 4; + tmp_other1["dequeued"] = 4; + tmp_other1["resp_count"] = 7; + tmp_other1["resp_max"] = F64(-23.2892); + tmp_other1["resp_min"] = F64(-123.2892); + tmp_other1["resp_mean"] = F64(-58.28298); + + LLSD & tmp_other2 = reg2_stats["get_other"]; + tmp_other2["enqueued"] = 8; + tmp_other2["dequeued"] = 7; + // tmp_other2["resp_count"] = 0; + tmp_other2["resp_max"] = F64(0); + tmp_other2["resp_min"] = F64(0); + tmp_other2["resp_mean"] = F64(0); + + { + LLSD src = LLSD::emptyMap(); + LLSD dst = LLSD::emptyMap(); + + src["regions"][reg1_name] = reg1_stats; + src["duration"] = 24; + dst["regions"][reg1_name] = reg2_stats; + dst["duration"] = 36; + + LLViewerAssetStats::mergeRegionsLLSD(src, dst); + + ensure_approximately_equals("dst maximum with undefined count does not contribute to merged maximum", + dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20); + } + + { + LLSD src = LLSD::emptyMap(); + LLSD dst = LLSD::emptyMap(); + + src["regions"][reg1_name] = reg2_stats; + src["duration"] = 24; + dst["regions"][reg1_name] = reg1_stats; + dst["duration"] = 36; + + LLViewerAssetStats::mergeRegionsLLSD(src, dst); + + ensure_approximately_equals("src maximum with undefined count does not contribute to merged maximum", + dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20); + } + } + + // resp_count unspecified is taken as 0 for minimum merges + template<> template<> + void tst_viewerassetstats_index_object_t::test<13>() + { + LLSD::String reg1_name = region1.asString(); + LLSD::String reg2_name = region2.asString(); + + LLSD reg1_stats = LLSD::emptyMap(); + LLSD reg2_stats = LLSD::emptyMap(); + + LLSD & tmp_other1 = reg1_stats["get_other"]; + tmp_other1["enqueued"] = 4; + tmp_other1["dequeued"] = 4; + tmp_other1["resp_count"] = 7; + tmp_other1["resp_max"] = F64(123.2892); + tmp_other1["resp_min"] = F64(23.2892); + tmp_other1["resp_mean"] = F64(58.28298); + + LLSD & tmp_other2 = reg2_stats["get_other"]; + tmp_other2["enqueued"] = 8; + tmp_other2["dequeued"] = 7; + // tmp_other2["resp_count"] = 0; + tmp_other2["resp_max"] = F64(0); + tmp_other2["resp_min"] = F64(0); + tmp_other2["resp_mean"] = F64(0); + + { + LLSD src = LLSD::emptyMap(); + LLSD dst = LLSD::emptyMap(); + + src["regions"][reg1_name] = reg1_stats; + src["duration"] = 24; + dst["regions"][reg1_name] = reg2_stats; + dst["duration"] = 36; + + LLViewerAssetStats::mergeRegionsLLSD(src, dst); + + ensure_approximately_equals("dst minimum with undefined count does not contribute to merged minimum", + dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20); + } + + { + LLSD src = LLSD::emptyMap(); + LLSD dst = LLSD::emptyMap(); + + src["regions"][reg1_name] = reg2_stats; + src["duration"] = 24; + dst["regions"][reg1_name] = reg1_stats; + dst["duration"] = 36; + + LLViewerAssetStats::mergeRegionsLLSD(src, dst); + + ensure_approximately_equals("src minimum with undefined count does not contribute to merged minimum", + dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20); + } + } +} |