summaryrefslogtreecommitdiff
path: root/indra/llcorehttp/tests
diff options
context:
space:
mode:
authorMonty Brandenberg <monty@lindenlab.com>2012-04-23 16:19:39 -0400
committerMonty Brandenberg <monty@lindenlab.com>2012-04-23 16:19:39 -0400
commit5611cb6d476540e6a1c654c1f9acdce2787b3505 (patch)
treee35afc4aa33ae00e71679ba3ccfead0de563843d /indra/llcorehttp/tests
parentb187aeb8f177bd76e792652e773617beff18b47b (diff)
Okay, imported the core-http library and got it compiling suspiciously easily.
The unit/integration tests don't work yet as I'm still battling cmake/autobuild as usual but first milestone passed.
Diffstat (limited to 'indra/llcorehttp/tests')
-rw-r--r--indra/llcorehttp/tests/all_test.cpp64
-rw-r--r--indra/llcorehttp/tests/test_allocator.cpp178
-rw-r--r--indra/llcorehttp/tests/test_allocator.h47
-rw-r--r--indra/llcorehttp/tests/test_bufferarray.hpp456
-rw-r--r--indra/llcorehttp/tests/test_httpheaders.hpp108
-rw-r--r--indra/llcorehttp/tests/test_httpoperation.hpp128
-rw-r--r--indra/llcorehttp/tests/test_httprequest.hpp437
-rw-r--r--indra/llcorehttp/tests/test_httprequestqueue.hpp186
-rw-r--r--indra/llcorehttp/tests/test_httpstatus.hpp163
-rw-r--r--indra/llcorehttp/tests/test_refcounted.hpp156
10 files changed, 1923 insertions, 0 deletions
diff --git a/indra/llcorehttp/tests/all_test.cpp b/indra/llcorehttp/tests/all_test.cpp
new file mode 100644
index 0000000000..636f6f8c05
--- /dev/null
+++ b/indra/llcorehttp/tests/all_test.cpp
@@ -0,0 +1,64 @@
+/**
+ * @file test_all
+ * @brief Main test runner
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+
+#include <iostream>
+
+#include <tut/tut.hpp>
+#include <tut/tut_reporter.hpp>
+
+#include <curl/curl.h>
+
+// Pull in each of the test sets
+#include "test_httpstatus.hpp"
+#include "test_refcounted.hpp"
+#include "test_httpoperation.hpp"
+#include "test_httprequest.hpp"
+#include "test_httpheaders.hpp"
+#include "test_bufferarray.hpp"
+#include "test_httprequestqueue.hpp"
+
+
+namespace tut
+{
+ test_runner_singleton runner;
+}
+
+int main()
+{
+ curl_global_init(CURL_GLOBAL_ALL);
+
+ // *FIXME: Need threaded/SSL curl setup here.
+
+ tut::reporter reporter;
+
+ tut::runner.get().set_callback(&reporter);
+ tut::runner.get().run_tests();
+ return !reporter.all_ok();
+
+ curl_global_cleanup();
+}
+
diff --git a/indra/llcorehttp/tests/test_allocator.cpp b/indra/llcorehttp/tests/test_allocator.cpp
new file mode 100644
index 0000000000..926de0a208
--- /dev/null
+++ b/indra/llcorehttp/tests/test_allocator.cpp
@@ -0,0 +1,178 @@
+/**
+ * @file test_allocator.cpp
+ * @brief quick and dirty allocator for tracking memory allocations
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "test_allocator.h"
+
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
+#include <libkern/OSAtomic.h>
+#elif defined(_MSC_VER)
+#include <Windows.h>
+#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ ) > 40100
+// atomic extensions are built into GCC on posix platforms
+#endif
+
+#include <cassert>
+#include <cstdlib>
+#include <cstring>
+#include <vector>
+#include <iostream>
+#include <new>
+
+#include <boost/thread.hpp>
+
+
+#if defined(WIN32)
+#define THROW_BAD_ALLOC() _THROW1(std::bad_alloc)
+#define THROW_NOTHING() _THROW0()
+#else
+#define THROW_BAD_ALLOC() throw(std::bad_alloc)
+#define THROW_NOTHING() throw()
+#endif
+
+
+struct BlockHeader
+{
+ struct Block * next;
+ std::size_t size;
+ bool in_use;
+};
+
+struct Block
+{
+ BlockHeader hdr;
+ unsigned char data[1];
+};
+
+#define TRACE_MSG(val) std::cout << __FUNCTION__ << "(" << val << ") [" << __FILE__ << ":" << __LINE__ << "]" << std::endl;
+
+static unsigned char MemBuf[ 4096 * 1024 ];
+Block * pNext = static_cast<Block *>(static_cast<void *>(MemBuf));
+volatile std::size_t MemTotal = 0;
+
+// cross-platform compare and swap operation
+static bool CAS(void * volatile * ptr, void * expected, void * new_value)
+{
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
+ return OSAtomicCompareAndSwapPtr( expected, new_value, ptr );
+#elif defined(_MSC_VER)
+ return expected == InterlockedCompareExchangePointer( ptr, new_value, expected );
+#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ ) > 40100
+ return __sync_bool_compare_and_swap( ptr, expected, new_value );
+#endif
+}
+
+static void * GetMem(std::size_t size)
+{
+ // TRACE_MSG(size);
+ volatile Block * pBlock = NULL;
+ volatile Block * pNewNext = NULL;
+
+ // do a lock-free update of the global next pointer
+ do
+ {
+ pBlock = pNext;
+ pNewNext = (volatile Block *)(pBlock->data + size);
+
+ } while(! CAS((void * volatile *) &pNext, (void *) pBlock, (void *) pNewNext));
+
+ // if we get here, we safely carved out a block of memory in the
+ // memory pool...
+
+ // initialize our block
+ pBlock->hdr.next = (Block *)(pBlock->data + size);
+ pBlock->hdr.size = size;
+ pBlock->hdr.in_use = true;
+ memset((void *) pBlock->data, 0, pBlock->hdr.size);
+
+ // do a lock-free update of the global memory total
+ volatile size_t total = 0;
+ volatile size_t new_total = 0;
+ do
+ {
+ total = MemTotal;
+ new_total = total + size;
+
+ } while (! CAS((void * volatile *) &MemTotal, (void *) total, (void *) new_total));
+
+ return (void *) pBlock->data;
+}
+
+
+static void FreeMem(void * p)
+{
+ // get the pointer to the block record
+ Block * pBlock = (Block *)((unsigned char *) p - sizeof(BlockHeader));
+
+ // TRACE_MSG(pBlock->hdr.size);
+ bool * cur_in_use = &(pBlock->hdr.in_use);
+ volatile bool in_use = false;
+ bool new_in_use = false;
+ do
+ {
+ in_use = pBlock->hdr.in_use;
+ } while (! CAS((void * volatile *) cur_in_use, (void *) in_use, (void *) new_in_use));
+
+ // do a lock-free update of the global memory total
+ volatile size_t total = 0;
+ volatile size_t new_total = 0;
+ do
+ {
+ total = MemTotal;
+ new_total = total - pBlock->hdr.size;
+ } while (! CAS((void * volatile *)&MemTotal, (void *) total, (void *) new_total));
+}
+
+
+std::size_t GetMemTotal()
+{
+ return MemTotal;
+}
+
+
+void * operator new(std::size_t size) THROW_BAD_ALLOC()
+{
+ return GetMem( size );
+}
+
+
+void * operator new[](std::size_t size) THROW_BAD_ALLOC()
+{
+ return GetMem( size );
+}
+
+
+void operator delete(void * p) THROW_NOTHING()
+{
+ FreeMem( p );
+}
+
+
+void operator delete[](void * p) THROW_NOTHING()
+{
+ FreeMem( p );
+}
+
+
diff --git a/indra/llcorehttp/tests/test_allocator.h b/indra/llcorehttp/tests/test_allocator.h
new file mode 100644
index 0000000000..3572bbc5c5
--- /dev/null
+++ b/indra/llcorehttp/tests/test_allocator.h
@@ -0,0 +1,47 @@
+/**
+ * @file test_allocator.h
+ * @brief quick and dirty allocator for tracking memory allocations
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef TEST_ALLOCATOR_H
+#define TEST_ALLOCATOR_H
+
+#include <cstdlib>
+#include <new>
+
+size_t GetMemTotal();
+#if defined(WIN32)
+void * operator new(std::size_t size) _THROW1(std::bad_alloc);
+void * operator new[](std::size_t size) _THROW1(std::bad_alloc);
+void operator delete(void * p) _THROW0();
+void operator delete[](void * p) _THROW0();
+#else
+void * operator new(std::size_t size) throw (std::bad_alloc);
+void * operator new[](std::size_t size) throw (std::bad_alloc);
+void operator delete(void * p) throw ();
+void operator delete[](void * p) throw ();
+#endif
+
+#endif // TEST_ALLOCATOR_H
+
diff --git a/indra/llcorehttp/tests/test_bufferarray.hpp b/indra/llcorehttp/tests/test_bufferarray.hpp
new file mode 100644
index 0000000000..4f5d0284a1
--- /dev/null
+++ b/indra/llcorehttp/tests/test_bufferarray.hpp
@@ -0,0 +1,456 @@
+/**
+ * @file test_bufferarray.hpp
+ * @brief unit tests for the LLCore::BufferArray class
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+#ifndef TEST_LLCORE_BUFFER_ARRAY_H_
+#define TEST_LLCORE_BUFFER_ARRAY_H_
+
+#include <core-http/bufferarray.h>
+
+#include <iostream>
+
+#include "test_allocator.h"
+
+
+using namespace LLCoreInt;
+
+
+
+namespace tut
+{
+
+struct BufferArrayTestData
+{
+ // the test objects inherit from this so the member functions and variables
+ // can be referenced directly inside of the test functions.
+ size_t mMemTotal;
+};
+
+typedef test_group<BufferArrayTestData> BufferArrayTestGroupType;
+typedef BufferArrayTestGroupType::object BufferArrayTestObjectType;
+BufferArrayTestGroupType BufferArrayTestGroup("BufferArray Tests");
+
+template <> template <>
+void BufferArrayTestObjectType::test<1>()
+{
+ set_test_name("BufferArray construction");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ BufferArray * ba = new BufferArray();
+ ensure("One ref on construction of BufferArray", ba->getRefCount() == 1);
+ ensure("Memory being used", mMemTotal < GetMemTotal());
+ ensure("Nothing in BA", 0 == ba->size());
+
+ // Try to read
+ char buffer[20];
+ size_t read_len(ba->read(buffer, sizeof(buffer)));
+ ensure("Read returns empty", 0 == read_len);
+
+ // release the implicit reference, causing the object to be released
+ ba->release();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+}
+
+template <> template <>
+void BufferArrayTestObjectType::test<2>()
+{
+ set_test_name("BufferArray single write");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ BufferArray * ba = new BufferArray();
+
+ // write some data to the buffer
+ char str1[] = "abcdefghij";
+ char buffer[256];
+
+ size_t len = ba->write(str1, strlen(str1));
+ ensure("Wrote length correct", strlen(str1) == len);
+ ensure("Recorded size correct", strlen(str1) == ba->size());
+
+ // read some data back
+ len = ba->seek(2);
+ ensure("Seek worked", 2 == len);
+
+ memset(buffer, 'X', sizeof(buffer));
+ len = ba->read(buffer, 2);
+ ensure("Read length correct", 2 == len);
+ ensure("Read content correct", 'c' == buffer[0] && 'd' == buffer[1]);
+ ensure("Read didn't overwrite", 'X' == buffer[2]);
+
+ // release the implicit reference, causing the object to be released
+ ba->release();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+}
+
+
+template <> template <>
+void BufferArrayTestObjectType::test<3>()
+{
+ set_test_name("BufferArray multiple writes");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ BufferArray * ba = new BufferArray();
+
+ // write some data to the buffer
+ char str1[] = "abcdefghij";
+ size_t str1_len(strlen(str1));
+ char buffer[256];
+
+ size_t len = ba->write(str1, str1_len);
+ ensure("Wrote length correct", str1_len == len);
+ ensure("Recorded size correct", str1_len == ba->size());
+
+ // again...
+ len = ba->write(str1, strlen(str1));
+ ensure("Wrote length correct", str1_len == len);
+ ensure("Recorded size correct", (2 * str1_len) == ba->size());
+
+ // read some data back
+ len = ba->seek(8);
+ ensure("Seek worked", 8 == len);
+
+ memset(buffer, 'X', sizeof(buffer));
+ len = ba->read(buffer, 4);
+ ensure("Read length correct", 4 == len);
+ ensure("Read content correct", 'i' == buffer[0] && 'j' == buffer[1]);
+ ensure("Read content correct", 'a' == buffer[2] && 'b' == buffer[3]);
+ ensure("Read didn't overwrite", 'X' == buffer[4]);
+
+ // Read whole thing
+ len = ba->seek(0);
+ ensure("Seek worked (2)", 0 == len);
+
+ memset(buffer, 'X', sizeof(buffer));
+ len = ba->read(buffer, sizeof(buffer));
+ ensure("Read length correct", (2 * str1_len) == len);
+ ensure("Read content correct (3)", 0 == strncmp(buffer, str1, str1_len));
+ ensure("Read content correct (4)", 0 == strncmp(&buffer[str1_len], str1, str1_len));
+ ensure("Read didn't overwrite (5)", 'X' == buffer[2 * str1_len]);
+
+ // release the implicit reference, causing the object to be released
+ ba->release();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+}
+
+template <> template <>
+void BufferArrayTestObjectType::test<4>()
+{
+ set_test_name("BufferArray overwriting");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ BufferArray * ba = new BufferArray();
+
+ // write some data to the buffer
+ char str1[] = "abcdefghij";
+ size_t str1_len(strlen(str1));
+ char str2[] = "ABCDEFGHIJ";
+ size_t str2_len(strlen(str2));
+ char buffer[256];
+
+ size_t len = ba->write(str1, str1_len);
+ ensure("Wrote length correct", str1_len == len);
+ ensure("Recorded size correct", str1_len == ba->size());
+
+ // again...
+ len = ba->write(str1, strlen(str1));
+ ensure("Wrote length correct", str1_len == len);
+ ensure("Recorded size correct", (2 * str1_len) == ba->size());
+
+ // reposition and overwrite
+ len = ba->seek(8);
+ ensure("Seek worked", 8 == len);
+ len = ba->write(str2, 4);
+ ensure("Overwrite length correct", 4 == len);
+
+ // Leave position and read verifying content
+ memset(buffer, 'X', sizeof(buffer));
+ len = ba->read(buffer, 4);
+ ensure("Read length correct", 4 == len);
+ ensure("Read content correct", 'c' == buffer[0] && 'd' == buffer[1]);
+ ensure("Read content correct.2", 'e' == buffer[2] && 'f' == buffer[3]);
+ ensure("Read didn't overwrite", 'X' == buffer[4]);
+
+ // reposition and check
+ len = ba->seek(6);
+ memset(buffer, 'X', sizeof(buffer));
+ len = ba->read(buffer, 8);
+ ensure("Read length correct.2", 8 == len);
+ ensure("Read content correct.3", 'g' == buffer[0] && 'h' == buffer[1]);
+ ensure("Read content correct.4", 'A' == buffer[2] && 'B' == buffer[3]);
+ ensure("Read content correct.5", 'C' == buffer[4] && 'D' == buffer[5]);
+ ensure("Read content correct.6", 'c' == buffer[6] && 'd' == buffer[7]);
+ ensure("Read didn't overwrite.7", 'X' == buffer[8]);
+
+ // release the implicit reference, causing the object to be released
+ ba->release();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+}
+
+template <> template <>
+void BufferArrayTestObjectType::test<5>()
+{
+ set_test_name("BufferArray multiple writes - sequential reads");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ BufferArray * ba = new BufferArray();
+
+ // write some data to the buffer
+ char str1[] = "abcdefghij";
+ size_t str1_len(strlen(str1));
+ char buffer[256];
+
+ size_t len = ba->write(str1, str1_len);
+ ensure("Wrote length correct", str1_len == len);
+ ensure("Recorded size correct", str1_len == ba->size());
+
+ // again...
+ len = ba->write(str1, strlen(str1));
+ ensure("Wrote length correct", str1_len == len);
+ ensure("Recorded size correct", (2 * str1_len) == ba->size());
+
+ // read some data back
+ len = ba->seek(8);
+ ensure("Seek worked", 8 == len);
+
+ memset(buffer, 'X', sizeof(buffer));
+ len = ba->read(buffer, 4);
+ ensure("Read length correct", 4 == len);
+ ensure("Read content correct", 'i' == buffer[0] && 'j' == buffer[1]);
+ ensure("Read content correct.2", 'a' == buffer[2] && 'b' == buffer[3]);
+ ensure("Read didn't overwrite", 'X' == buffer[4]);
+
+ // Read some more without repositioning
+ memset(buffer, 'X', sizeof(buffer));
+ len = ba->read(buffer, sizeof(buffer));
+ ensure("Read length correct", (str1_len - 2) == len);
+ ensure("Read content correct.3", 0 == strncmp(buffer, str1+2, str1_len-2));
+ ensure("Read didn't overwrite.2", 'X' == buffer[str1_len-1]);
+
+ // release the implicit reference, causing the object to be released
+ ba->release();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+}
+
+template <> template <>
+void BufferArrayTestObjectType::test<6>()
+{
+ set_test_name("BufferArray overwrite spanning blocks and appending");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ BufferArray * ba = new BufferArray();
+
+ // write some data to the buffer
+ char str1[] = "abcdefghij";
+ size_t str1_len(strlen(str1));
+ char str2[] = "ABCDEFGHIJKLMNOPQRST";
+ size_t str2_len(strlen(str2));
+ char buffer[256];
+
+ size_t len = ba->write(str1, str1_len);
+ ensure("Wrote length correct", str1_len == len);
+ ensure("Recorded size correct", str1_len == ba->size());
+
+ // again...
+ len = ba->write(str1, strlen(str1));
+ ensure("Wrote length correct", str1_len == len);
+ ensure("Recorded size correct", (2 * str1_len) == ba->size());
+
+ // reposition and overwrite
+ len = ba->seek(8);
+ ensure("Seek worked", 8 == len);
+ len = ba->write(str2, str2_len);
+ ensure("Overwrite length correct", str2_len == len);
+
+ // Leave position and read verifying content
+ memset(buffer, 'X', sizeof(buffer));
+ len = ba->read(buffer, 0);
+ ensure("Read length correct", 0 == len);
+ ensure("Read didn't overwrite", 'X' == buffer[0]);
+
+ // reposition and check
+ len = ba->seek(0);
+ memset(buffer, 'X', sizeof(buffer));
+ len = ba->read(buffer, sizeof(buffer));
+ ensure("Read length correct.2", (str1_len + str2_len - 2) == len);
+ ensure("Read content correct", 0 == strncmp(buffer, str1, str1_len-2));
+ ensure("Read content correct.2", 0 == strncmp(buffer+str1_len-2, str2, str2_len));
+ ensure("Read didn't overwrite.2", 'X' == buffer[str1_len + str2_len - 2]);
+
+ // release the implicit reference, causing the object to be released
+ ba->release();
+
+ // make sure we didn't leak any memory
+ ensure("All memory released", mMemTotal == GetMemTotal());
+}
+
+template <> template <>
+void BufferArrayTestObjectType::test<7>()
+{
+ set_test_name("BufferArray overwrite spanning blocks and sequential writes");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ BufferArray * ba = new BufferArray();
+
+ // write some data to the buffer
+ char str1[] = "abcdefghij";
+ size_t str1_len(strlen(str1));
+ char str2[] = "ABCDEFGHIJKLMNOPQRST";
+ size_t str2_len(strlen(str2));
+ char buffer[256];
+
+ // 2x str1
+ size_t len = ba->write(str1, str1_len);
+ len = ba->write(str1, strlen(str1));
+
+ // reposition and overwrite
+ len = ba->seek(6);
+ len = ba->write(str2, 2);
+ ensure("Overwrite length correct", 2 == len);
+
+ len = ba->write(str2, 2);
+ ensure("Overwrite length correct.2", 2 == len);
+
+ len = ba->write(str2, 2);
+ ensure("Overwrite length correct.3", 2 == len);
+
+ // append some data
+ len = ba->append(str2, str2_len);
+ ensure("Append length correct", str2_len == len);
+
+ // append some more
+ char * out_buf(ba->appendBufferAlloc(str1_len));
+ memcpy(out_buf, str1, str1_len);
+
+ // And some final writes
+ len = ba->write(str2, 2);
+ ensure("Write length correct.2", 2 == len);
+
+ // Check contents
+ memset(buffer, 'X', sizeof(buffer));
+ ba->seek(0);
+ len = ba->read(buffer, sizeof(buffer));
+ ensure("Final buffer length correct", (3 * str1_len + str2_len + 2) == len);
+ ensure("Read content correct", 0 == strncmp(buffer, str1, 6));
+ ensure("Read content correct.2", 0 == strncmp(buffer + 6, str2, 2));
+ ensure("Read content correct.3", 0 == strncmp(buffer + 8, str2, 2));
+ ensure("Read content correct.4", 0 == strncmp(buffer + 10, str2, 2));
+ ensure("Read content correct.5", 0 == strncmp(buffer + str1_len + 2, str1 + 2, str1_len - 2));
+ ensure("Read content correct.6", 0 == strncmp(buffer + str1_len + str1_len, str2, str2_len));
+ ensure("Read content correct.7", 0 == strncmp(buffer + str1_len + str1_len + str2_len, str1, str1_len));
+ ensure("Read content correct.8", 0 == strncmp(buffer + str1_len + str1_len + str2_len + str1_len, str2, 2));
+ ensure("Read didn't overwrite", 'X' == buffer[str1_len + str1_len + str2_len + str1_len + 2]);
+
+ // release the implicit reference, causing the object to be released
+ ba->release();
+
+ // make sure we didn't leak any memory
+ ensure("All memory released", mMemTotal == GetMemTotal());
+}
+
+template <> template <>
+void BufferArrayTestObjectType::test<8>()
+{
+ set_test_name("BufferArray zero-length appendBufferAlloc");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ BufferArray * ba = new BufferArray();
+
+ // write some data to the buffer
+ char str1[] = "abcdefghij";
+ size_t str1_len(strlen(str1));
+ char str2[] = "ABCDEFGHIJKLMNOPQRST";
+ size_t str2_len(strlen(str2));
+ char buffer[256];
+
+ // 2x str1
+ size_t len = ba->write(str1, str1_len);
+ len = ba->write(str1, strlen(str1));
+
+ // zero-length allocate (we allow this with a valid pointer returned)
+ char * out_buf(ba->appendBufferAlloc(0));
+ ensure("Buffer from zero-length appendBufferAlloc non-NULL", NULL != out_buf);
+
+ // Do it again
+ char * out_buf2(ba->appendBufferAlloc(0));
+ ensure("Buffer from zero-length appendBufferAlloc non-NULL.2", NULL != out_buf2);
+ ensure("Two zero-length appendBufferAlloc buffers distinct", out_buf != out_buf2);
+
+ // And some final writes
+ len = ba->write(str2, str2_len);
+
+ // Check contents
+ memset(buffer, 'X', sizeof(buffer));
+ ba->seek(0);
+ len = ba->read(buffer, sizeof(buffer));
+ ensure("Final buffer length correct", (2 * str1_len + str2_len) == len);
+ ensure("Read content correct.1", 0 == strncmp(buffer, str1, str1_len));
+ ensure("Read content correct.2", 0 == strncmp(buffer + str1_len, str1, str1_len));
+ ensure("Read content correct.3", 0 == strncmp(buffer + str1_len + str1_len, str2, str2_len));
+ ensure("Read didn't overwrite", 'X' == buffer[str1_len + str1_len + str2_len]);
+
+ // release the implicit reference, causing the object to be released
+ ba->release();
+
+ // make sure we didn't leak any memory
+ ensure("All memory released", mMemTotal == GetMemTotal());
+}
+
+} // end namespace tut
+
+
+#endif // TEST_LLCORE_BUFFER_ARRAY_H_
diff --git a/indra/llcorehttp/tests/test_httpheaders.hpp b/indra/llcorehttp/tests/test_httpheaders.hpp
new file mode 100644
index 0000000000..d22b516691
--- /dev/null
+++ b/indra/llcorehttp/tests/test_httpheaders.hpp
@@ -0,0 +1,108 @@
+/**
+ * @file test_httpheaders.hpp
+ * @brief unit tests for the LLCore::HttpHeaders class
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+#ifndef TEST_LLCORE_HTTP_HEADERS_H_
+#define TEST_LLCORE_HTTP_HEADERS_H_
+
+#include <core-http/httpheaders.h>
+
+#include <iostream>
+
+#include "test_allocator.h"
+
+
+using namespace LLCoreInt;
+
+
+
+namespace tut
+{
+
+struct HttpHeadersTestData
+{
+ // the test objects inherit from this so the member functions and variables
+ // can be referenced directly inside of the test functions.
+ size_t mMemTotal;
+};
+
+typedef test_group<HttpHeadersTestData> HttpHeadersTestGroupType;
+typedef HttpHeadersTestGroupType::object HttpHeadersTestObjectType;
+HttpHeadersTestGroupType HttpHeadersTestGroup("HttpHeaders Tests");
+
+template <> template <>
+void HttpHeadersTestObjectType::test<1>()
+{
+ set_test_name("HttpHeaders construction");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ HttpHeaders * headers = new HttpHeaders();
+ ensure("One ref on construction of HttpHeaders", headers->getRefCount() == 1);
+ ensure("Memory being used", mMemTotal < GetMemTotal());
+ ensure("Nothing in headers", 0 == headers->mHeaders.size());
+
+ // release the implicit reference, causing the object to be released
+ headers->release();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+}
+
+template <> template <>
+void HttpHeadersTestObjectType::test<2>()
+{
+ set_test_name("HttpHeaders construction");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ HttpHeaders * headers = new HttpHeaders();
+
+ {
+ // Append a few strings
+ std::string str1("Pragma:");
+ headers->mHeaders.push_back(str1);
+ std::string str2("Accept: application/json");
+ headers->mHeaders.push_back(str2);
+
+ ensure("Headers retained", 2 == headers->mHeaders.size());
+ ensure("First is first", headers->mHeaders[0] == str1);
+ ensure("Second is second", headers->mHeaders[1] == str2);
+ }
+
+ // release the implicit reference, causing the object to be released
+ headers->release();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+}
+
+} // end namespace tut
+
+
+#endif // TEST_LLCORE_HTTP_HEADERS_H_
diff --git a/indra/llcorehttp/tests/test_httpoperation.hpp b/indra/llcorehttp/tests/test_httpoperation.hpp
new file mode 100644
index 0000000000..c9feaddb2a
--- /dev/null
+++ b/indra/llcorehttp/tests/test_httpoperation.hpp
@@ -0,0 +1,128 @@
+/**
+ * @file test_httpoperation.hpp
+ * @brief unit tests for the LLCore::HttpOperation-derived classes
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+#ifndef TEST_LLCORE_HTTP_OPERATION_H_
+#define TEST_LLCORE_HTTP_OPERATION_H_
+
+#include "_httpoperation.h"
+#include <core-http/httphandler.h>
+
+#include <iostream>
+
+#include "test_allocator.h"
+
+
+using namespace LLCoreInt;
+
+
+namespace
+{
+
+class TestHandler : public LLCore::HttpHandler
+{
+public:
+ virtual void onCompleted(HttpHandle, HttpResponse *)
+ {
+ std::cout << "TestHandler::onCompleted() invoked" << std::endl;
+ }
+
+};
+
+
+} // end namespace anonymous
+
+
+namespace tut
+{
+ struct HttpOperationTestData
+ {
+ // the test objects inherit from this so the member functions and variables
+ // can be referenced directly inside of the test functions.
+ size_t mMemTotal;
+ };
+
+ typedef test_group<HttpOperationTestData> HttpOperationTestGroupType;
+ typedef HttpOperationTestGroupType::object HttpOperationTestObjectType;
+ HttpOperationTestGroupType HttpOperationTestGroup("HttpOperation Tests");
+
+ template <> template <>
+ void HttpOperationTestObjectType::test<1>()
+ {
+ set_test_name("HttpOpNull construction");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ HttpOpNull * op = new HttpOpNull();
+ ensure(op->getRefCount() == 1);
+ ensure(mMemTotal < GetMemTotal());
+
+ // release the implicit reference, causing the object to be released
+ op->release();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+ }
+
+ template <> template <>
+ void HttpOperationTestObjectType::test<2>()
+ {
+ set_test_name("HttpOpNull construction with handlers");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // Get some handlers
+ TestHandler * h1 = new TestHandler();
+ TestHandler * h2 = new TestHandler();
+
+ // create a new ref counted object with an implicit reference
+ HttpOpNull * op = new HttpOpNull();
+
+ // Add the handlers
+ op->setHandlers(NULL, h1, h2);
+
+ // Check ref count
+ ensure(op->getRefCount() == 1);
+
+ // release the reference, releasing the operation but
+ // not the handlers.
+ op->release();
+ op = NULL;
+ ensure(mMemTotal != GetMemTotal());
+
+ // release the handlers
+ delete h1;
+ h1 = NULL;
+ delete h2;
+ h2 = NULL;
+
+ ensure(mMemTotal == GetMemTotal());
+ }
+
+}
+
+#endif // TEST_LLCORE_HTTP_OPERATION_H_
diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp
new file mode 100644
index 0000000000..df5640859f
--- /dev/null
+++ b/indra/llcorehttp/tests/test_httprequest.hpp
@@ -0,0 +1,437 @@
+/**
+ * @file test_httprequest.hpp
+ * @brief unit tests for the LLCore::HttpRequest class
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+#ifndef TEST_LLCORE_HTTP_REQUEST_H_
+#define TEST_LLCORE_HTTP_REQUEST_H_
+
+#include <core-http/httprequest.h>
+#include <core-http/httphandler.h>
+#include <core-http/httpresponse.h>
+#include <core-http/_httpservice.h>
+#include <core-http/_httprequestqueue.h>
+
+#include <curl/curl.h>
+
+#include "test_allocator.h"
+
+
+using namespace LLCoreInt;
+
+
+namespace
+{
+
+#if defined(WIN32)
+
+void usleep(unsigned long usec);
+
+#endif
+
+}
+
+namespace tut
+{
+
+struct HttpRequestTestData
+{
+ // the test objects inherit from this so the member functions and variables
+ // can be referenced directly inside of the test functions.
+ size_t mMemTotal;
+ int mHandlerCalls;
+ HttpStatus mStatus;
+};
+
+class TestHandler2 : public LLCore::HttpHandler
+{
+public:
+ TestHandler2(HttpRequestTestData * state,
+ const std::string & name)
+ : mState(state),
+ mName(name),
+ mExpectHandle(LLCORE_HTTP_HANDLE_INVALID)
+ {}
+
+ virtual void onCompleted(HttpHandle handle, HttpResponse * response)
+ {
+ if (LLCORE_HTTP_HANDLE_INVALID != mExpectHandle)
+ {
+ ensure("Expected handle received in handler", mExpectHandle == handle);
+ }
+ ensure("Handler got a response", NULL != response);
+ if (response && mState)
+ {
+ const HttpStatus actual_status(response->getStatus());
+
+ ensure("Expected HttpStatus received in response", actual_status == mState->mStatus);
+ }
+ if (mState)
+ {
+ mState->mHandlerCalls++;
+ }
+ // std::cout << "TestHandler2::onCompleted() invoked" << std::endl;
+ }
+
+ HttpRequestTestData * mState;
+ std::string mName;
+ HttpHandle mExpectHandle;
+};
+
+typedef test_group<HttpRequestTestData> HttpRequestTestGroupType;
+typedef HttpRequestTestGroupType::object HttpRequestTestObjectType;
+HttpRequestTestGroupType HttpRequestTestGroup("HttpRequest Tests");
+
+template <> template <>
+void HttpRequestTestObjectType::test<1>()
+{
+ set_test_name("HttpRequest construction");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // Get singletons created
+ HttpRequest::createService();
+
+ // create a new ref counted object with an implicit reference
+ HttpRequest * req = new HttpRequest();
+ ensure(mMemTotal < GetMemTotal());
+
+ // release the request object
+ delete req;
+ req = NULL;
+
+ HttpRequest::destroyService();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+}
+
+template <> template <>
+void HttpRequestTestObjectType::test<2>()
+{
+ set_test_name("HttpRequest and Null Op queued");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // Get singletons created
+ HttpRequest::createService();
+
+ // create a new ref counted object with an implicit reference
+ HttpRequest * req = new HttpRequest();
+ ensure(mMemTotal < GetMemTotal());
+
+ // Issue a NoOp
+ HttpHandle handle = req->requestNoOp(NULL);
+ ensure(handle != LLCORE_HTTP_HANDLE_INVALID);
+
+ // release the request object
+ delete req;
+ req = NULL;
+
+ // We're still holding onto the operation which is
+ // sitting, unserviced, on the request queue so...
+ ensure(mMemTotal < GetMemTotal());
+
+ // Request queue should have two references: global singleton & service object
+ ensure("Two references to request queue", 2 == HttpRequestQueue::instanceOf()->getRefCount());
+
+ // Okay, tear it down
+ HttpRequest::destroyService();
+ // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal());
+ ensure(mMemTotal == GetMemTotal());
+}
+
+
+template <> template <>
+void HttpRequestTestObjectType::test<3>()
+{
+ set_test_name("HttpRequest NoOp + Stop execution");
+
+ // Handler can be stack-allocated *if* there are no dangling
+ // references to it after completion of this method.
+ // Create before memory record as the string copy will bump numbers.
+ TestHandler2 handler(this, "handler");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+ mHandlerCalls = 0;
+
+ // Get singletons created
+ HttpRequest::createService();
+
+ // Start threading early so that thread memory is invariant
+ // over the test.
+ HttpRequest::startThread();
+
+ // create a new ref counted object with an implicit reference
+ HttpRequest * req = new HttpRequest();
+ ensure("Memory allocated on construction", mMemTotal < GetMemTotal());
+
+ // Issue a NoOp
+ HttpHandle handle = req->requestNoOp(&handler);
+ ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID);
+
+ // Run the notification pump.
+ int count(0);
+ int limit(20);
+ while (count++ < limit && mHandlerCalls < 1)
+ {
+ req->update(1000);
+ usleep(100000);
+ }
+ ensure("Request executed in reasonable time", count < limit);
+ ensure("One handler invocation for request", mHandlerCalls == 1);
+
+ // Okay, request a shutdown of the servicing thread
+ handle = req->requestStopThread(&handler);
+ ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
+
+ // Run the notification pump again
+ count = 0;
+ limit = 100;
+ while (count++ < limit && mHandlerCalls < 2)
+ {
+ req->update(1000);
+ usleep(100000);
+ }
+ ensure("Second request executed in reasonable time", count < limit);
+ ensure("Second handler invocation", mHandlerCalls == 2);
+
+ // See that we actually shutdown the thread
+ count = 0;
+ limit = 10;
+ while (count++ < limit && ! HttpService::isStopped())
+ {
+ usleep(100000);
+ }
+ ensure("Thread actually stopped running", HttpService::isStopped());
+
+ // release the request object
+ delete req;
+ req = NULL;
+
+ // Shut down service
+ HttpRequest::destroyService();
+
+ // We have left over state so can't really say something
+ // definitive about memory usage at the end of this.
+ ensure("Two handler calls on the way out", 2 == mHandlerCalls);
+ // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal());
+ ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal());
+}
+
+template <> template <>
+void HttpRequestTestObjectType::test<4>()
+{
+ set_test_name("2 HttpRequest instances, one thread");
+
+ // Handler can be stack-allocated *if* there are no dangling
+ // references to it after completion of this method.
+ TestHandler2 handler1(this, "handler1");
+ TestHandler2 handler2(this, "handler2");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+ mHandlerCalls = 0;
+
+ // Get singletons created
+ HttpRequest::createService();
+
+ // Start threading early so that thread memory is invariant
+ // over the test.
+ HttpRequest::startThread();
+
+ // create a new ref counted object with an implicit reference
+ HttpRequest * req1 = new HttpRequest();
+ HttpRequest * req2 = new HttpRequest();
+ ensure("Memory allocated on construction", mMemTotal < GetMemTotal());
+
+ // Issue some NoOps
+ HttpHandle handle = req1->requestNoOp(&handler1);
+ ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID);
+ handler1.mExpectHandle = handle;
+
+ handle = req2->requestNoOp(&handler2);
+ ensure("Valid handle returned for first request", handle != LLCORE_HTTP_HANDLE_INVALID);
+ handler2.mExpectHandle = handle;
+
+ // Run the notification pump.
+ int count(0);
+ int limit(20);
+ while (count++ < limit && mHandlerCalls < 2)
+ {
+ req1->update(1000);
+ req2->update(1000);
+ usleep(100000);
+ }
+ ensure("Request executed in reasonable time", count < limit);
+ ensure("One handler invocation for request", mHandlerCalls == 2);
+
+ // Okay, request a shutdown of the servicing thread
+ handle = req2->requestStopThread(&handler2);
+ ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
+ handler2.mExpectHandle = handle;
+
+ // Run the notification pump again
+ count = 0;
+ limit = 100;
+ while (count++ < limit && mHandlerCalls < 3)
+ {
+ req1->update(1000);
+ req2->update(1000);
+ usleep(100000);
+ }
+ ensure("Second request executed in reasonable time", count < limit);
+ ensure("Second handler invocation", mHandlerCalls == 3);
+
+ // See that we actually shutdown the thread
+ count = 0;
+ limit = 10;
+ while (count++ < limit && ! HttpService::isStopped())
+ {
+ usleep(100000);
+ }
+ ensure("Thread actually stopped running", HttpService::isStopped());
+
+ // release the request object
+ delete req1;
+ req1 = NULL;
+ delete req2;
+ req2 = NULL;
+
+ // Shut down service
+ HttpRequest::destroyService();
+
+ // We have left over state so can't really say something
+ // definitive about memory usage at the end of this.
+ ensure("Two handler calls on the way out", 3 == mHandlerCalls);
+ // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal());
+ ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal());
+}
+
+template <> template <>
+void HttpRequestTestObjectType::test<5>()
+{
+ set_test_name("HttpRequest GET + Stop execution");
+
+ // Handler can be stack-allocated *if* there are no dangling
+ // references to it after completion of this method.
+ // Create before memory record as the string copy will bump numbers.
+ TestHandler2 handler(this, "handler");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+ mHandlerCalls = 0;
+
+ // Get singletons created
+ HttpRequest::createService();
+
+ // Start threading early so that thread memory is invariant
+ // over the test.
+ HttpRequest::startThread();
+
+ // create a new ref counted object with an implicit reference
+ HttpRequest * req = new HttpRequest();
+ ensure("Memory allocated on construction", mMemTotal < GetMemTotal());
+
+ // Issue a GET that can't connect
+ mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT);
+ HttpHandle handle = req->requestGetByteRange(HttpRequest::DEFAULT_POLICY_ID,
+ 0.0f,
+ "http://localhost:2/nothing/here",
+ 0,
+ 0,
+ NULL,
+ NULL,
+ &handler);
+ ensure("Valid handle returned for ranged request", handle != LLCORE_HTTP_HANDLE_INVALID);
+
+ // Run the notification pump.
+ int count(0);
+ int limit(20);
+ while (count++ < limit && mHandlerCalls < 1)
+ {
+ req->update(1000);
+ usleep(100000);
+ }
+ ensure("Request executed in reasonable time", count < limit);
+ ensure("One handler invocation for request", mHandlerCalls == 1);
+
+ // Okay, request a shutdown of the servicing thread
+ mStatus = HttpStatus();
+ handle = req->requestStopThread(&handler);
+ ensure("Valid handle returned for second request", handle != LLCORE_HTTP_HANDLE_INVALID);
+
+ // Run the notification pump again
+ count = 0;
+ limit = 100;
+ while (count++ < limit && mHandlerCalls < 2)
+ {
+ req->update(1000);
+ usleep(100000);
+ }
+ ensure("Second request executed in reasonable time", count < limit);
+ ensure("Second handler invocation", mHandlerCalls == 2);
+
+ // See that we actually shutdown the thread
+ count = 0;
+ limit = 10;
+ while (count++ < limit && ! HttpService::isStopped())
+ {
+ usleep(100000);
+ }
+ ensure("Thread actually stopped running", HttpService::isStopped());
+
+ // release the request object
+ delete req;
+ req = NULL;
+
+ // Shut down service
+ HttpRequest::destroyService();
+
+ // We have left over state so can't really say something
+ // definitive about memory usage at the end of this.
+ ensure("Two handler calls on the way out", 2 == mHandlerCalls);
+ // printf("Old mem: %d, New mem: %d\n", mMemTotal, GetMemTotal());
+ ensure("Memory usage back to that at entry", mMemTotal == GetMemTotal());
+}
+
+} // end namespace tut
+
+namespace
+{
+
+#if defined(WIN32)
+
+void usleep(unsigned long usec)
+{
+ Sleep((DWORD) (usec / 1000UL));
+}
+
+#endif
+
+}
+
+#endif // TEST_LLCORE_HTTP_REQUEST_H_
diff --git a/indra/llcorehttp/tests/test_httprequestqueue.hpp b/indra/llcorehttp/tests/test_httprequestqueue.hpp
new file mode 100644
index 0000000000..1de2d8f9ab
--- /dev/null
+++ b/indra/llcorehttp/tests/test_httprequestqueue.hpp
@@ -0,0 +1,186 @@
+/**
+ * @file test_httprequestqueue.hpp
+ * @brief unit tests for the LLCore::HttpRequestQueue class
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+#ifndef TEST_LLCORE_HTTP_REQUESTQUEUE_H_
+#define TEST_LLCORE_HTTP_REQUESTQUEUE_H_
+
+#include "_httprequestqueue.h"
+
+#include <iostream>
+
+#include "test_allocator.h"
+#include "_httpoperation.h"
+
+
+using namespace LLCoreInt;
+
+
+
+namespace tut
+{
+
+struct HttpRequestqueueTestData
+{
+ // the test objects inherit from this so the member functions and variables
+ // can be referenced directly inside of the test functions.
+ size_t mMemTotal;
+};
+
+typedef test_group<HttpRequestqueueTestData> HttpRequestqueueTestGroupType;
+typedef HttpRequestqueueTestGroupType::object HttpRequestqueueTestObjectType;
+HttpRequestqueueTestGroupType HttpRequestqueueTestGroup("HttpRequestqueue Tests");
+
+template <> template <>
+void HttpRequestqueueTestObjectType::test<1>()
+{
+ set_test_name("HttpRequestQueue construction");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ HttpRequestQueue::init();
+
+ ensure("One ref on construction of HttpRequestQueue", HttpRequestQueue::instanceOf()->getRefCount() == 1);
+ ensure("Memory being used", mMemTotal < GetMemTotal());
+
+ // release the implicit reference, causing the object to be released
+ HttpRequestQueue::term();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+}
+
+template <> template <>
+void HttpRequestqueueTestObjectType::test<2>()
+{
+ set_test_name("HttpRequestQueue refcount works");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ HttpRequestQueue::init();
+
+ HttpRequestQueue * rq = HttpRequestQueue::instanceOf();
+ rq->addRef();
+
+ // release the singleton, hold on to the object
+ HttpRequestQueue::term();
+
+ ensure("One ref after term() called", rq->getRefCount() == 1);
+ ensure("Memory being used", mMemTotal < GetMemTotal());
+
+ // Drop ref
+ rq->release();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+}
+
+template <> template <>
+void HttpRequestqueueTestObjectType::test<3>()
+{
+ set_test_name("HttpRequestQueue addOp/fetchOp work");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ HttpRequestQueue::init();
+
+ HttpRequestQueue * rq = HttpRequestQueue::instanceOf();
+
+ HttpOperation * op = new HttpOpNull();
+
+ rq->addOp(op); // transfer my refcount
+
+ op = rq->fetchOp(true); // Potentially hangs the test on failure
+ ensure("One goes in, one comes out", NULL != op);
+ op->release();
+
+ op = rq->fetchOp(false);
+ ensure("Better not be two of them", NULL == op);
+
+ // release the singleton, hold on to the object
+ HttpRequestQueue::term();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+}
+
+template <> template <>
+void HttpRequestqueueTestObjectType::test<4>()
+{
+ set_test_name("HttpRequestQueue addOp/fetchAll work");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ HttpRequestQueue::init();
+
+ HttpRequestQueue * rq = HttpRequestQueue::instanceOf();
+
+ HttpOperation * op = new HttpOpNull();
+ rq->addOp(op); // transfer my refcount
+
+ op = new HttpOpNull();
+ rq->addOp(op); // transfer my refcount
+
+ op = new HttpOpNull();
+ rq->addOp(op); // transfer my refcount
+
+ {
+ HttpRequestQueue::OpContainer ops;
+ rq->fetchAll(true, ops); // Potentially hangs the test on failure
+ ensure("Three go in, three come out", 3 == ops.size());
+
+ op = rq->fetchOp(false);
+ ensure("Better not be any more of them", NULL == op);
+
+ // release the singleton, hold on to the object
+ HttpRequestQueue::term();
+
+ // We're still holding onto the ops.
+ ensure(mMemTotal < GetMemTotal());
+
+ // Release them
+ while (! ops.empty())
+ {
+ HttpOperation * op = ops.front();
+ ops.erase(ops.begin());
+ op->release();
+ }
+ }
+
+ // Should be clean
+ ensure("All memory returned", mMemTotal == GetMemTotal());
+}
+
+} // end namespace tut
+
+
+#endif // TEST_LLCORE_HTTP_REQUESTQUEUE_H_
diff --git a/indra/llcorehttp/tests/test_httpstatus.hpp b/indra/llcorehttp/tests/test_httpstatus.hpp
new file mode 100644
index 0000000000..fa5803a17c
--- /dev/null
+++ b/indra/llcorehttp/tests/test_httpstatus.hpp
@@ -0,0 +1,163 @@
+/**
+ * @file test_llrefcounted
+ * @brief unit tests for HttpStatus struct
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef TEST_HTTP_STATUS_H_
+#define TEST_HTTP_STATUS_H_
+
+#include <core-http/httpcommon.h>
+
+#include <curl/curl.h>
+#include <curl/multi.h>
+
+using namespace LLCore;
+
+namespace tut
+{
+
+struct HttpStatusTestData
+{
+ HttpStatusTestData()
+ {}
+};
+
+typedef test_group<HttpStatusTestData> HttpStatusTestGroupType;
+typedef HttpStatusTestGroupType::object HttpStatusTestObjectType;
+
+HttpStatusTestGroupType HttpStatusTestGroup("HttpStatus Tests");
+
+template <> template <>
+void HttpStatusTestObjectType::test<1>()
+{
+ set_test_name("HttpStatus construction");
+
+ // auto allocation fine for this
+ HttpStatus status;
+ status.mType = HttpStatus::EXT_CURL_EASY;
+ status.mStatus = 0;
+
+ ensure(bool(status));
+ ensure(false == !(status));
+
+ status.mType = HttpStatus::EXT_CURL_MULTI;
+ status.mStatus = 0;
+
+ ensure(bool(status));
+ ensure(false == !(status));
+
+ status.mType = HttpStatus::LLCORE;
+ status.mStatus = HE_SUCCESS;
+
+ ensure(bool(status));
+ ensure(false == !(status));
+
+ status.mType = HttpStatus::EXT_CURL_MULTI;
+ status.mStatus = -1;
+
+ ensure(false == bool(status));
+ ensure(!(status));
+
+ status.mType = HttpStatus::EXT_CURL_EASY;
+ status.mStatus = CURLE_BAD_DOWNLOAD_RESUME;
+
+ ensure(false == bool(status));
+ ensure(!(status));
+}
+
+
+template <> template <>
+void HttpStatusTestObjectType::test<2>()
+{
+ set_test_name("HttpStatus memory structure");
+
+ // Require that an HttpStatus object can be trivially
+ // returned as a function return value in registers.
+ // One should fit in an int on all platforms.
+
+ ensure(sizeof(HttpStatus) <= sizeof(int));
+}
+
+
+template <> template <>
+void HttpStatusTestObjectType::test<3>()
+{
+ set_test_name("HttpStatus valid error string conversion");
+
+ HttpStatus status;
+ status.mType = HttpStatus::EXT_CURL_EASY;
+ status.mStatus = 0;
+ std::string msg = status.toString();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure(msg.empty());
+
+ status.mType = HttpStatus::EXT_CURL_EASY;
+ status.mStatus = CURLE_BAD_FUNCTION_ARGUMENT;
+ msg = status.toString();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure(! msg.empty());
+
+ status.mType = HttpStatus::EXT_CURL_MULTI;
+ status.mStatus = CURLM_OUT_OF_MEMORY;
+ msg = status.toString();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure(! msg.empty());
+
+ status.mType = HttpStatus::LLCORE;
+ status.mStatus = HE_SHUTTING_DOWN;
+ msg = status.toString();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure(! msg.empty());
+}
+
+
+template <> template <>
+void HttpStatusTestObjectType::test<4>()
+{
+ set_test_name("HttpStatus invalid error string conversion");
+
+ HttpStatus status;
+ status.mType = HttpStatus::EXT_CURL_EASY;
+ status.mStatus = 32726;
+ std::string msg = status.toString();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure(! msg.empty());
+
+ status.mType = HttpStatus::EXT_CURL_MULTI;
+ status.mStatus = -470;
+ msg = status.toString();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure(! msg.empty());
+
+ status.mType = HttpStatus::LLCORE;
+ status.mStatus = 923;
+ msg = status.toString();
+ // std::cout << "Result: " << msg << std::endl;
+ ensure(! msg.empty());
+}
+
+} // end namespace tut
+
+#endif // TEST_HTTP_STATUS_H
+
diff --git a/indra/llcorehttp/tests/test_refcounted.hpp b/indra/llcorehttp/tests/test_refcounted.hpp
new file mode 100644
index 0000000000..6a17947288
--- /dev/null
+++ b/indra/llcorehttp/tests/test_refcounted.hpp
@@ -0,0 +1,156 @@
+/**
+ * @file test_refcounted.hpp
+ * @brief unit tests for the LLCoreInt::RefCounted class
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+#ifndef TEST_LLCOREINT_REF_COUNTED_H_
+#define TEST_LLCOREINT_REF_COUNTED_H_
+
+#include <_refcounted.h>
+
+#include "test_allocator.h"
+
+using namespace LLCoreInt;
+
+namespace tut
+{
+ struct RefCountedTestData
+ {
+ // the test objects inherit from this so the member functions and variables
+ // can be referenced directly inside of the test functions.
+ size_t mMemTotal;
+ };
+
+ typedef test_group<RefCountedTestData> RefCountedTestGroupType;
+ typedef RefCountedTestGroupType::object RefCountedTestObjectType;
+ RefCountedTestGroupType RefCountedTestGroup("RefCounted Tests");
+
+ template <> template <>
+ void RefCountedTestObjectType::test<1>()
+ {
+ set_test_name("RefCounted construction with implicit count");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ RefCounted * rc = new RefCounted(true);
+ ensure(rc->getRefCount() == 1);
+
+ // release the implicit reference, causing the object to be released
+ rc->release();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+ }
+
+ template <> template <>
+ void RefCountedTestObjectType::test<2>()
+ {
+ set_test_name("RefCounted construction without implicit count");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ // create a new ref counted object with an implicit reference
+ RefCounted * rc = new RefCounted(false);
+ ensure(rc->getRefCount() == 0);
+
+ // add a reference
+ rc->addRef();
+ ensure(rc->getRefCount() == 1);
+
+ // release the implicit reference, causing the object to be released
+ rc->release();
+
+ ensure(mMemTotal == GetMemTotal());
+ }
+
+ template <> template <>
+ void RefCountedTestObjectType::test<3>()
+ {
+ set_test_name("RefCounted addRef and release");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ RefCounted * rc = new RefCounted(false);
+
+ for (int i = 0; i < 1024; ++i)
+ {
+ rc->addRef();
+ }
+
+ ensure(rc->getRefCount() == 1024);
+
+ for (int i = 0; i < 1024; ++i)
+ {
+ rc->release();
+ }
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+ }
+
+ template <> template <>
+ void RefCountedTestObjectType::test<4>()
+ {
+ set_test_name("RefCounted isLastRef check");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ RefCounted * rc = new RefCounted(true);
+
+ // with only one reference, isLastRef should be true
+ ensure(rc->isLastRef());
+
+ // release it to clean up memory
+ rc->release();
+
+ // make sure we didn't leak any memory
+ ensure(mMemTotal == GetMemTotal());
+ }
+
+ template <> template <>
+ void RefCountedTestObjectType::test<5>()
+ {
+ set_test_name("RefCounted noRef check");
+
+ // record the total amount of dynamically allocated memory
+ mMemTotal = GetMemTotal();
+
+ RefCounted * rc = new RefCounted(false);
+
+ // set the noRef
+ rc->noRef();
+
+ // with only one reference, isLastRef should be true
+ ensure(rc->getRefCount() == RefCounted::NOT_REF_COUNTED);
+
+ // allow this memory leak, but check that we're leaking a known amount
+ ensure(mMemTotal == (GetMemTotal() - sizeof(RefCounted)));
+ }
+}
+
+#endif // TEST_LLCOREINT_REF_COUNTED_H_