Apertura del repositorio

This commit is contained in:
2025-05-24 18:09:39 -03:00
parent 76e6359dad
commit d883ddd0d0
35253 changed files with 2891973 additions and 2 deletions
+141
View File
@@ -0,0 +1,141 @@
/**
* @file commtest.h
* @author Nat Goodspeed
* @date 2009-01-09
* @brief
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#if ! defined(LL_COMMTEST_H)
#define LL_COMMTEST_H
#include "networkio.h"
#include "llevents.h"
#include "llsd.h"
#include "llhost.h"
#include "llexception.h"
#include "llstring.h"
#include "stringize.h"
#include <map>
#include <string>
#include <boost/lexical_cast.hpp>
struct CommtestError: public LLException
{
CommtestError(const std::string& what): LLException(what) {}
};
static bool query_verbose()
{
std::string strbose(LLStringUtil::getenv("INTEGRATION_TEST_VERBOSE", "1"));
return (! (strbose == "0" || strbose == "off" ||
strbose == "false" || strbose == "quiet"));
}
bool verbose()
{
// This should only be initialized once.
static bool vflag = query_verbose();
return vflag;
}
static int query_port(const std::string& var)
{
const char* cport = getenv(var.c_str());
if (! cport)
{
LLTHROW(CommtestError(STRINGIZE("missing environment variable" << var)));
}
// This will throw, too, if the value of PORT isn't numeric.
int port(boost::lexical_cast<int>(cport));
if (verbose())
{
std::cout << "getport('" << var << "') = " << port << std::endl;
}
return port;
}
static int getport(const std::string& var)
{
typedef std::map<std::string, int> portsmap;
static portsmap ports;
// We can do this with a single map lookup with map::insert(). Either it
// returns an existing entry and 'false' (not newly inserted), or it
// inserts the specified value and 'true'.
std::pair<portsmap::iterator, bool> inserted(ports.insert(portsmap::value_type(var, 0)));
if (inserted.second)
{
// We haven't yet seen this var. Remember its value.
inserted.first->second = query_port(var);
}
// Return the (existing or new) iterator's value.
return inserted.first->second;
}
/**
* This struct is shared by a couple of standalone comm tests (ADD_COMM_BUILD_TEST).
*/
struct commtest_data
{
NetworkIO& netio;
LLEventPumps& pumps;
LLEventStream replyPump, errorPump;
LLSD result;
bool success;
LLHost host;
std::string server;
commtest_data():
netio(NetworkIO::instance()),
pumps(LLEventPumps::instance()),
replyPump("reply"),
errorPump("error"),
success(false),
host("127.0.0.1", getport("PORT")),
server(STRINGIZE("http://" << host.getString() << "/"))
{
replyPump.listen("self", boost::bind(&commtest_data::outcome, this, _1, true));
errorPump.listen("self", boost::bind(&commtest_data::outcome, this, _1, false));
}
static int getport(const std::string& var)
{
// We have a couple consumers of commtest_data::getport(). But we've
// since moved it out to the global namespace. So this is just a
// facade.
return ::getport(var);
}
bool outcome(const LLSD& _result, bool _success)
{
// std::cout << "commtest_data::outcome(" << _result << ", " << _success << ")\n";
result = _result;
success = _success;
// Break the wait loop in NetworkIO::pump(), otherwise devs get
// irritated at making the big monolithic test executable take longer
pumps.obtain("done").post(success);
return false;
}
};
#endif /* ! defined(LL_COMMTEST_H) */
@@ -0,0 +1,193 @@
/**
* @file llareslistener_test.cpp
* @author Mark Palange
* @date 2009-02-26
* @brief Tests of llareslistener.h.
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#if LL_WINDOWS
#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
#endif
// Precompiled header
#include "linden_common.h"
// associated header
#include "../llareslistener.h"
// STL headers
#include <iostream>
// std headers
// external library headers
#include <boost/bind.hpp>
// other Linden headers
#include "llsd.h"
#include "llares.h"
#include "../test/lltut.h"
#include "llevents.h"
#include "tests/wrapllerrs.h"
/*****************************************************************************
* Dummy stuff
*****************************************************************************/
LLAres::LLAres():
// Simulate this much of the real LLAres constructor: we need an
// LLAresListener instance.
mListener(new LLAresListener("LLAres", this))
{}
LLAres::~LLAres() {}
void LLAres::rewriteURI(const std::string &uri,
LLAres::UriRewriteResponder *resp)
{
// This is the only LLAres method I chose to implement.
// The effect is that LLAres returns immediately with
// a result that is equal to the input uri.
std::vector<std::string> result;
result.push_back(uri);
resp->rewriteResult(result);
}
LLAres::QueryResponder::~QueryResponder() {}
void LLAres::QueryResponder::queryError(int) {}
void LLAres::QueryResponder::queryResult(char const*, size_t) {}
LLQueryResponder::LLQueryResponder() {}
void LLQueryResponder::queryResult(char const*, size_t) {}
void LLQueryResponder::querySuccess() {}
void LLAres::UriRewriteResponder::queryError(int) {}
void LLAres::UriRewriteResponder::querySuccess() {}
void LLAres::UriRewriteResponder::rewriteResult(const std::vector<std::string>& uris) {}
/*****************************************************************************
* TUT
*****************************************************************************/
namespace tut
{
struct data
{
LLAres dummyAres;
};
typedef test_group<data> llareslistener_group;
typedef llareslistener_group::object object;
llareslistener_group llareslistenergrp("llareslistener");
struct ResponseCallback
{
std::vector<std::string> mURIs;
bool operator()(const LLSD& response)
{
mURIs.clear();
for (LLSD::array_const_iterator ri(response.beginArray()), rend(response.endArray());
ri != rend; ++ri)
{
mURIs.push_back(*ri);
}
return false;
}
};
template<> template<>
void object::test<1>()
{
set_test_name("test event");
// Tests the success and failure cases, since they both use
// the same code paths in the LLAres responder.
ResponseCallback response;
std::string pumpname("trigger");
// Since we're asking LLEventPumps to obtain() the pump by the desired
// name, it will persist beyond the current scope, so ensure we
// disconnect from it when 'response' goes away.
LLTempBoundListener temp(
LLEventPumps::instance().obtain(pumpname).listen("rewriteURIresponse",
boost::bind(&ResponseCallback::operator(), &response, _1)));
// Now build an LLSD request that will direct its response events to
// that pump.
const std::string testURI("login.bar.com");
LLSD request;
request["op"] = "rewriteURI";
request["uri"] = testURI;
request["reply"] = pumpname;
LLEventPumps::instance().obtain("LLAres").post(request);
ensure_equals(response.mURIs.size(), 1);
ensure_equals(response.mURIs.front(), testURI);
}
template<> template<>
void object::test<2>()
{
set_test_name("bad op");
WrapLLErrs capture;
LLSD request;
request["op"] = "foo";
std::string threw = capture.catch_llerrs([&request](){
LLEventPumps::instance().obtain("LLAres").post(request);
});
ensure_contains("LLAresListener bad op", threw, "bad");
}
template<> template<>
void object::test<3>()
{
set_test_name("bad rewriteURI request");
WrapLLErrs capture;
LLSD request;
request["op"] = "rewriteURI";
std::string threw = capture.catch_llerrs([&request](){
LLEventPumps::instance().obtain("LLAres").post(request);
});
ensure_contains("LLAresListener bad req", threw, "missing");
ensure_contains("LLAresListener bad req", threw, "reply");
ensure_contains("LLAresListener bad req", threw, "uri");
}
template<> template<>
void object::test<4>()
{
set_test_name("bad rewriteURI request");
WrapLLErrs capture;
LLSD request;
request["op"] = "rewriteURI";
request["reply"] = "nonexistent";
std::string threw = capture.catch_llerrs([&request](){
LLEventPumps::instance().obtain("LLAres").post(request);
});
ensure_contains("LLAresListener bad req", threw, "missing");
ensure_contains("LLAresListener bad req", threw, "uri");
ensure_does_not_contain("LLAresListener bad req", threw, "reply");
}
template<> template<>
void object::test<5>()
{
set_test_name("bad rewriteURI request");
WrapLLErrs capture;
LLSD request;
request["op"] = "rewriteURI";
request["uri"] = "foo.bar.com";
std::string threw = capture.catch_llerrs([&request](){
LLEventPumps::instance().obtain("LLAres").post(request);
});
ensure_contains("LLAresListener bad req", threw, "missing");
ensure_contains("LLAresListener bad req", threw, "reply");
ensure_does_not_contain("LLAresListener bad req", threw, "uri");
}
}
@@ -0,0 +1,102 @@
/**
* @file llavatarnamecache_test.cpp
* @author James Cook
* @brief LLAvatarNameCache test cases.
*
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "../llavatarnamecache.h"
#include "../test/lltut.h"
namespace tut
{
struct avatarnamecache_data
{
};
typedef test_group<avatarnamecache_data> avatarnamecache_test;
typedef avatarnamecache_test::object avatarnamecache_object;
tut::avatarnamecache_test avatarnamecache_testcase("LLAvatarNameCache");
template<> template<>
void avatarnamecache_object::test<1>()
{
bool valid = false;
S32 max_age = 0;
valid = max_age_from_cache_control("max-age=3600", &max_age);
ensure("typical input valid", valid);
ensure_equals("typical input parsed", max_age, 3600);
valid = max_age_from_cache_control(
" max-age=600 , no-cache,private=\"stuff\" ", &max_age);
ensure("complex input valid", valid);
ensure_equals("complex input parsed", max_age, 600);
valid = max_age_from_cache_control(
"no-cache, max-age = 123 ", &max_age);
ensure("complex input 2 valid", valid);
ensure_equals("complex input 2 parsed", max_age, 123);
}
template<> template<>
void avatarnamecache_object::test<2>()
{
bool valid = false;
S32 max_age = -1;
valid = max_age_from_cache_control("", &max_age);
ensure("empty input returns invalid", !valid);
ensure_equals("empty input doesn't change val", max_age, -1);
valid = max_age_from_cache_control("no-cache", &max_age);
ensure("no max-age field returns invalid", !valid);
valid = max_age_from_cache_control("max", &max_age);
ensure("just 'max' returns invalid", !valid);
valid = max_age_from_cache_control("max-age", &max_age);
ensure("partial max-age is invalid", !valid);
valid = max_age_from_cache_control("max-age=", &max_age);
ensure("longer partial max-age is invalid", !valid);
valid = max_age_from_cache_control("max-age=FOO", &max_age);
ensure("invalid integer max-age is invalid", !valid);
valid = max_age_from_cache_control("max-age 234", &max_age);
ensure("space separated max-age is invalid", !valid);
valid = max_age_from_cache_control("max-age=0", &max_age);
ensure("zero max-age is valid", valid);
// *TODO: Handle "0000" as zero
//valid = max_age_from_cache_control("max-age=0000", &max_age);
//ensure("multi-zero max-age is valid", valid);
valid = max_age_from_cache_control("max-age=-123", &max_age);
ensure("less than zero max-age is invalid", !valid);
}
}
@@ -0,0 +1,179 @@
/**
* @file llcoproceduremanager_test.cpp
* @author Brad
* @date 2019-02
* @brief LLCoprocedureManager unit test
*
* $LicenseInfo:firstyear=2019&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "llwin32headers.h"
#include "linden_common.h"
#include "llsdserialize.h"
#include "../llcoproceduremanager.h"
#include <functional>
#include <boost/fiber/fiber.hpp>
#include <boost/fiber/buffered_channel.hpp>
#include <boost/fiber/unbuffered_channel.hpp>
#include "../test/lltut.h"
#include "../test/sync.h"
#if LL_WINDOWS
// disable unreachable code warnings
#pragma warning(disable: 4702)
#endif
LLCoreHttpUtil::HttpCoroutineAdapter::HttpCoroutineAdapter(std::string const&, unsigned int)
{
}
void LLCoreHttpUtil::HttpCoroutineAdapter::cancelSuspendedOperation()
{
}
LLCoreHttpUtil::HttpCoroutineAdapter::~HttpCoroutineAdapter()
{
}
LLCore::HttpRequest::HttpRequest()
{
}
LLCore::HttpRequest::~HttpRequest()
{
}
namespace tut
{
struct coproceduremanager_test
{
coproceduremanager_test()
{
}
~coproceduremanager_test()
{
LLCoprocedureManager::instance().close();
}
};
typedef test_group<coproceduremanager_test> coproceduremanager_t;
typedef coproceduremanager_t::object coproceduremanager_object_t;
tut::coproceduremanager_t tut_coproceduremanager("LLCoprocedureManager");
template<> template<>
void coproceduremanager_object_t::test<1>()
{
Sync sync;
int foo = 0;
LLCoprocedureManager::instance().initializePool("PoolName");
LLCoprocedureManager::instance().enqueueCoprocedure("PoolName", "ProcName",
[&foo, &sync] (LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t & ptr, const LLUUID & id) {
sync.bump();
foo = 1;
});
sync.yield();
ensure_equals("coprocedure failed to update foo", foo, 1);
LLCoprocedureManager::instance().close("PoolName");
}
template<> template<>
void coproceduremanager_object_t::test<2>()
{
const size_t capacity = 2;
boost::fibers::buffered_channel<std::function<void(void)>> chan(capacity);
boost::fibers::fiber worker([&chan]() {
chan.value_pop()();
});
chan.push([]() {
LL_INFOS("Test") << "test 1" << LL_ENDL;
});
worker.join();
}
template<> template<>
void coproceduremanager_object_t::test<3>()
{
boost::fibers::unbuffered_channel<std::function<void(void)>> chan;
boost::fibers::fiber worker([&chan]() {
chan.value_pop()();
});
chan.push([]() {
LL_INFOS("Test") << "test 1" << LL_ENDL;
});
worker.join();
}
template<> template<>
void coproceduremanager_object_t::test<4>()
{
boost::fibers::buffered_channel<std::function<void(void)>> chan(4);
boost::fibers::fiber worker([&chan]() {
std::function<void(void)> f;
// using namespace std::chrono_literals;
// const auto timeout = 5s;
// boost::fibers::channel_op_status status;
while (chan.pop(f) != boost::fibers::channel_op_status::closed)
{
LL_INFOS("CoWorker") << "got coproc" << LL_ENDL;
f();
}
LL_INFOS("CoWorker") << "got closed" << LL_ENDL;
});
int counter = 0;
for (int i = 0; i < 5; ++i)
{
LL_INFOS("CoMain") << "pushing coproc " << i << LL_ENDL;
chan.push([&counter]() {
LL_INFOS("CoProc") << "in coproc" << LL_ENDL;
++counter;
});
}
LL_INFOS("CoMain") << "closing channel" << LL_ENDL;
chan.close();
LL_INFOS("CoMain") << "joining worker" << LL_ENDL;
worker.join();
LL_INFOS("CoMain") << "checking count" << LL_ENDL;
ensure_equals("coprocedure failed to update counter", counter, 5);
}
} // namespace tut
+99
View File
@@ -0,0 +1,99 @@
/**
* @file llcurl_stub.cpp
* @brief stub class to allow unit testing
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 LL_CURL_STUB_CPP
#define LL_CURL_STUB_CPP
#include "linden_common.h"
#include "llcurl.h"
#include "llhttpconstants.cpp"
LLCurl::Responder::Responder()
{
}
void LLCurl::Responder::httpCompleted()
{
if (isGoodStatus())
{
httpSuccess();
}
else
{
httpFailure();
}
}
void LLCurl::Responder::completedRaw(LLChannelDescriptors const&,
std::shared_ptr<LLBufferArray> const&)
{
}
void LLCurl::Responder::httpFailure()
{
}
LLCurl::Responder::~Responder ()
{
}
void LLCurl::Responder::httpSuccess()
{
}
std::string LLCurl::Responder::dumpResponse() const
{
return "dumpResponse()";
}
void LLCurl::Responder::successResult(const LLSD& content)
{
setResult(HTTP_OK, "", content);
httpSuccess();
}
void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content)
{
setResult(status, reason, content);
httpFailure();
}
void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content)
{
setResult(status, reason, content);
httpCompleted();
}
void LLCurl::Responder::setResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */)
{
mStatus = status;
mReason = reason;
mContent = content;
}
#endif
+271
View File
@@ -0,0 +1,271 @@
/**
* @file llhost_test.cpp
* @author Adroit
* @date 2007-02
* @brief llhost test cases.
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "../llhost.h"
#include "../test/lltut.h"
namespace tut
{
struct host_data
{
};
typedef test_group<host_data> host_test;
typedef host_test::object host_object;
tut::host_test host_testcase("LLHost");
template<> template<>
void host_object::test<1>()
{
LLHost host;
ensure("IP address is not NULL", (0 == host.getAddress()) && (0 == host.getPort()) && !host.isOk());
}
template<> template<>
void host_object::test<2>()
{
U32 ip_addr = 0xc098017d;
U32 port = 8080;
LLHost host(ip_addr, port);
ensure("IP address is invalid", ip_addr == host.getAddress());
ensure("Port Number is invalid", port == host.getPort());
ensure("IP address and port number both should be ok", host.isOk());
}
template<> template<>
void host_object::test<3>()
{
const char* str = "192.168.1.1";
U32 port = 8080;
LLHost host(str, port);
ensure("IP address could not be processed", (host.getAddress() == ip_string_to_u32(str)));
ensure("Port Number is invalid", (port == host.getPort()));
}
template<> template<>
void host_object::test<4>()
{
U32 ip = ip_string_to_u32("192.168.1.1");
U32 port = 22;
U64 ip_port = (((U64) ip) << 32) | port;
LLHost host(ip_port);
ensure("IP address is invalid", ip == host.getAddress());
ensure("Port Number is invalid", port == host.getPort());
}
template<> template<>
void host_object::test<5>()
{
std::string ip_port_string = "192.168.1.1:8080";
U32 ip = ip_string_to_u32("192.168.1.1");
U32 port = 8080;
LLHost host(ip_port_string);
ensure("IP address from IP:port is invalid", ip == host.getAddress());
ensure("Port Number from from IP:port is invalid", port == host.getPort());
}
template<> template<>
void host_object::test<6>()
{
U32 ip = 0xc098017d, port = 8080;
LLHost host;
host.set(ip,port);
ensure("IP address is invalid", (ip == host.getAddress()));
ensure("Port Number is invalid", (port == host.getPort()));
}
template<> template<>
void host_object::test<7>()
{
const char* str = "192.168.1.1";
U32 port = 8080, ip;
LLHost host;
host.set(str,port);
ip = ip_string_to_u32(str);
ensure("IP address is invalid", (ip == host.getAddress()));
ensure("Port Number is invalid", (port == host.getPort()));
str = "64.233.187.99";
ip = ip_string_to_u32(str);
host.setAddress(str);
ensure("IP address is invalid", (ip == host.getAddress()));
ip = 0xc098017b;
host.setAddress(ip);
ensure("IP address is invalid", (ip == host.getAddress()));
// should still use the old port
ensure("Port Number is invalid", (port == host.getPort()));
port = 8084;
host.setPort(port);
ensure("Port Number is invalid", (port == host.getPort()));
// should still use the old address
ensure("IP address is invalid", (ip == host.getAddress()));
}
template<> template<>
void host_object::test<8>()
{
const std::string str("192.168.1.1");
U32 port = 8080;
LLHost host;
host.set(str,port);
std::string ip_string = host.getIPString();
ensure("Function Failed", (ip_string == str));
std::string ip_string_port = host.getIPandPort();
ensure("Function Failed", (ip_string_port == "192.168.1.1:8080"));
}
// getHostName() and setHostByName
template<> template<>
void host_object::test<9>()
{
skip("this test is irreparably flaky");
// skip("setHostByName(\"google.com\"); getHostName() -> (e.g.) \"yx-in-f100.1e100.net\"");
// nat: is it reasonable to expect LLHost::getHostName() to echo
// back something resembling the string passed to setHostByName()?
//
// If that's not even reasonable, would a round trip in the /other/
// direction make more sense? (Call getHostName() for something with
// known IP address; call setHostByName(); verify IP address)
//
// Failing that... is there a plausible way to test getHostName() and
// setHostByName()? Hopefully without putting up a dummy local DNS
// server?
// monty: If you don't control the DNS server or the DNS configuration
// for the test point then, no, none of these will necessarily be
// reliable and may start to fail at any time. Forward translation
// is subject to CNAME records and round-robin address assignment.
// Reverse lookup is 1-to-many and is more and more likely to have
// nothing to do with the forward translation.
//
// So the test is increasingly meaningless on a real network.
std::string hostStr = "lindenlab.com";
LLHost host;
host.setHostByName(hostStr);
// reverse DNS will likely result in appending of some
// sub-domain to the main hostname. so look for
// the main domain name and not do the exact compare
std::string hostname = host.getHostName();
try
{
ensure("getHostName failed", hostname.find(hostStr) != std::string::npos);
}
catch (const std::exception&)
{
std::cerr << "set '" << hostStr << "'; reported '" << hostname << "'" << std::endl;
throw;
}
}
// setHostByName for dotted IP
template<> template<>
void host_object::test<10>()
{
std::string hostStr = "64.233.167.99";
LLHost host;
host.setHostByName(hostStr);
ensure("SetHostByName for dotted IP Address failed", host.getAddress() == ip_string_to_u32(hostStr.c_str()));
}
template<> template<>
void host_object::test<11>()
{
LLHost host1(0xc098017d, 8080);
LLHost host2 = host1;
ensure("Both IP addresses are not same", (host1.getAddress() == host2.getAddress()));
ensure("Both port numbers are not same", (host1.getPort() == host2.getPort()));
}
template<> template<>
void host_object::test<12>()
{
LLHost host1("192.168.1.1", 8080);
std::string str1 = "192.168.1.1:8080";
std::ostringstream stream;
stream << host1;
ensure("Operator << failed", ( stream.str()== str1));
// There is no istream >> llhost operator.
//std::istringstream is(stream.str());
//LLHost host2;
//is >> host2;
//ensure("Operator >> failed. Not compatible with <<", host1 == host2);
}
// operators ==, !=, <
template<> template<>
void host_object::test<13>()
{
U32 ip_addr = 0xc098017d;
U32 port = 8080;
LLHost host1(ip_addr, port);
LLHost host2(ip_addr, port);
ensure("operator== failed", host1 == host2);
// change port
host2.setPort(7070);
ensure("operator!= failed", host1 != host2);
// set port back to 8080 and change IP address now
host2.setPort(8080);
host2.setAddress(ip_addr+10);
ensure("operator!= failed", host1 != host2);
ensure("operator< failed", host1 < host2);
// set IP address back to same value and change port
host2.setAddress(ip_addr);
host2.setPort(host1.getPort() + 10);
ensure("operator< failed", host1 < host2);
}
// invalid ip address string
template<> template<>
void host_object::test<14>()
{
LLHost host1("10.0.1.2", 6143);
ensure("10.0.1.2 should be a valid address", host1.isOk());
LLHost host2("booger-brains", 6143);
ensure("booger-brains should be an invalid ip addess", !host2.isOk());
LLHost host3("255.255.255.255", 6143);
ensure("255.255.255.255 should be valid broadcast address", host3.isOk());
}
}
+311
View File
@@ -0,0 +1,311 @@
/**
* @file llhttpclient_test.cpp
* @brief Testing the HTTP client classes.
*
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
/**
*
* These classes test the HTTP client framework.
*
*/
#include <tut/tut.hpp>
#include "linden_common.h"
#include "lltut.h"
#include "llhttpclient.h"
#include "llformat.h"
#include "llpipeutil.h"
#include "llproxy.h"
#include "llpumpio.h"
#include "lliosocket.h"
#include "llstring.h"
#include "stringize.h"
#include "llcleanup.h"
namespace tut
{
struct HTTPClientTestData
{
public:
HTTPClientTestData():
PORT(LLStringUtil::getenv("PORT")),
// Turning NULL PORT into empty string doesn't make things work;
// that's just to keep this initializer from blowing up. We test
// PORT separately in the constructor body.
local_server(STRINGIZE("http://127.0.0.1:" << PORT << "/"))
{
ensure("Set environment variable PORT to local test server port", !PORT.empty());
apr_pool_create(&mPool, NULL);
LLCurl::initClass(false);
mClientPump = new LLPumpIO(mPool);
LLHTTPClient::setPump(*mClientPump);
}
~HTTPClientTestData()
{
delete mClientPump;
SUBSYSTEM_CLEANUP(LLProxy);
apr_pool_destroy(mPool);
}
void runThePump(float timeout = 100.0f)
{
LLTimer timer;
timer.setTimerExpirySec(timeout);
while(!mSawCompleted && !mSawCompletedHeader && !timer.hasExpired())
{
LLFrameTimer::updateFrameTime();
if (mClientPump)
{
mClientPump->pump();
mClientPump->callback();
}
}
}
const std::string PORT;
const std::string local_server;
private:
apr_pool_t* mPool;
LLPumpIO* mClientPump;
protected:
void ensureStatusOK()
{
if (mSawError)
{
std::string msg =
llformat("httpFailure() called when not expected, status %d",
mStatus);
fail(msg);
}
}
void ensureStatusError()
{
if (!mSawError)
{
fail("httpFailure() wasn't called");
}
}
LLSD getResult()
{
return mResult;
}
LLSD getHeader()
{
return mHeader;
}
protected:
bool mSawError;
U32 mStatus;
std::string mReason;
bool mSawCompleted;
bool mSawCompletedHeader;
LLSD mResult;
LLSD mHeader;
bool mResultDeleted;
class Result : public LLHTTPClient::Responder
{
protected:
Result(HTTPClientTestData& client)
: mClient(client)
{
}
public:
static Result* build(HTTPClientTestData& client)
{
return new Result(client);
}
~Result()
{
mClient.mResultDeleted = true;
}
protected:
virtual void httpFailure()
{
mClient.mSawError = true;
mClient.mStatus = getStatus();
mClient.mReason = getReason();
}
virtual void httpSuccess()
{
mClient.mResult = getContent();
}
virtual void httpCompleted()
{
LLHTTPClient::Responder::httpCompleted();
mClient.mSawCompleted = true;
mClient.mSawCompletedHeader = true;
mClient.mHeader = getResponseHeaders();
}
private:
HTTPClientTestData& mClient;
};
friend class Result;
protected:
LLHTTPClient::ResponderPtr newResult()
{
mSawError = false;
mStatus = 0;
mSawCompleted = false;
mSawCompletedHeader = false;
mResult.clear();
mHeader.clear();
mResultDeleted = false;
return Result::build(*this);
}
};
typedef test_group<HTTPClientTestData> HTTPClientTestGroup;
typedef HTTPClientTestGroup::object HTTPClientTestObject;
HTTPClientTestGroup httpClientTestGroup("http_client");
template<> template<>
void HTTPClientTestObject::test<1>()
{
LLHTTPClient::get(local_server, newResult());
runThePump();
ensureStatusOK();
ensure("result object wasn't destroyed", mResultDeleted);
}
template<> template<>
void HTTPClientTestObject::test<2>()
{
// Please nobody listen on this particular port...
LLHTTPClient::get("http://127.0.0.1:7950", newResult());
runThePump();
ensureStatusError();
}
template<> template<>
void HTTPClientTestObject::test<3>()
{
LLSD sd;
sd["list"][0]["one"] = 1;
sd["list"][0]["two"] = 2;
sd["list"][1]["three"] = 3;
sd["list"][1]["four"] = 4;
LLHTTPClient::post(local_server + "web/echo", sd, newResult());
runThePump();
ensureStatusOK();
ensure_equals("echoed result matches", getResult(), sd);
}
template<> template<>
void HTTPClientTestObject::test<4>()
{
LLSD sd;
sd["message"] = "This is my test message.";
LLHTTPClient::put(local_server + "test/storage", sd, newResult());
runThePump();
ensureStatusOK();
LLHTTPClient::get(local_server + "test/storage", newResult());
runThePump();
ensureStatusOK();
ensure_equals("echoed result matches", getResult(), sd);
}
template<> template<>
void HTTPClientTestObject::test<5>()
{
LLSD sd;
sd["status"] = 543;
sd["reason"] = "error for testing";
LLHTTPClient::post(local_server + "test/error", sd, newResult());
runThePump();
ensureStatusError();
ensure_contains("reason", mReason, sd["reason"]);
}
template<> template<>
void HTTPClientTestObject::test<6>()
{
const F32 timeout = 1.0f;
LLHTTPClient::get(local_server + "test/timeout", newResult(), LLSD(), timeout);
runThePump(timeout * 5.0f);
ensureStatusError();
ensure_equals("reason", mReason, "STATUS_EXPIRED");
}
template<> template<>
void HTTPClientTestObject::test<7>()
{
LLHTTPClient::get(local_server, newResult());
runThePump();
ensureStatusOK();
LLSD expected = getResult();
LLSD result;
result = LLHTTPClient::blockingGet(local_server);
LLSD body = result["body"];
ensure_equals("echoed result matches", body.size(), expected.size());
}
template<> template<>
void HTTPClientTestObject::test<8>()
{
// This is testing for the presence of the Header in the returned results
// from an HTTP::get call.
LLHTTPClient::get(local_server, newResult());
runThePump();
ensureStatusOK();
LLSD header = getHeader();
ensure("got a header", ! header.emptyMap().asBoolean());
}
template<> template<>
void HTTPClientTestObject::test<9>()
{
LLHTTPClient::head(local_server, newResult());
runThePump();
ensureStatusOK();
ensure("result object wasn't destroyed", mResultDeleted);
}
}
+107
View File
@@ -0,0 +1,107 @@
/**
* @file llhttpnode_stub.cpp
* @brief STUB Implementation of classes for generic HTTP/LSL/REST handling.
*
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
*
* Second Life Viewer Source Code
* Copyright (c) 2006-2009, 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 "linden_common.h"
#include "llhttpnode.h"
const std::string CONTEXT_VERB("verb");
const std::string CONTEXT_REQUEST("request");
const std::string CONTEXT_WILDCARD("wildcard");
const std::string CONTEXT_PATH("path");
const std::string CONTEXT_QUERY_STRING("query-string");
const std::string CONTEXT_REMOTE_HOST("remote-host");
const std::string CONTEXT_REMOTE_PORT("remote-port");
const std::string CONTEXT_HEADERS("headers");
const std::string CONTEXT_RESPONSE("response");
/**
* LLHTTPNode
*/
class LLHTTPNode::Impl
{
// dummy
};
LLHTTPNode::LLHTTPNode(): impl(*new Impl) {}
LLHTTPNode::~LLHTTPNode() {}
LLSD LLHTTPNode::simpleGet() const { return LLSD(); }
LLSD LLHTTPNode::simplePut(const LLSD& input) const { return LLSD(); }
LLSD LLHTTPNode::simplePost(const LLSD& input) const { return LLSD(); }
LLSD LLHTTPNode::simpleDel(const LLSD&) const { return LLSD(); }
void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) const {}
void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const {}
void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const {}
void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) const {}
void LLHTTPNode::options(ResponsePtr response, const LLSD& context) const {}
LLHTTPNode* LLHTTPNode::getChild(const std::string& name, LLSD& context) const { return NULL; }
bool LLHTTPNode::handles(const LLSD& remainder, LLSD& context) const { return false; }
bool LLHTTPNode::validate(const std::string& name, LLSD& context) const { return false; }
const LLHTTPNode* LLHTTPNode::traverse(const std::string& path, LLSD& context) const { return NULL; }
void LLHTTPNode::addNode(const std::string& path, LLHTTPNode* nodeToAdd) { }
LLSD LLHTTPNode::allNodePaths() const { return LLSD(); }
const LLHTTPNode* LLHTTPNode::rootNode() const { return NULL; }
const LLHTTPNode* LLHTTPNode::findNode(const std::string& name) const { return NULL; }
LLHTTPNode::Response::~Response(){}
void LLHTTPNode::Response::notFound(const std::string& message)
{
status(404, message);
}
void LLHTTPNode::Response::notFound()
{
status(404, "Not Found");
}
void LLHTTPNode::Response::methodNotAllowed()
{
status(405, "Method Not Allowed");
}
void LLHTTPNode::Response::statusUnknownError(S32 code)
{
status(code, "Unknown Error");
}
void LLHTTPNode::Response::status(S32 code, const std::string& message)
{
}
void LLHTTPNode::Response::addHeader(const std::string& name,const std::string& value)
{
mHeaders[name] = value;
}
void LLHTTPNode::describe(Description& desc) const { }
const LLChainIOFactory* LLHTTPNode::getProtocolHandler() const { return NULL; }
LLHTTPRegistrar::NodeFactory::~NodeFactory() { }
void LLHTTPRegistrar::registerFactory(
const std::string& path, NodeFactory& factory) {}
void LLHTTPRegistrar::buildAllServices(LLHTTPNode& root) {}
+406
View File
@@ -0,0 +1,406 @@
/**
* @file llnamevalue_test.cpp
* @author Adroit
* @date 2007-02
* @brief LLNameValue unit test
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "llsdserialize.h"
#include "../llnamevalue.h"
#include "../test/lltut.h"
#if LL_WINDOWS
// disable unreachable code warnings
#pragma warning(disable: 4702)
#endif
namespace tut
{
struct namevalue_test
{
namevalue_test()
{
}
};
typedef test_group<namevalue_test> namevalue_t;
typedef namevalue_t::object namevalue_object_t;
tut::namevalue_t tut_namevalue("LLNameValue");
template<> template<>
void namevalue_object_t::test<1>()
{
// LLNameValue()
LLNameValue nValue;
ensure("mName should have been NULL", nValue.mName == NULL);
ensure("getTypeEnum failed",nValue.getTypeEnum() == NVT_NULL);
ensure("getClassEnum failed",nValue.getClassEnum() == NVC_NULL);
ensure("getSendtoEnum failed",nValue.getSendtoEnum() == NVS_NULL);
LLNameValue nValue1(" SecondLife ASSET RW SIM 232324343");
}
// LLNameValue(const char* data);
// LLNameValue(const char* name, const char* data, const char* type, const char* nvclass, const char* nvsendto,
// TNameValueCallback nvcb = NULL, void** user_data = NULL);
template<> template<>
void namevalue_object_t::test<2>()
{
LLNameValue nValue(" SecondLife ASSET RW S 232324343");
ensure("mName not set correctly", (0 == strcmp(nValue.mName,"SecondLife")));
ensure("getTypeEnum failed", nValue.getTypeEnum() == NVT_ASSET);
ensure("getClassEnum failed", nValue.getClassEnum() == NVC_READ_WRITE);
ensure("getSendtoEnum failed", nValue.getSendtoEnum() == NVS_SIM);
ensure("getString failed", (0==strcmp(nValue.getAsset(),"232324343")));
ensure("sendToData or sendToViewer failed", !nValue.sendToData() && !nValue.sendToViewer());
LLNameValue nValue1("\n\r SecondLife_1 STRING READ_WRITE SIM 232324343");
ensure("1. mName not set correctly", (0 == strcmp(nValue1.mName,"SecondLife_1")));
ensure("1. getTypeEnum failed", nValue1.getTypeEnum() == NVT_STRING);
ensure("1. getClassEnum failed", nValue1.getClassEnum() == NVC_READ_WRITE);
ensure("1. getSendtoEnum failed", nValue1.getSendtoEnum() == NVS_SIM);
ensure("1. getString failed", (0==strcmp(nValue1.getString(),"232324343")));
ensure("1. sendToData or sendToViewer failed", !nValue1.sendToData() && !nValue1.sendToViewer());
LLNameValue nValue2("SecondLife", "23.5", "F32", "R", "DS");
ensure("2. getTypeEnum failed", nValue2.getTypeEnum() == NVT_F32);
ensure("2. getClassEnum failed", nValue2.getClassEnum() == NVC_READ_ONLY);
ensure("2. getSendtoEnum failed", nValue2.getSendtoEnum() == NVS_DATA_SIM);
ensure("2. getF32 failed", *nValue2.getF32() == 23.5f);
ensure("2. sendToData or sendToViewer failed", nValue2.sendToData() && !nValue2.sendToViewer());
LLNameValue nValue3("SecondLife", "-43456787", "S32", "READ_ONLY", "SIM_SPACE");
ensure("3. getTypeEnum failed", nValue3.getTypeEnum() == NVT_S32);
ensure("3. getClassEnum failed", nValue3.getClassEnum() == NVC_READ_ONLY);
ensure("3. getSendtoEnum failed", nValue3.getSendtoEnum() == NVS_DATA_SIM);
ensure("3. getS32 failed", *nValue3.getS32() == -43456787);
ensure("sendToData or sendToViewer failed", nValue3.sendToData() && !nValue3.sendToViewer());
LLNameValue nValue4("SecondLife", "<1.0, 2.0, 3.0>", "VEC3", "RW", "SV");
LLVector3 llvec4(1.0, 2.0, 3.0);
ensure("4. getTypeEnum failed", nValue4.getTypeEnum() == NVT_VEC3);
ensure("4. getClassEnum failed", nValue4.getClassEnum() == NVC_READ_WRITE);
ensure("4. getSendtoEnum failed", nValue4.getSendtoEnum() == NVS_SIM_VIEWER);
ensure("4. getVec3 failed", *nValue4.getVec3() == llvec4);
ensure("4. sendToData or sendToViewer failed", !nValue4.sendToData() && nValue4.sendToViewer());
LLNameValue nValue5("SecondLife", "-1.0, 2.4, 3", "VEC3", "RW", "SIM_VIEWER");
LLVector3 llvec5(-1.0f, 2.4f, 3);
ensure("5. getTypeEnum failed", nValue5.getTypeEnum() == NVT_VEC3);
ensure("5. getClassEnum failed", nValue5.getClassEnum() == NVC_READ_WRITE);
ensure("5. getSendtoEnum failed", nValue5.getSendtoEnum() == NVS_SIM_VIEWER);
ensure("5. getVec3 failed", *nValue5.getVec3() == llvec5);
ensure("5. sendToData or sendToViewer failed", !nValue5.sendToData() && nValue5.sendToViewer());
LLNameValue nValue6("SecondLife", "89764323", "U32", "RW", "DSV");
ensure("6. getTypeEnum failed", nValue6.getTypeEnum() == NVT_U32);
ensure("6. getClassEnum failed", nValue6.getClassEnum() == NVC_READ_WRITE);
ensure("6. getSendtoEnum failed", nValue6.getSendtoEnum() == NVS_DATA_SIM_VIEWER);
ensure("6. getU32 failed", *nValue6.getU32() == 89764323);
ensure("6. sendToData or sendToViewer failed", nValue6.sendToData() && nValue6.sendToViewer());
LLNameValue nValue7("SecondLife", "89764323323232", "U64", "RW", "SIM_SPACE_VIEWER");
U64 u64_7 = U64L(89764323323232);
ensure("7. getTypeEnum failed", nValue7.getTypeEnum() == NVT_U64);
ensure("7. getClassEnum failed", nValue7.getClassEnum() == NVC_READ_WRITE);
ensure("7. getSendtoEnum failed", nValue7.getSendtoEnum() == NVS_DATA_SIM_VIEWER);
ensure("7. getU32 failed", *nValue7.getU64() == u64_7);
ensure("7. sendToData or sendToViewer failed", nValue7.sendToData() && nValue7.sendToViewer());
}
// LLNameValue(const char* name, const char* data, const char* type, const char* nvclass,
// TNameValueCallback nvcb = NULL, void** user_data = NULL);
template<> template<>
void namevalue_object_t::test<3>()
{
LLNameValue nValue("SecondLife", "232324343", "ASSET", "READ_WRITE");
ensure("mName not set correctly", (0 == strcmp(nValue.mName,"SecondLife")));
ensure("getTypeEnum failed", nValue.getTypeEnum() == NVT_ASSET);
ensure("getClassEnum failed", nValue.getClassEnum() == NVC_READ_WRITE);
ensure("getSendtoEnum failed", nValue.getSendtoEnum() == NVS_SIM);
ensure("getString failed", (0==strcmp(nValue.getAsset(),"232324343")));
LLNameValue nValue1("SecondLife", "232324343", "STRING", "READ_WRITE");
ensure("1. mName not set correctly", (0 == strcmp(nValue1.mName,"SecondLife")));
ensure("1. getTypeEnum failed", nValue1.getTypeEnum() == NVT_STRING);
ensure("1. getClassEnum failed", nValue1.getClassEnum() == NVC_READ_WRITE);
ensure("1. getSendtoEnum failed", nValue1.getSendtoEnum() == NVS_SIM);
ensure("1. getString failed", (0==strcmp(nValue1.getString(),"232324343")));
LLNameValue nValue2("SecondLife", "23.5", "F32", "R");
ensure("2. getTypeEnum failed", nValue2.getTypeEnum() == NVT_F32);
ensure("2. getClassEnum failed", nValue2.getClassEnum() == NVC_READ_ONLY);
ensure("2. getSendtoEnum failed", nValue2.getSendtoEnum() == NVS_SIM);
ensure("2. getF32 failed", *nValue2.getF32() == 23.5f);
LLNameValue nValue3("SecondLife", "-43456787", "S32", "READ_ONLY");
ensure("3. getTypeEnum failed", nValue3.getTypeEnum() == NVT_S32);
ensure("3. getClassEnum failed", nValue3.getClassEnum() == NVC_READ_ONLY);
ensure("3. getSendtoEnum failed", nValue3.getSendtoEnum() == NVS_SIM);
ensure("3. getS32 failed", *nValue3.getS32() == -43456787);
LLNameValue nValue4("SecondLife", "<1.0, 2.0, 3.0>", "VEC3", "RW");
LLVector3 llvec4(1.0, 2.0, 3.0);
ensure("4. getTypeEnum failed", nValue4.getTypeEnum() == NVT_VEC3);
ensure("4. getClassEnum failed", nValue4.getClassEnum() == NVC_READ_WRITE);
ensure("4. getSendtoEnum failed", nValue4.getSendtoEnum() == NVS_SIM);
ensure("4. getVec3 failed", *nValue4.getVec3() == llvec4);
LLNameValue nValue5("SecondLife", "-1.0, 2.4, 3", "VEC3", "RW");
LLVector3 llvec5(-1.0f, 2.4f, 3);
ensure("5. getTypeEnum failed", nValue5.getTypeEnum() == NVT_VEC3);
ensure("5. getClassEnum failed", nValue5.getClassEnum() == NVC_READ_WRITE);
ensure("5. getSendtoEnum failed", nValue5.getSendtoEnum() == NVS_SIM);
ensure("5. getVec3 failed", *nValue5.getVec3() == llvec5);
LLNameValue nValue6("SecondLife", "89764323", "U32", "RW");
ensure("6. getTypeEnum failed", nValue6.getTypeEnum() == NVT_U32);
ensure("6. getClassEnum failed", nValue6.getClassEnum() == NVC_READ_WRITE);
ensure("6. getSendtoEnum failed", nValue6.getSendtoEnum() == NVS_SIM);
ensure("6. getU32 failed", *nValue6.getU32() == 89764323);
LLNameValue nValue7("SecondLife", "89764323323232", "U64", "RW");
U64 u64_7 = U64L(89764323323232);
ensure("7. getTypeEnum failed", nValue7.getTypeEnum() == NVT_U64);
ensure("7. getClassEnum failed", nValue7.getClassEnum() == NVC_READ_WRITE);
ensure("7. getSendtoEnum failed", nValue7.getSendtoEnum() == NVS_SIM);
ensure("7. getU32 failed", *nValue7.getU64() == u64_7);
}
// LLNameValue(const char* name, const char* type, const char* nvclass,
// TNameValueCallback nvcb = NULL, void** user_data = NULL);
template<> template<>
void namevalue_object_t::test<4>()
{
LLNameValue nValue("SecondLife", "STRING", "READ_WRITE");
ensure("mName not set correctly", (0 == strcmp(nValue.mName,"SecondLife")));
ensure("getTypeEnum failed", nValue.getTypeEnum() == NVT_STRING);
ensure("getClassEnum failed", nValue.getClassEnum() == NVC_READ_WRITE);
ensure("getSendtoEnum failed", nValue.getSendtoEnum() == NVS_SIM);
LLNameValue nValue1("SecondLife", "ASSET", "READ_WRITE");
ensure("1. mName not set correctly", (0 == strcmp(nValue1.mName,"SecondLife")));
ensure("1. getTypeEnum for RW failed", nValue1.getTypeEnum() == NVT_ASSET);
ensure("1. getClassEnum for RW failed", nValue1.getClassEnum() == NVC_READ_WRITE);
ensure("1. getSendtoEnum for RW failed", nValue1.getSendtoEnum() == NVS_SIM);
LLNameValue nValue2("SecondLife", "F32", "READ_ONLY");
ensure("2. getTypeEnum failed", nValue2.getTypeEnum() == NVT_F32);
ensure("2. getClassEnum failed", nValue2.getClassEnum() == NVC_READ_ONLY);
ensure("2. getSendtoEnum failed", nValue2.getSendtoEnum() == NVS_SIM);
LLNameValue nValue3("SecondLife", "S32", "READ_ONLY");
ensure("3. getTypeEnum failed", nValue3.getTypeEnum() == NVT_S32);
ensure("3. getClassEnum failed", nValue3.getClassEnum() == NVC_READ_ONLY);
ensure("3. getSendtoEnum failed", nValue3.getSendtoEnum() == NVS_SIM);
LLNameValue nValue4("SecondLife", "VEC3", "READ_WRITE");
ensure("4. getTypeEnum failed", nValue4.getTypeEnum() == NVT_VEC3);
ensure("4. getClassEnum failed", nValue4.getClassEnum() == NVC_READ_WRITE);
ensure("4. getSendtoEnum failed", nValue4.getSendtoEnum() == NVS_SIM);
LLNameValue nValue6("SecondLife", "U32", "READ_WRITE");
ensure("6. getTypeEnum failed", nValue6.getTypeEnum() == NVT_U32);
ensure("6. getClassEnum failed", nValue6.getClassEnum() == NVC_READ_WRITE);
ensure("6. getSendtoEnum failed", nValue6.getSendtoEnum() == NVS_SIM);
LLNameValue nValue7("SecondLife", "U64", "READ_WRITE");
ensure("7. getTypeEnum failed", nValue7.getTypeEnum() == NVT_U64);
ensure("7. getClassEnum failed", nValue7.getClassEnum() == NVC_READ_WRITE);
ensure("7. getSendtoEnum failed", nValue7.getSendtoEnum() == NVS_SIM);
}
template<> template<>
void namevalue_object_t::test<5>()
{
LLNameValue nValue("SecondLife", "This is a test", "STRING", "RW", "SIM");
ensure("getString failed", (0 == strcmp(nValue.getString(),"This is a test")));
}
template<> template<>
void namevalue_object_t::test<6>()
{
LLNameValue nValue("SecondLife", "This is a test", "ASSET", "RW", "S");
ensure("getAsset failed", (0 == strcmp(nValue.getAsset(),"This is a test")));
}
template<> template<>
void namevalue_object_t::test<7>()
{
LLNameValue nValue("SecondLife", "555555", "F32", "RW", "SIM");
ensure("getF32 failed",*nValue.getF32() == 555555.f);
}
template<> template<>
void namevalue_object_t::test<8>()
{
LLNameValue nValue("SecondLife", "-5555", "S32", "RW", "SIM");
ensure("getS32 failed", *nValue.getS32() == -5555);
S32 sVal = 0x7FFFFFFF;
nValue.setS32(sVal);
ensure("getS32 failed", *nValue.getS32() == sVal);
sVal = -0x7FFFFFFF;
nValue.setS32(sVal);
ensure("getS32 failed", *nValue.getS32() == sVal);
sVal = 0;
nValue.setS32(sVal);
ensure("getS32 failed", *nValue.getS32() == sVal);
}
template<> template<>
void namevalue_object_t::test<9>()
{
LLNameValue nValue("SecondLife", "<-3, 2, 1>", "VEC3", "RW", "SIM");
LLVector3 vecExpected(-3, 2, 1);
LLVector3 vec;
nValue.getVec3(vec);
ensure("getVec3 failed", vec == vecExpected);
}
template<> template<>
void namevalue_object_t::test<10>()
{
LLNameValue nValue("SecondLife", "12345678", "U32", "RW", "SIM");
ensure("getU32 failed",*nValue.getU32() == 12345678);
U32 val = 0xFFFFFFFF;
nValue.setU32(val);
ensure("U32 max", *nValue.getU32() == val);
val = 0;
nValue.setU32(val);
ensure("U32 min", *nValue.getU32() == val);
}
template<> template<>
void namevalue_object_t::test<11>()
{
//skip_fail("incomplete support for U64.");
LLNameValue nValue("SecondLife", "44444444444", "U64", "RW", "SIM");
ensure("getU64 failed",*nValue.getU64() == U64L(44444444444));
// there is no LLNameValue::setU64()
}
template<> template<>
void namevalue_object_t::test<12>()
{
//skip_fail("incomplete support for U64.");
LLNameValue nValue("SecondLife U64 RW DSV 44444444444");
std::string ret_str = nValue.printNameValue();
ensure_equals("1:printNameValue failed",ret_str,"SecondLife U64 RW DSV 44444444444");
LLNameValue nValue1(ret_str.c_str());
ensure_equals("Serialization of printNameValue failed", *nValue.getU64(), *nValue1.getU64());
}
template<> template<>
void namevalue_object_t::test<13>()
{
LLNameValue nValue("SecondLife STRING RW DSV 44444444444");
std::string ret_str = nValue.printData();
ensure_equals("1:printData failed",ret_str,"44444444444");
LLNameValue nValue1("SecondLife S32 RW DSV 44444");
ret_str = nValue1.printData();
ensure_equals("2:printData failed",ret_str,"44444");
}
template<> template<>
void namevalue_object_t::test<14>()
{
LLNameValue nValue("SecodLife STRING RW SIM 22222");
std::ostringstream stream1,stream2,stream3, stream4, stream5;
stream1 << nValue;
ensure_equals("STRING << failed",stream1.str(),"22222");
LLNameValue nValue1("SecodLife F32 RW SIM 22222");
stream2 << nValue1;
ensure_equals("F32 << failed",stream2.str(),"22222");
LLNameValue nValue2("SecodLife S32 RW SIM 22222");
stream3<< nValue2;
ensure_equals("S32 << failed",stream3.str(),"22222");
LLNameValue nValue3("SecodLife U32 RW SIM 122222");
stream4<< nValue3;
ensure_equals("U32 << failed",stream4.str(),"122222");
// I don't think we use U64 name value pairs. JC
//skip_fail("incomplete support for U64.");
//LLNameValue nValue4("SecodLife U64 RW SIM 22222");
//stream5<< nValue4;
//ensure("U64 << failed",0 == strcmp((stream5.str()).c_str(),"22222"));
}
template<> template<>
void namevalue_object_t::test<15>()
{
LLNameValue nValue("SecondLife", "This is a test", "ASSET", "R", "S");
ensure("getAsset failed", (0 == strcmp(nValue.getAsset(),"This is a test")));
// this should not have updated as it is read only.
nValue.setAsset("New Value should not be updated");
ensure("setAsset on ReadOnly failed", (0 == strcmp(nValue.getAsset(),"This is a test")));
LLNameValue nValue1("SecondLife", "1234", "U32", "R", "S");
// this should not have updated as it is read only.
nValue1.setU32(4567);
ensure("setU32 on ReadOnly failed", *nValue1.getU32() == 1234);
LLNameValue nValue2("SecondLife", "1234", "S32", "R", "S");
// this should not have updated as it is read only.
nValue2.setS32(4567);
ensure("setS32 on ReadOnly failed", *nValue2.getS32() == 1234);
LLNameValue nValue3("SecondLife", "1234", "F32", "R", "S");
// this should not have updated as it is read only.
nValue3.setF32(4567);
ensure("setF32 on ReadOnly failed", *nValue3.getF32() == 1234);
LLNameValue nValue4("SecondLife", "<1,2,3>", "VEC3", "R", "S");
// this should not have updated as it is read only.
LLVector3 vec(4,5,6);
nValue3.setVec3(vec);
LLVector3 vec1(1,2,3);
ensure("setVec3 on ReadOnly failed", *nValue4.getVec3() == vec1);
// cant test for U64 as no set64 exists nor any operators support U64 type
}
}
+154
View File
@@ -0,0 +1,154 @@
/**
* @file llpartdata_tut.cpp
* @author Adroit
* @date March 2007
* @brief LLPartData and LLPartSysData test cases.
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "lldatapacker.h"
#include "v3math.h"
#include "llsdserialize.h"
#include "message.h"
#include "../llpartdata.h"
#include "../test/lltut.h"
namespace tut
{
//bunch of sniffed data that *should* be a valid particle system
static U8 msg[] = {
0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x80, 0x00, 0x80,
0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x5e, 0x12, 0x0b, 0xa1, 0x58, 0x05, 0xdc, 0x57, 0x66,
0xb7, 0xf5, 0xac, 0x4b, 0xd1, 0x8f, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x05, 0x02, 0x00, 0x00, 0x0a, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7e, 0xc6, 0x81, 0xdc, 0x7e, 0xc6, 0x81, 0xdc, 0x77, 0xcf, 0xef, 0xd4, 0xce, 0x64, 0x1a, 0x7e,
0x26, 0x87, 0x55, 0x7f, 0xdd, 0x65, 0x22, 0x7f, 0xdd, 0x65, 0x22, 0x7f, 0x77, 0xcf, 0x98, 0xa3, 0xab,
0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xf2,
0xf1, 0x65, 0x32, 0x1b, 0xef, 0x18, 0x70, 0x66, 0xba, 0x30, 0xa0, 0x11, 0xaa, 0x2f, 0xb0, 0xab, 0xd0,
0x30, 0x7d, 0xbd, 0x01, 0x00, 0xf8, 0x0d, 0xb8, 0x30, 0x01, 0x00, 0x00, 0x00, 0xce, 0xc6, 0x81, 0xdc,
0xce, 0xc6, 0x81, 0xdc, 0xc7, 0xcf, 0xef, 0xd4, 0x75, 0x65, 0x1a, 0x7f, 0x62, 0x6f, 0x55, 0x7f, 0x6d,
0x65, 0x22, 0x7f, 0x6d, 0x65, 0x22, 0x7f, 0xc7, 0xcf, 0x98, 0xa3, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xf2, 0xf1, 0x62, 0x12, 0x1b, 0xef,
0x18, 0x7e, 0xbd, 0x01, 0x00, 0x16, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7c, 0xac, 0x28, 0x03, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48,
0xe0, 0xb9, 0x30, 0x03, 0xe1, 0xb9, 0x30, 0xbb, 0x00, 0x00, 0x00, 0x48, 0xe0, 0xb9, 0x30, 0x36, 0xd9,
0x81, 0xdc, 0x36, 0xd9, 0x81, 0xdc, 0x3f, 0xd0, 0xef, 0xd4, 0xa5, 0x7a, 0x72, 0x7f, 0x26, 0x30, 0x55,
0x7f, 0x95, 0x7a, 0x22, 0x7f, 0x95, 0x7a, 0x22, 0x7f, 0x3f, 0xd0, 0x98, 0xa3, 0xab, 0xab, 0xab, 0xab,
0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00 };
struct partdata_test
{
};
typedef test_group<partdata_test> partdata_test_t;
typedef partdata_test_t::object partdata_test_object_t;
tut::partdata_test_t tut_partdata_test("LLPartData");
template<> template<>
void partdata_test_object_t::test<1>()
{
LLPartSysData llpsysdata;
LLDataPackerBinaryBuffer dp1(msg, sizeof(msg));
ensure("LLPartSysData::unpack failed.", llpsysdata.unpack(dp1));
//mCRC 1 unsigned int
ensure("mCRC different after unpacking", llpsysdata.mCRC == (U32) 1);
//mFlags 0 unsigned int
ensure ("mFlags different after unpacking", llpsysdata.mFlags == (U32) 0);
//mPattern 1 '' unsigned char
ensure ("mPattern different after unpacking", llpsysdata.mPattern == (U8) 1);
//mInnerAngle 0.00000000 float
ensure_approximately_equals("mInnerAngle different after unpacking", llpsysdata.mInnerAngle, 0.f, 8);
//mOuterAngle 0.00000000 float
ensure_approximately_equals("mOuterAngle different after unpacking", llpsysdata.mOuterAngle, 0.f, 8);
//mAngularVelocity 0,0,0
ensure_approximately_equals("mAngularVelocity.mV[0] different after unpacking", llpsysdata.mAngularVelocity.mV[0], 0.f, 8);
ensure_approximately_equals("mAngularVelocity.mV[0] different after unpacking", llpsysdata.mAngularVelocity.mV[1], 0.f, 8);
ensure_approximately_equals("mAngularVelocity.mV[0] different after unpacking", llpsysdata.mAngularVelocity.mV[2], 0.f, 8);
//mBurstRate 0.097656250 float
ensure_approximately_equals("mBurstRate different after unpacking", llpsysdata.mBurstRate, 0.097656250f, 8);
//mBurstPartCount 1 '' unsigned char
ensure("mBurstPartCount different after unpacking", llpsysdata.mBurstPartCount == (U8) 1);
//mBurstRadius 0.00000000 float
ensure_approximately_equals("mBurstRadius different after unpacking", llpsysdata.mBurstRadius, 0.f, 8);
//mBurstSpeedMin 1.0000000 float
ensure_approximately_equals("mBurstSpeedMin different after unpacking", llpsysdata.mBurstSpeedMin, 1.f, 8);
//mBurstSpeedMax 1.0000000 float
ensure_approximately_equals("mBurstSpeedMax different after unpacking", llpsysdata.mBurstSpeedMax, 1.f, 8);
//mMaxAge 0.00000000 float
ensure_approximately_equals("mMaxAge different after unpacking", llpsysdata.mMaxAge, 0.f, 8);
//mStartAge 0.00000000 float
ensure_approximately_equals("mStartAge different after unpacking", llpsysdata.mStartAge, 0.f, 8);
//mPartAccel <0,0,0>
ensure_approximately_equals("mPartAccel.mV[0] different after unpacking", llpsysdata.mPartAccel.mV[0], 0.f, 7);
ensure_approximately_equals("mPartAccel.mV[1] different after unpacking", llpsysdata.mPartAccel.mV[1], 0.f, 7);
ensure_approximately_equals("mPartAccel.mV[2] different after unpacking", llpsysdata.mPartAccel.mV[2], 0.f, 7);
//mPartData
LLPartData& data = llpsysdata.mPartData;
//mFlags 132354 unsigned int
ensure ("mPartData.mFlags different after unpacking", data.mFlags == (U32) 132354);
//mMaxAge 10.000000 float
ensure_approximately_equals("mPartData.mMaxAge different after unpacking", data.mMaxAge, 10.f, 8);
//mStartColor <1,1,1,1>
ensure_approximately_equals("mPartData.mStartColor.mV[0] different after unpacking", data.mStartColor.mV[0], 1.f, 8);
ensure_approximately_equals("mPartData.mStartColor.mV[1] different after unpacking", data.mStartColor.mV[1], 1.f, 8);
ensure_approximately_equals("mPartData.mStartColor.mV[2] different after unpacking", data.mStartColor.mV[2], 1.f, 8);
ensure_approximately_equals("mPartData.mStartColor.mV[3] different after unpacking", data.mStartColor.mV[3], 1.f, 8);
//mEndColor <1,1,0,0>
ensure_approximately_equals("mPartData.mEndColor.mV[0] different after unpacking", data.mEndColor.mV[0], 1.f, 8);
ensure_approximately_equals("mPartData.mEndColor.mV[1] different after unpacking", data.mEndColor.mV[1], 1.f, 8);
ensure_approximately_equals("mPartData.mEndColor.mV[2] different after unpacking", data.mEndColor.mV[2], 0.f, 8);
ensure_approximately_equals("mPartData.mEndColor.mV[3] different after unpacking", data.mEndColor.mV[3], 0.f, 8);
//mStartScale <1,1>
ensure_approximately_equals("mPartData.mStartScale.mV[0] different after unpacking", data.mStartScale.mV[0], 1.f, 8);
ensure_approximately_equals("mPartData.mStartScale.mV[1] different after unpacking", data.mStartScale.mV[1], 1.f, 8);
//mEndScale <0,0>
ensure_approximately_equals("mPartData.mEndScale.mV[0] different after unpacking", data.mEndScale.mV[0], 0.f, 8);
ensure_approximately_equals("mPartData.mEndScale.mV[1] different after unpacking", data.mEndScale.mV[1], 0.f, 8);
//mPosOffset <0,0,0>
ensure_approximately_equals("mPartData.mPosOffset.mV[0] different after unpacking", data.mPosOffset.mV[0], 0.f, 8);
ensure_approximately_equals("mPartData.mPosOffset.mV[1] different after unpacking", data.mPosOffset.mV[1], 0.f, 8);
ensure_approximately_equals("mPartData.mPosOffset.mV[2] different after unpacking", data.mPosOffset.mV[2], 0.f, 8);
//mParameter 0.00000000 float
ensure_approximately_equals("mPartData.mParameter different after unpacking", data.mParameter, 0.f, 8);
//mStartGlow 0.00000000 float
ensure_approximately_equals("mPartData.mStartGlow different after unpacking", data.mStartGlow, 0.f, 8);
//mEndGlow 0.00000000 float
ensure_approximately_equals("mPartData.mEndGlow different after unpacking", data.mEndGlow, 0.f, 8);
//mBlendFuncSource 2 '' unsigned char
ensure("mPartData.mBlendFuncSource different after unpacking", data.mBlendFuncSource == (U8) 2);
//mBlendFuncDest 1 '' unsigned char
ensure("mPartData.mBlendFuncDest different after unpacking", data.mBlendFuncDest == (U8) 1);
}
}
@@ -0,0 +1,160 @@
/**
* @file lltrustedmessageservice_test.cpp
* @brief LLTrustedMessageService unit tests
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "lltemplatemessagedispatcher.h"
#include "lltut.h"
#include "llhttpnode.h"
#include "llhost.h"
#include "message.h"
#include "llsd.h"
#include "llpounceable.h"
#include "llhost.cpp" // Needed for copy operator
#include "net.cpp" // Needed by LLHost.
LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
// sensor test doubles
bool gClearRecvWasCalled = false;
void LLMessageSystem::clearReceiveState(void)
{
gClearRecvWasCalled = true;
}
char gUdpDispatchedData[MAX_BUFFER_SIZE];
bool gUdpDispatchWasCalled = false;
bool LLTemplateMessageReader::readMessage(const U8* data,class LLHost const &)
{
gUdpDispatchWasCalled = true;
strcpy(gUdpDispatchedData, reinterpret_cast<const char*>(data));
return true;
}
bool gValidateMessage = false;
bool LLTemplateMessageReader::validateMessage(const U8*, S32 buffer_size, LLHost const &sender, bool trusted)
{
return gValidateMessage;
}
LLHost host;
const LLHost& LLMessageSystem::getSender() const
{
return host;
}
const char* gBinaryTemplateData = "BINARYTEMPLATEDATA";
void fillVector(std::vector<U8>& vector_data, const char* data)
{
vector_data.resize(strlen(data) + 1);
strcpy(reinterpret_cast<char*>(&vector_data[0]), data);
}
namespace tut
{
static LLTemplateMessageReader::message_template_number_map_t numberMap;
struct LLTemplateMessageDispatcherData
{
LLTemplateMessageDispatcherData()
{
mMessageName = "MessageName";
gUdpDispatchWasCalled = false;
gClearRecvWasCalled = false;
gValidateMessage = false;
mMessage["body"]["binary-template-data"] = std::vector<U8>();
}
LLSD mMessage;
LLHTTPNode::ResponsePtr mResponsePtr;
std::string mMessageName;
};
typedef test_group<LLTemplateMessageDispatcherData> factory;
typedef factory::object object;
}
namespace
{
tut::factory tf("LLTemplateMessageDispatcher");
}
namespace tut
{
// does an empty message stop processing?
template<> template<>
void object::test<1>()
{
LLTemplateMessageReader* pReader = NULL;
LLTemplateMessageDispatcher t(*pReader);
t.dispatch(mMessageName, mMessage, mResponsePtr);
ensure(! gUdpDispatchWasCalled);
ensure(! gClearRecvWasCalled);
}
// does the disaptch invoke the udp send method?
template<> template<>
void object::test<2>()
{
LLTemplateMessageReader* pReader = NULL;
LLTemplateMessageDispatcher t(*pReader);
gValidateMessage = true;
std::vector<U8> vector_data;
fillVector(vector_data, gBinaryTemplateData);
mMessage["body"]["binary-template-data"] = vector_data;
t.dispatch(mMessageName, mMessage, mResponsePtr);
ensure("udp dispatch was called", gUdpDispatchWasCalled);
}
// what if the message wasn't valid? We would hope the message gets cleared!
template<> template<>
void object::test<3>()
{
LLTemplateMessageReader* pReader = NULL;
LLTemplateMessageDispatcher t(*pReader);
std::vector<U8> vector_data;
fillVector(vector_data, gBinaryTemplateData);
mMessage["body"]["binary-template-data"] = vector_data;
gValidateMessage = false;
t.dispatch(mMessageName, mMessage, mResponsePtr);
ensure("clear received message was called", gClearRecvWasCalled);
}
// is the binary data passed through correctly?
template<> template<>
void object::test<4>()
{
LLTemplateMessageReader* pReader = NULL;
LLTemplateMessageDispatcher t(*pReader);
gValidateMessage = true;
std::vector<U8> vector_data;
fillVector(vector_data, gBinaryTemplateData);
mMessage["body"]["binary-template-data"] = vector_data;
t.dispatch(mMessageName, mMessage, mResponsePtr);
ensure("data couriered correctly", strcmp(gBinaryTemplateData, gUdpDispatchedData) == 0);
}
}
@@ -0,0 +1,38 @@
/**
* @file
* @brief
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "lltestmessagesender.h"
LLTestMessageSender::~LLTestMessageSender()
{
}
S32 LLTestMessageSender::sendMessage(const LLHost& host, LLStoredMessagePtr message)
{
mSendHosts.push_back(host);
mSendMessages.push_back(message);
return 0;
}
@@ -0,0 +1,51 @@
/**
* @file
* @brief
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
/* Macro Definitions */
#ifndef LL_LLTESTMESSAGESENDER_H
#define LL_LLTESTMESSAGESENDER_H
#include "linden_common.h"
#include "llmessagesenderinterface.h"
#include <vector>
class LLTestMessageSender : public LLMessageSenderInterface
{
public:
virtual ~LLTestMessageSender();
virtual S32 sendMessage(const LLHost& host, LLStoredMessagePtr message);
std::vector<LLHost> mSendHosts;
std::vector<LLStoredMessagePtr> mSendMessages;
};
#endif //LL_LLTESTMESSAGESENDER_H
@@ -0,0 +1,142 @@
/**
* @file lltrustedmessageservice_test.cpp
* @brief LLTrustedMessageService unit tests
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "lltrustedmessageservice.h"
#include "../test/lltut.h"
#include "llhost.cpp" // LLHost is a value type for test purposes.
#include "net.cpp" // Needed by LLHost.
#include "message.h"
#include "llmessageconfig.h"
#include "llhttpnode_stub.cpp"
#include "llpounceable.h"
LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
LLMessageConfig::SenderTrust
LLMessageConfig::getSenderTrustedness(const std::string& msg_name)
{
return LLMessageConfig::NOT_SET;
}
void LLMessageSystem::receivedMessageFromTrustedSender()
{
}
bool LLMessageSystem::isTrustedSender(const LLHost& host) const
{
return false;
}
bool LLMessageSystem::isTrustedMessage(const std::string& name) const
{
return false;
}
bool messageDispatched = false;
bool messageDispatchedAsBinary = false;
LLSD lastLLSD;
std::string lastMessageName;
void LLMessageSystem::dispatch(const std::string& msg_name,
const LLSD& message,
LLHTTPNode::ResponsePtr responsep)
{
messageDispatched = true;
lastLLSD = message;
lastMessageName = msg_name;
}
void LLMessageSystem::dispatchTemplate(const std::string& msg_name,
const LLSD& message,
LLHTTPNode::ResponsePtr responsep)
{
lastLLSD = message;
lastMessageName = msg_name;
messageDispatchedAsBinary = true;
}
namespace tut
{
struct LLTrustedMessageServiceData
{
LLTrustedMessageServiceData()
{
LLSD emptyLLSD;
lastLLSD = emptyLLSD;
lastMessageName = "uninitialised message name";
messageDispatched = false;
messageDispatchedAsBinary = false;
}
};
typedef test_group<LLTrustedMessageServiceData> factory;
typedef factory::object object;
}
namespace
{
tut::factory tf("LLTrustedMessageServiceData");
}
namespace tut
{
// characterisation tests
// 1) test that messages get forwarded with names etc. as current behaviour (something like LLMessageSystem::dispatch(name, data...)
// test llsd messages are sent as normal using LLMessageSystem::dispatch() (eventually)
template<> template<>
void object::test<1>()
{
LLHTTPNode::ResponsePtr response;
LLSD input;
LLSD context;
LLTrustedMessageService adapter;
adapter.post(response, context, input);
// test original ting got called wit nowt, ya get me blood?
ensure_equals(messageDispatched, true);
ensure(lastLLSD.has("body"));
}
// test that llsd wrapped binary-template-data messages are
// sent via LLMessageSystem::binaryDispatch() or similar
template<> template<>
void object::test<2>()
{
LLHTTPNode::ResponsePtr response;
LLSD input;
input["binary-template-data"] = "10001010110"; //make me a message here.
LLSD context;
LLTrustedMessageService adapter;
adapter.post(response, context, input);
ensure("check template-binary-data message was dispatched as binary", messageDispatchedAsBinary);
ensure_equals(lastLLSD["body"]["binary-template-data"].asString(), "10001010110");
// test somit got called with "10001010110" (something like LLMessageSystem::dispatchTemplate(blah))
}
}
@@ -0,0 +1,58 @@
/**
* @file llxfer_test.cpp
* @author Moss
* @date 2007-04-17
*
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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 "linden_common.h"
#include "../llxfer_file.h"
#include "../test/lltut.h"
namespace tut
{
struct llxfer_data
{
};
typedef test_group<llxfer_data> llxfer_test;
typedef llxfer_test::object llxfer_object;
tut::llxfer_test llxfer("LLXferFile");
template<> template<>
void llxfer_object::test<1>()
{
// test that we handle an oversized filename correctly.
std::string oversized_filename;
U32 i;
for (i=0; i<LL_MAX_PATH*2; ++i) // create oversized filename
{
oversized_filename += 'X';
}
LLXfer_File xff(oversized_filename, false, 1);
ensure("oversized local_filename nul-terminated",
xff.getFileName().length() < LL_MAX_PATH);
}
}
+112
View File
@@ -0,0 +1,112 @@
/**
* @file networkio.h
* @author Nat Goodspeed
* @date 2009-01-09
* @brief
*
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
#if ! defined(LL_NETWORKIO_H)
#define LL_NETWORKIO_H
#include "llmemory.h" // LLSingleton
#include "llapr.h"
#include "llares.h"
#include "llpumpio.h"
#include "llhttpclient.h"
#include "llexception.h"
/*****************************************************************************
* NetworkIO
*****************************************************************************/
// Doing this initialization in a class constructor makes sense. But we don't
// want to redo it for each different test. Nor do we want to do it at static-
// init time. Use the lazy, on-demand initialization we get from LLSingleton.
class NetworkIO: public LLSingleton<NetworkIO>
{
LLSINGLETON(NetworkIO);
NetworkIO():
mServicePump(NULL),
mDone(false)
{
ll_init_apr();
if (! gAPRPoolp)
{
LLTHROW(LLException("Can't initialize APR"));
}
// Create IO Pump to use for HTTP Requests.
mServicePump = new LLPumpIO(gAPRPoolp);
LLHTTPClient::setPump(*mServicePump);
if (ll_init_ares() == NULL || !gAres->isInitialized())
{
LLTHROW(LLException("Can't start DNS resolver"));
}
// You can interrupt pump() without waiting the full timeout duration
// by posting an event to the LLEventPump named "done".
LLEventPumps::instance().obtain("done").listen("self",
boost::bind(&NetworkIO::done, this, _1));
}
public:
bool pump(F32 timeout=10)
{
// Reset the done flag so we don't pop out prematurely
mDone = false;
// Evidently the IO structures underlying LLHTTPClient need to be
// "pumped". Do some stuff normally performed in the viewer's main
// loop.
LLTimer timer;
while (timer.getElapsedTimeF32() < timeout)
{
if (mDone)
{
// std::cout << "NetworkIO::pump(" << timeout << "): breaking loop after "
// << timer.getElapsedTimeF32() << " seconds\n";
return true;
}
pumpOnce();
}
return false;
}
void pumpOnce()
{
gAres->process();
mServicePump->pump();
mServicePump->callback();
}
bool done(const LLSD&)
{
mDone = true;
return false;
}
private:
LLPumpIO* mServicePump;
bool mDone;
};
#endif /* ! defined(LL_NETWORKIO_H) */
+175
View File
@@ -0,0 +1,175 @@
#!/usr/bin/env python3
"""\
@file test_llsdmessage_peer.py
@author Nat Goodspeed
@date 2008-10-09
@brief This script asynchronously runs the executable (with args) specified on
the command line, returning its result code. While that executable is
running, we provide dummy local services for use by C++ tests.
$LicenseInfo:firstyear=2008&license=viewerlgpl$
Second Life Viewer Source Code
Copyright (C) 2010, 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$
"""
import os
import sys
from http.server import HTTPServer, BaseHTTPRequestHandler
import llsd
from testrunner import freeport, run, debug, VERBOSE
import time
_storage=None
class TestHTTPRequestHandler(BaseHTTPRequestHandler):
"""This subclass of BaseHTTPRequestHandler is to receive and echo
LLSD-flavored messages sent by the C++ LLHTTPClient.
"""
def read(self):
# The following logic is adapted from the library module
# SimpleXMLRPCServer.py.
# Get arguments by reading body of request.
# We read this in chunks to avoid straining
# socket.read(); around the 10 or 15Mb mark, some platforms
# begin to have problems (bug #792570).
try:
size_remaining = int(self.headers["content-length"])
except (KeyError, ValueError):
return ""
max_chunk_size = 10*1024*1024
L = []
while size_remaining:
chunk_size = min(size_remaining, max_chunk_size)
chunk = self.rfile.read(chunk_size)
L.append(chunk)
size_remaining -= len(chunk)
return ''.join(L)
# end of swiped read() logic
def read_xml(self):
# This approach reads the entire POST data into memory first
return llsd.parse(self.read())
## # This approach attempts to stream in the LLSD XML from self.rfile,
## # assuming that the underlying XML parser reads its input file
## # incrementally. Unfortunately I haven't been able to make it work.
## tree = xml_parse(self.rfile)
## debug("Finished raw parse")
## debug("parsed XML tree %s", tree)
## debug("parsed root node %s", tree.getroot())
## debug("root node tag %s", tree.getroot().tag)
## return llsd.to_python(tree.getroot())
def do_HEAD(self):
self.do_GET(withdata=False)
def do_GET(self, withdata=True):
# Of course, don't attempt to read data.
data = dict(reply="success", body="avatar", random=17)
self.answer(data, withdata=withdata)
def do_POST(self):
# Read the provided POST data.
self.answer(self.read_xml())
def do_PUT(self):
# Read the provided PUT data.
self.answer(self.read_xml())
def answer(self, data, withdata=True):
global _storage
debug("%s.answer(%s): self.path = %r", self.__class__.__name__, data, self.path)
if "fail" in self.path or "test/error" in self.path: # fail requested
status = data.get("status", 500)
# self.responses maps an int status to a (short, long) pair of
# strings. We want the longer string. That's why we pass a string
# pair to get(): the [1] will select the second string, whether it
# came from self.responses or from our default pair.
reason = data.get("reason",
self.responses.get(status,
("fail requested",
"Your request specified failure status %s "
"without providing a reason" % status))[1])
debug("fail requested: %s: %r", status, reason)
self.send_error(status, reason)
else:
if "web/echo" in self.path:
pass
elif "test/timeout" in self.path:
time.sleep(5.0)
return
elif "test/storage" in self.path:
if "GET" == self.command:
data = _storage
else:
_storage = data
data = "ok"
else:
data = data.copy() # we're going to modify
# Ensure there's a "reply" key in data, even if there wasn't before
data["reply"] = data.get("reply", llsd.LLSD("success"))
response = llsd.format_xml(data)
debug("success: %s", response)
self.send_response(200)
self.send_header("Content-type", "application/llsd+xml")
self.send_header("Content-Length", str(len(response)))
self.end_headers()
if withdata:
self.wfile.write(response)
if not VERBOSE:
# When VERBOSE is set, skip both these overrides because they exist to
# suppress output.
def log_request(self, code, size=None):
# For present purposes, we don't want the request splattered onto
# stderr, as it would upset devs watching the test run
pass
def log_error(self, format, *args):
# Suppress error output as well
pass
class Server(HTTPServer):
# This pernicious flag is on by default in HTTPServer. But proper
# operation of freeport() absolutely depends on it being off.
allow_reuse_address = False
if __name__ == "__main__":
# function to make a server with specified port
make_server = lambda port: Server(('127.0.0.1', port), TestHTTPRequestHandler)
if not sys.platform.startswith("win"):
# Instantiate a Server(TestHTTPRequestHandler) on a port chosen by the
# runtime.
httpd = make_server(0)
else:
# "Then there's Windows"
# Instantiate a Server(TestHTTPRequestHandler) on the first free port
# in the specified port range.
httpd, port = freeport(range(8000, 8020), make_server)
# Pass the selected port number to the subject test program via the
# environment. We don't want to impose requirements on the test program's
# command-line parsing -- and anyway, for C++ integration tests, that's
# performed in TUT code rather than our own.
os.environ["PORT"] = str(httpd.server_port)
debug("$PORT = %s", httpd.server_port)
sys.exit(run(server_inst=httpd, *sys.argv[1:]))
+303
View File
@@ -0,0 +1,303 @@
#!/usr/bin/env python3
"""\
@file testrunner.py
@author Nat Goodspeed
@date 2009-03-20
@brief Utilities for writing wrapper scripts for ADD_COMM_BUILD_TEST unit tests
$LicenseInfo:firstyear=2009&license=viewerlgpl$
Second Life Viewer Source Code
Copyright (C) 2010, 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$
"""
import os
import sys
import re
import errno
import socket
import subprocess
VERBOSE = os.environ.get("INTEGRATION_TEST_VERBOSE", "0") # default to quiet
# Support usage such as INTEGRATION_TEST_VERBOSE=off -- distressing to user if
# that construct actually turns on verbosity...
VERBOSE = not re.match(r"(0|off|false|quiet)$", VERBOSE, re.IGNORECASE)
if VERBOSE:
def debug(fmt, *args):
print(fmt % args)
sys.stdout.flush()
else:
debug = lambda *args: None
class Error(Exception):
pass
def freeport(portlist, expr):
"""
Find a free server port to use. Specifically, evaluate 'expr' (a
callable(port)) until it stops raising EADDRINUSE exception.
Pass:
portlist: an iterable (e.g. xrange()) of ports to try. If you exhaust the
range, freeport() lets the socket.error exception propagate. If you want
unbounded, you could pass itertools.count(baseport), though of course in
practice the ceiling is 2^16-1 anyway. But it seems prudent to constrain
the range much more sharply: if we're iterating an absurd number of times,
probably something else is wrong.
expr: a callable accepting a port number, specifically one of the items
from portlist. If calling that callable raises socket.error with
EADDRINUSE, freeport() retrieves the next item from portlist and retries.
Returns: (expr(port), port)
port: the value from portlist for which expr(port) succeeded
Raises:
Any exception raised by expr(port) other than EADDRINUSE.
socket.error if, for every item from portlist, expr(port) raises
socket.error. The exception you see is the one from the last item in
portlist.
StopIteration if portlist is completely empty.
Example:
class Server(HTTPServer):
# If you use BaseHTTPServer.HTTPServer, turning off this flag is
# essential for proper operation of freeport()!
allow_reuse_address = False
# ...
server, port = freeport(xrange(8000, 8010),
lambda port: Server(("localhost", port),
MyRequestHandler))
# pass 'port' to client code
# call server.serve_forever()
"""
try:
# If portlist is completely empty, let StopIteration propagate: that's an
# error because we can't return meaningful values. We have no 'port',
# therefore no 'expr(port)'.
portiter = iter(portlist)
port = next(portiter)
while True:
try:
# If this value of port works, return as promised.
value = expr(port)
except socket.error as err:
# Anything other than 'Address already in use', propagate
if err.args[0] != errno.EADDRINUSE:
raise
# Here we want the next port from portiter. But on StopIteration,
# we want to raise the original exception rather than
# StopIteration. So save the original exc_info().
type, value, tb = sys.exc_info()
try:
try:
port = next(portiter)
except StopIteration:
raise type(value).with_traceback(tb)
finally:
# Clean up local traceback, see docs for sys.exc_info()
del tb
else:
debug("freeport() returning %s on port %s", value, port)
return value, port
# Recap of the control flow above:
# If expr(port) doesn't raise, return as promised.
# If expr(port) raises anything but EADDRINUSE, propagate that
# exception.
# If portiter.next() raises StopIteration -- that is, if the port
# value we just passed to expr(port) was the last available -- reraise
# the EADDRINUSE exception.
# If we've actually arrived at this point, portiter.next() delivered a
# new port value. Loop back to pass that to expr(port).
except Exception as err:
debug("*** freeport() raising %s: %s", err.__class__.__name__, err)
raise
def run(*args, **kwds):
"""
Run a specified command as a synchronous child process, optionally
launching a server Thread during the run.
All positional arguments collectively form a command line. The first
positional argument names the program file to execute.
Returns the termination code of the child process.
In addition, you may pass keyword-only arguments:
use_path=True: allow a simple filename as command and search PATH for that
filename. (This argument is retained for backwards compatibility but is
now the default behavior.)
server_inst: an instance of a subclass of SocketServer.BaseServer.
When you pass server_inst, run() calls its handle_request() method in a
loop until the child process terminates.
"""
# server= keyword arg is discontinued
try:
thread = kwds.pop("server")
except KeyError:
pass
else:
raise Error("Obsolete call to testrunner.run(): pass server_inst=, not server=")
debug("Running %s...", " ".join(args))
try:
server_inst = kwds.pop("server_inst")
except KeyError:
# Without server_inst, this is very simple: just run child process.
rc = subprocess.call(args)
else:
# We're being asked to run a local server while the child process
# runs. We used to launch a daemon thread calling
# server_inst.serve_forever(), then eventually call sys.exit() with
# the daemon thread still running -- but in recent versions of Python
# 2, even when you call sys.exit(0), apparently killing the thread
# causes the Python runtime to force the process termination code
# nonzero. So now we avoid the extra thread altogether.
# SocketServer.BaseServer.handle_request() honors a 'timeout'
# attribute, if it's set to something other than None.
# We pick 0.5 seconds because that's the default poll timeout for
# BaseServer.serve_forever(), which is what we used to use.
server_inst.timeout = 0.5
child = subprocess.Popen(args)
while child.poll() is None:
# Setting server_inst.timeout is what keeps this handle_request()
# call from blocking "forever." Interestingly, looping over
# handle_request() with a timeout is very like the implementation
# of serve_forever(). We just check a different flag to break out.
# It might be interesting if handle_request() returned an
# indication of whether it in fact handled a request or timed out.
# Oddly, it doesn't. We could discover that by overriding
# handle_timeout(), whose default implementation does nothing --
# but in fact we really don't care. All that matters is that we
# regularly poll both the child process and the server socket.
server_inst.handle_request()
# We don't bother to capture the rc returned by child.poll() because
# poll() is already defined to capture that in its returncode attr.
rc = child.returncode
debug("%s returned %s", args[0], rc)
return rc
# ****************************************************************************
# test code -- manual at this point, see SWAT-564
# ****************************************************************************
def test_freeport():
# ------------------------------- Helpers --------------------------------
from contextlib import contextmanager
# helper Context Manager for expecting an exception
# with exc(SomeError):
# raise SomeError()
# raises AssertionError otherwise.
@contextmanager
def exc(exception_class, *args):
try:
yield
except exception_class as err:
for i, expected_arg in enumerate(args):
assert expected_arg == err.args[i], \
"Raised %s, but args[%s] is %r instead of %r" % \
(err.__class__.__name__, i, err.args[i], expected_arg)
print("Caught expected exception %s(%s)" % \
(err.__class__.__name__, ', '.join(repr(arg) for arg in err.args)))
else:
assert False, "Failed to raise " + exception_class.__class__.__name__
# helper to raise specified exception
def raiser(exception):
raise exception
# the usual
def assert_equals(a, b):
assert a == b, "%r != %r" % (a, b)
# ------------------------ Sanity check the above ------------------------
class SomeError(Exception): pass
# Without extra args, accept any err.args value
with exc(SomeError):
raiser(SomeError("abc"))
# With extra args, accept only the specified value
with exc(SomeError, "abc"):
raiser(SomeError("abc"))
with exc(AssertionError):
with exc(SomeError, "abc"):
raiser(SomeError("def"))
with exc(AssertionError):
with exc(socket.error, errno.EADDRINUSE):
raiser(socket.error(errno.ECONNREFUSED, 'Connection refused'))
# ----------- freeport() without engaging socket functionality -----------
# If portlist is empty, freeport() raises StopIteration.
with exc(StopIteration):
freeport([], None)
assert_equals(freeport([17], str), ("17", 17))
# This is the magic exception that should prompt us to retry
inuse = socket.error(errno.EADDRINUSE, 'Address already in use')
# Get the iterator to our ports list so we can check later if we've used all
ports = iter(range(5))
with exc(socket.error, errno.EADDRINUSE):
freeport(ports, lambda port: raiser(inuse))
# did we entirely exhaust 'ports'?
with exc(StopIteration):
next(ports)
ports = iter(range(2))
# Any exception but EADDRINUSE should quit immediately
with exc(SomeError):
freeport(ports, lambda port: raiser(SomeError()))
assert_equals(next(ports), 1)
# ----------- freeport() with platform-dependent socket stuff ------------
# This is what we should've had unit tests to begin with (see CHOP-661).
def newbind(port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.1', port))
return sock
bound0, port0 = freeport(range(7777, 7780), newbind)
assert_equals(port0, 7777)
bound1, port1 = freeport(range(7777, 7780), newbind)
assert_equals(port1, 7778)
bound2, port2 = freeport(range(7777, 7780), newbind)
assert_equals(port2, 7779)
with exc(socket.error, errno.EADDRINUSE):
bound3, port3 = freeport(range(7777, 7780), newbind)
if __name__ == "__main__":
test_freeport()