And of course i forgot to add some files
This commit is contained in:
97
indra/llmessage/llareslistener.cpp
Normal file
97
indra/llmessage/llareslistener.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @file llareslistener.cpp
|
||||
* @author Nat Goodspeed
|
||||
* @date 2009-03-18
|
||||
* @brief Implementation for llareslistener.
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
// Precompiled header
|
||||
#include "linden_common.h"
|
||||
// associated header
|
||||
#include "llareslistener.h"
|
||||
// STL headers
|
||||
// std headers
|
||||
// external library headers
|
||||
// other Linden headers
|
||||
#include "llares.h"
|
||||
#include "llerror.h"
|
||||
#include "llevents.h"
|
||||
#include "llsdutil.h"
|
||||
|
||||
LLAresListener::LLAresListener(LLAres* llares):
|
||||
LLEventAPI("LLAres",
|
||||
"LLAres listener to request DNS operations"),
|
||||
mAres(llares)
|
||||
{
|
||||
// add() every method we want to be able to invoke via this event API.
|
||||
// Optional last parameter validates expected LLSD request structure.
|
||||
add("rewriteURI",
|
||||
"Given [\"uri\"], return on [\"reply\"] an array of alternative URIs.\n"
|
||||
"On failure, returns an array containing only the original URI, so\n"
|
||||
"failure case can be processed like success case.",
|
||||
&LLAresListener::rewriteURI,
|
||||
LLSD().with("uri", LLSD()).with("reply", LLSD()));
|
||||
}
|
||||
|
||||
/// This UriRewriteResponder subclass packages returned URIs as an LLSD
|
||||
/// array to send back to the requester.
|
||||
class UriRewriteResponder: public LLAres::UriRewriteResponder
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Specify the request, containing the event pump name on which to send
|
||||
* the reply.
|
||||
*/
|
||||
UriRewriteResponder(const LLSD& request):
|
||||
mReqID(request),
|
||||
mPumpName(request["reply"])
|
||||
{}
|
||||
|
||||
/// Called by base class with results. This is called in both the
|
||||
/// success and error cases. On error, the calling logic passes the
|
||||
/// original URI.
|
||||
virtual void rewriteResult(const std::vector<std::string>& uris)
|
||||
{
|
||||
LLSD result;
|
||||
for (std::vector<std::string>::const_iterator ui(uris.begin()), uend(uris.end());
|
||||
ui != uend; ++ui)
|
||||
{
|
||||
result.append(*ui);
|
||||
}
|
||||
// This call knows enough to avoid trying to insert a map key into an
|
||||
// LLSD array. It's there so that if, for any reason, we ever decide
|
||||
// to change the response from array to map, it will Just Start Working.
|
||||
mReqID.stamp(result);
|
||||
LLEventPumps::instance().obtain(mPumpName).post(result);
|
||||
}
|
||||
|
||||
private:
|
||||
LLReqID mReqID;
|
||||
const std::string mPumpName;
|
||||
};
|
||||
|
||||
void LLAresListener::rewriteURI(const LLSD& data)
|
||||
{
|
||||
mAres->rewriteURI(data["uri"], new UriRewriteResponder(data));
|
||||
}
|
||||
53
indra/llmessage/llareslistener.h
Normal file
53
indra/llmessage/llareslistener.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @file llareslistener.h
|
||||
* @author Nat Goodspeed
|
||||
* @date 2009-03-18
|
||||
* @brief LLEventPump API for LLAres. This header doesn't actually define the
|
||||
* API; the API is defined by the pump name on which this class
|
||||
* listens, and by the expected content of LLSD it receives.
|
||||
*
|
||||
* $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_LLARESLISTENER_H)
|
||||
#define LL_LLARESLISTENER_H
|
||||
|
||||
#include "lleventapi.h"
|
||||
|
||||
class LLAres;
|
||||
class LLSD;
|
||||
|
||||
/// Listen on an LLEventPump with specified name for LLAres request events.
|
||||
class LLAresListener: public LLEventAPI
|
||||
{
|
||||
public:
|
||||
/// Bind the LLAres instance to use (e.g. gAres)
|
||||
LLAresListener(LLAres* llares);
|
||||
|
||||
private:
|
||||
/// command["op"] == "rewriteURI"
|
||||
void rewriteURI(const LLSD& data);
|
||||
|
||||
LLAres* mAres;
|
||||
};
|
||||
|
||||
#endif /* ! defined(LL_LLARESLISTENER_H) */
|
||||
546
indra/llmessage/llproxy.cpp
Normal file
546
indra/llmessage/llproxy.cpp
Normal file
@@ -0,0 +1,546 @@
|
||||
/**
|
||||
* @file llproxy.cpp
|
||||
* @brief UDP and HTTP proxy communications
|
||||
*
|
||||
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2011, 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 "llproxy.h"
|
||||
|
||||
#include <string>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "llapr.h"
|
||||
#include "llcurl.h"
|
||||
#include "llhost.h"
|
||||
|
||||
// Static class variable instances
|
||||
|
||||
// We want this to be static to avoid excessive indirection on every
|
||||
// incoming packet just to do a simple bool test. The getter for this
|
||||
// member is also static
|
||||
bool LLProxy::sUDPProxyEnabled = false;
|
||||
|
||||
// Some helpful TCP static functions.
|
||||
static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen); // Do a TCP data handshake
|
||||
static LLSocket::ptr_t tcp_open_channel(LLHost host); // Open a TCP channel to a given host
|
||||
static void tcp_close_channel(LLSocket::ptr_t* handle_ptr); // Close an open TCP channel
|
||||
|
||||
LLProxy::LLProxy():
|
||||
mHTTPProxyEnabled(false),
|
||||
mProxyMutex(),
|
||||
mUDPProxy(),
|
||||
mTCPProxy(),
|
||||
mHTTPProxy(),
|
||||
mProxyType(LLPROXY_SOCKS),
|
||||
mAuthMethodSelected(METHOD_NOAUTH),
|
||||
mSocksUsername(),
|
||||
mSocksPassword()
|
||||
{
|
||||
}
|
||||
|
||||
LLProxy::~LLProxy()
|
||||
{
|
||||
stopSOCKSProxy();
|
||||
disableHTTPProxy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Open the SOCKS 5 TCP control channel.
|
||||
*
|
||||
* Perform a SOCKS 5 authentication and UDP association with the proxy server.
|
||||
*
|
||||
* @param proxy The SOCKS 5 server to connect to.
|
||||
* @return SOCKS_OK if successful, otherwise a socks error code from llproxy.h.
|
||||
*/
|
||||
S32 LLProxy::proxyHandshake(LLHost proxy)
|
||||
{
|
||||
S32 result;
|
||||
|
||||
/* SOCKS 5 Auth request */
|
||||
socks_auth_request_t socks_auth_request;
|
||||
socks_auth_response_t socks_auth_response;
|
||||
|
||||
socks_auth_request.version = SOCKS_VERSION; // SOCKS version 5
|
||||
socks_auth_request.num_methods = 1; // Sending 1 method.
|
||||
socks_auth_request.methods = getSelectedAuthMethod(); // Send only the selected method.
|
||||
|
||||
result = tcp_blocking_handshake(mProxyControlChannel,
|
||||
static_cast<char*>(static_cast<void*>(&socks_auth_request)),
|
||||
sizeof(socks_auth_request),
|
||||
static_cast<char*>(static_cast<void*>(&socks_auth_response)),
|
||||
sizeof(socks_auth_response));
|
||||
if (result != APR_SUCCESS)
|
||||
{
|
||||
LL_WARNS("Proxy") << "SOCKS authentication request failed, error on TCP control channel : " << result << LL_ENDL;
|
||||
stopSOCKSProxy();
|
||||
return SOCKS_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
if (socks_auth_response.method == AUTH_NOT_ACCEPTABLE)
|
||||
{
|
||||
LL_WARNS("Proxy") << "SOCKS 5 server refused all our authentication methods." << LL_ENDL;
|
||||
stopSOCKSProxy();
|
||||
return SOCKS_NOT_ACCEPTABLE;
|
||||
}
|
||||
|
||||
/* SOCKS 5 USERNAME/PASSWORD authentication */
|
||||
if (socks_auth_response.method == METHOD_PASSWORD)
|
||||
{
|
||||
// The server has requested a username/password combination
|
||||
std::string socks_username(getSocksUser());
|
||||
std::string socks_password(getSocksPwd());
|
||||
U32 request_size = socks_username.size() + socks_password.size() + 3;
|
||||
char * password_auth = new char[request_size];
|
||||
password_auth[0] = 0x01;
|
||||
password_auth[1] = socks_username.size();
|
||||
memcpy(&password_auth[2], socks_username.c_str(), socks_username.size());
|
||||
password_auth[socks_username.size() + 2] = socks_password.size();
|
||||
memcpy(&password_auth[socks_username.size() + 3], socks_password.c_str(), socks_password.size());
|
||||
|
||||
authmethod_password_reply_t password_reply;
|
||||
|
||||
result = tcp_blocking_handshake(mProxyControlChannel,
|
||||
password_auth,
|
||||
request_size,
|
||||
static_cast<char*>(static_cast<void*>(&password_reply)),
|
||||
sizeof(password_reply));
|
||||
delete[] password_auth;
|
||||
|
||||
if (result != APR_SUCCESS)
|
||||
{
|
||||
LL_WARNS("Proxy") << "SOCKS authentication failed, error on TCP control channel : " << result << LL_ENDL;
|
||||
stopSOCKSProxy();
|
||||
return SOCKS_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
if (password_reply.status != AUTH_SUCCESS)
|
||||
{
|
||||
LL_WARNS("Proxy") << "SOCKS authentication failed" << LL_ENDL;
|
||||
stopSOCKSProxy();
|
||||
return SOCKS_AUTH_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* SOCKS5 connect request */
|
||||
|
||||
socks_command_request_t connect_request;
|
||||
socks_command_response_t connect_reply;
|
||||
|
||||
connect_request.version = SOCKS_VERSION; // SOCKS V5
|
||||
connect_request.command = COMMAND_UDP_ASSOCIATE; // Associate UDP
|
||||
connect_request.reserved = FIELD_RESERVED;
|
||||
connect_request.atype = ADDRESS_IPV4;
|
||||
connect_request.address = htonl(0); // 0.0.0.0
|
||||
connect_request.port = htons(0); // 0
|
||||
// "If the client is not in possession of the information at the time of the UDP ASSOCIATE,
|
||||
// the client MUST use a port number and address of all zeros. RFC 1928"
|
||||
|
||||
result = tcp_blocking_handshake(mProxyControlChannel,
|
||||
static_cast<char*>(static_cast<void*>(&connect_request)),
|
||||
sizeof(connect_request),
|
||||
static_cast<char*>(static_cast<void*>(&connect_reply)),
|
||||
sizeof(connect_reply));
|
||||
if (result != APR_SUCCESS)
|
||||
{
|
||||
LL_WARNS("Proxy") << "SOCKS connect request failed, error on TCP control channel : " << result << LL_ENDL;
|
||||
stopSOCKSProxy();
|
||||
return SOCKS_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
if (connect_reply.reply != REPLY_REQUEST_GRANTED)
|
||||
{
|
||||
LL_WARNS("Proxy") << "Connection to SOCKS 5 server failed, UDP forward request not granted" << LL_ENDL;
|
||||
stopSOCKSProxy();
|
||||
return SOCKS_UDP_FWD_NOT_GRANTED;
|
||||
}
|
||||
|
||||
mUDPProxy.setPort(ntohs(connect_reply.port)); // reply port is in network byte order
|
||||
mUDPProxy.setAddress(proxy.getAddress());
|
||||
// The connection was successful. We now have the UDP port to send requests that need forwarding to.
|
||||
LL_INFOS("Proxy") << "SOCKS 5 UDP proxy connected on " << mUDPProxy << LL_ENDL;
|
||||
|
||||
return SOCKS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initiates a SOCKS 5 proxy session.
|
||||
*
|
||||
* Performs basic checks on host to verify that it is a valid address. Opens the control channel
|
||||
* and then negotiates the proxy connection with the server. Closes any existing SOCKS
|
||||
* connection before proceeding. Also disables an HTTP proxy if it is using SOCKS as the proxy.
|
||||
*
|
||||
*
|
||||
* @param host Socks server to connect to.
|
||||
* @return SOCKS_OK if successful, otherwise a SOCKS error code defined in llproxy.h.
|
||||
*/
|
||||
S32 LLProxy::startSOCKSProxy(LLHost host)
|
||||
{
|
||||
if (host.isOk())
|
||||
{
|
||||
mTCPProxy = host;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SOCKS_INVALID_HOST;
|
||||
}
|
||||
|
||||
// Close any running SOCKS connection.
|
||||
stopSOCKSProxy();
|
||||
|
||||
mProxyControlChannel = tcp_open_channel(mTCPProxy);
|
||||
if (!mProxyControlChannel)
|
||||
{
|
||||
return SOCKS_HOST_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
S32 status = proxyHandshake(mTCPProxy);
|
||||
|
||||
if (status != SOCKS_OK)
|
||||
{
|
||||
// Shut down the proxy if any of the above steps failed.
|
||||
stopSOCKSProxy();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Connection was successful.
|
||||
sUDPProxyEnabled = true;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop using the SOCKS 5 proxy.
|
||||
*
|
||||
* This will stop sending UDP packets through the SOCKS 5 proxy
|
||||
* and will also stop the HTTP proxy if it is configured to use SOCKS.
|
||||
* The proxy control channel will also be disconnected.
|
||||
*/
|
||||
void LLProxy::stopSOCKSProxy()
|
||||
{
|
||||
sUDPProxyEnabled = false;
|
||||
|
||||
// If the SOCKS proxy is requested to stop and we are using that for HTTP as well
|
||||
// then we must shut down any HTTP proxy operations. But it is allowable if web
|
||||
// proxy is being used to continue proxying HTTP.
|
||||
|
||||
if (LLPROXY_SOCKS == getHTTPProxyType())
|
||||
{
|
||||
disableHTTPProxy();
|
||||
}
|
||||
|
||||
if (mProxyControlChannel)
|
||||
{
|
||||
tcp_close_channel(&mProxyControlChannel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the proxy's SOCKS authentication method to none.
|
||||
*/
|
||||
void LLProxy::setAuthNone()
|
||||
{
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
|
||||
mAuthMethodSelected = METHOD_NOAUTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the proxy's SOCKS authentication method to password.
|
||||
*
|
||||
* Check whether the lengths of the supplied username
|
||||
* and password conform to the lengths allowed by the
|
||||
* SOCKS protocol.
|
||||
*
|
||||
* @param username The SOCKS username to send.
|
||||
* @param password The SOCKS password to send.
|
||||
* @return Return true if applying the settings was successful. No changes are made if false.
|
||||
*
|
||||
*/
|
||||
bool LLProxy::setAuthPassword(const std::string &username, const std::string &password)
|
||||
{
|
||||
if (username.length() > SOCKSMAXUSERNAMELEN || password.length() > SOCKSMAXPASSWORDLEN ||
|
||||
username.length() < SOCKSMINUSERNAMELEN || password.length() < SOCKSMINPASSWORDLEN)
|
||||
{
|
||||
LL_WARNS("Proxy") << "Invalid SOCKS 5 password or username length." << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
|
||||
mAuthMethodSelected = METHOD_PASSWORD;
|
||||
mSocksUsername = username;
|
||||
mSocksPassword = password;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the HTTP proxy for either SOCKS or HTTP.
|
||||
*
|
||||
* Check the supplied host to see if it is a valid IP and port.
|
||||
*
|
||||
* @param httpHost Proxy server to connect to.
|
||||
* @param type Is the host a SOCKS or HTTP proxy.
|
||||
* @return Return true if applying the setting was successful. No changes are made if false.
|
||||
*/
|
||||
bool LLProxy::enableHTTPProxy(LLHost httpHost, LLHttpProxyType type)
|
||||
{
|
||||
if (!httpHost.isOk())
|
||||
{
|
||||
LL_WARNS("Proxy") << "Invalid SOCKS 5 Server" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
|
||||
mHTTPProxy = httpHost;
|
||||
mProxyType = type;
|
||||
|
||||
mHTTPProxyEnabled = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable the HTTP proxy without changing the proxy settings.
|
||||
*
|
||||
* This should not be called unless the proxy has already been set up.
|
||||
*
|
||||
* @return Return true only if the current settings are valid and the proxy was enabled.
|
||||
*/
|
||||
bool LLProxy::enableHTTPProxy()
|
||||
{
|
||||
bool ok;
|
||||
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
|
||||
ok = (mHTTPProxy.isOk());
|
||||
if (ok)
|
||||
{
|
||||
mHTTPProxyEnabled = true;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable the HTTP proxy.
|
||||
*/
|
||||
void LLProxy::disableHTTPProxy()
|
||||
{
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
|
||||
mHTTPProxyEnabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the currently selected HTTP proxy type
|
||||
*/
|
||||
LLHttpProxyType LLProxy::getHTTPProxyType() const
|
||||
{
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
return mProxyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the SOCKS 5 password.
|
||||
*/
|
||||
std::string LLProxy::getSocksPwd() const
|
||||
{
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
return mSocksPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the SOCKS 5 username.
|
||||
*/
|
||||
std::string LLProxy::getSocksUser() const
|
||||
{
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
return mSocksUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the currently selected SOCKS 5 authentication method.
|
||||
*
|
||||
* @return Returns either none or password.
|
||||
*/
|
||||
LLSocks5AuthType LLProxy::getSelectedAuthMethod() const
|
||||
{
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
return mAuthMethodSelected;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop the LLProxy and make certain that any APR pools and classes are deleted before terminating APR.
|
||||
*
|
||||
* Deletes the LLProxy singleton, destroying the APR pool used by the control channel as well as .
|
||||
*/
|
||||
//static
|
||||
void LLProxy::cleanupClass()
|
||||
{
|
||||
getInstance()->stopSOCKSProxy();
|
||||
deleteSingleton();
|
||||
}
|
||||
|
||||
void LLProxy::applyProxySettings(LLCurlEasyRequest* handle)
|
||||
{
|
||||
applyProxySettings(handle->getEasy());
|
||||
}
|
||||
|
||||
void LLProxy::applyProxySettings(LLCurl::Easy* handle)
|
||||
{
|
||||
applyProxySettings(handle->getCurlHandle());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Apply proxy settings to a CuRL request if an HTTP proxy is enabled.
|
||||
*
|
||||
* This method has been designed to be safe to call from
|
||||
* any thread in the viewer. This allows requests in the
|
||||
* texture fetch thread to be aware of the proxy settings.
|
||||
* When the HTTP proxy is enabled, the proxy mutex will
|
||||
* be locked every time this method is called.
|
||||
*
|
||||
* @param handle A pointer to a valid CURL request, before it has been performed.
|
||||
*/
|
||||
void LLProxy::applyProxySettings(CURL* handle)
|
||||
{
|
||||
// Do a faster unlocked check to see if we are supposed to proxy.
|
||||
if (mHTTPProxyEnabled)
|
||||
{
|
||||
// We think we should proxy, lock the proxy mutex.
|
||||
LLMutexLock lock(&mProxyMutex);
|
||||
// Now test again to verify that the proxy wasn't disabled between the first check and the lock.
|
||||
if (mHTTPProxyEnabled)
|
||||
{
|
||||
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXY, mHTTPProxy.getIPString().c_str()));
|
||||
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYPORT, mHTTPProxy.getPort()));
|
||||
|
||||
if (mProxyType == LLPROXY_SOCKS)
|
||||
{
|
||||
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5));
|
||||
if (mAuthMethodSelected == METHOD_PASSWORD)
|
||||
{
|
||||
std::string auth_string = mSocksUsername + ":" + mSocksPassword;
|
||||
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, auth_string.c_str()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LLCurlFF::check_easy_code(curl_easy_setopt(handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send one TCP packet and receive one in return.
|
||||
*
|
||||
* This operation is done synchronously with a 1000ms timeout. Therefore, it should not be used when a blocking
|
||||
* operation would impact the operation of the viewer.
|
||||
*
|
||||
* @param handle_ptr Pointer to a connected LLSocket of type STREAM_TCP.
|
||||
* @param dataout Data to send.
|
||||
* @param outlen Length of dataout.
|
||||
* @param datain Buffer for received data. Undefined if return value is not APR_SUCCESS.
|
||||
* @param maxinlen Maximum possible length of received data. Short reads are allowed.
|
||||
* @return Indicates APR status code of exchange. APR_SUCCESS if exchange was successful, -1 if invalid data length was received.
|
||||
*/
|
||||
static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataout, apr_size_t outlen, char * datain, apr_size_t maxinlen)
|
||||
{
|
||||
apr_socket_t* apr_socket = handle->getSocket();
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
|
||||
apr_size_t expected_len = outlen;
|
||||
|
||||
handle->setBlocking(1000);
|
||||
|
||||
rv = apr_socket_send(apr_socket, dataout, &outlen);
|
||||
if (APR_SUCCESS != rv)
|
||||
{
|
||||
LL_WARNS("Proxy") << "Error sending data to proxy control channel, status: " << rv << LL_ENDL;
|
||||
ll_apr_warn_status(rv);
|
||||
}
|
||||
else if (expected_len != outlen)
|
||||
{
|
||||
LL_WARNS("Proxy") << "Incorrect data length sent. Expected: " << expected_len <<
|
||||
" Sent: " << outlen << LL_ENDL;
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
if (APR_SUCCESS == rv)
|
||||
{
|
||||
expected_len = maxinlen;
|
||||
rv = apr_socket_recv(apr_socket, datain, &maxinlen);
|
||||
if (rv != APR_SUCCESS)
|
||||
{
|
||||
LL_WARNS("Proxy") << "Error receiving data from proxy control channel, status: " << rv << LL_ENDL;
|
||||
ll_apr_warn_status(rv);
|
||||
}
|
||||
else if (expected_len < maxinlen)
|
||||
{
|
||||
LL_WARNS("Proxy") << "Incorrect data length received. Expected: " << expected_len <<
|
||||
" Received: " << maxinlen << LL_ENDL;
|
||||
rv = -1;
|
||||
}
|
||||
}
|
||||
|
||||
handle->setNonBlocking();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Open a LLSocket and do a blocking connect to the chosen host.
|
||||
*
|
||||
* Checks for a successful connection, and makes sure the connection is closed if it fails.
|
||||
*
|
||||
* @param host The host to open the connection to.
|
||||
* @return The created socket. Will evaluate as NULL if the connection is unsuccessful.
|
||||
*/
|
||||
static LLSocket::ptr_t tcp_open_channel(LLHost host)
|
||||
{
|
||||
LLSocket::ptr_t socket = LLSocket::create(LLSocket::STREAM_TCP);
|
||||
bool connected = socket->blockingConnect(host);
|
||||
if (!connected)
|
||||
{
|
||||
tcp_close_channel(&socket);
|
||||
}
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Close the socket.
|
||||
*
|
||||
* @param handle_ptr The handle of the socket being closed. A pointer-to-pointer to avoid increasing the use count.
|
||||
*/
|
||||
static void tcp_close_channel(LLSocket::ptr_t* handle_ptr)
|
||||
{
|
||||
LL_DEBUGS("Proxy") << "Resetting proxy LLSocket handle, use_count == " << handle_ptr->use_count() << LL_ENDL;
|
||||
handle_ptr->reset();
|
||||
}
|
||||
352
indra/llmessage/llproxy.h
Normal file
352
indra/llmessage/llproxy.h
Normal file
@@ -0,0 +1,352 @@
|
||||
/**
|
||||
* @file llproxy.h
|
||||
* @brief UDP and HTTP proxy communications
|
||||
*
|
||||
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2011, 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_PROXY_H
|
||||
#define LL_PROXY_H
|
||||
|
||||
#include "llcurl.h"
|
||||
#include "llhost.h"
|
||||
#include "lliosocket.h"
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
#include "llthread.h"
|
||||
#include <string>
|
||||
|
||||
// SOCKS error codes returned from the StartProxy method
|
||||
#define SOCKS_OK 0
|
||||
#define SOCKS_CONNECT_ERROR (-1)
|
||||
#define SOCKS_NOT_PERMITTED (-2)
|
||||
#define SOCKS_NOT_ACCEPTABLE (-3)
|
||||
#define SOCKS_AUTH_FAIL (-4)
|
||||
#define SOCKS_UDP_FWD_NOT_GRANTED (-5)
|
||||
#define SOCKS_HOST_CONNECT_FAILED (-6)
|
||||
#define SOCKS_INVALID_HOST (-7)
|
||||
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
#define MAXHOSTNAMELEN (255 + 1) /* socks5: 255, +1 for len. */
|
||||
#endif
|
||||
|
||||
#define SOCKSMAXUSERNAMELEN 255
|
||||
#define SOCKSMAXPASSWORDLEN 255
|
||||
|
||||
#define SOCKSMINUSERNAMELEN 1
|
||||
#define SOCKSMINPASSWORDLEN 1
|
||||
|
||||
#define SOCKS_VERSION 0x05 // we are using SOCKS 5
|
||||
|
||||
#define SOCKS_HEADER_SIZE 10
|
||||
|
||||
// SOCKS 5 address/hostname types
|
||||
#define ADDRESS_IPV4 0x01
|
||||
#define ADDRESS_HOSTNAME 0x03
|
||||
#define ADDRESS_IPV6 0x04
|
||||
|
||||
// Lets just use our own ipv4 struct rather than dragging in system
|
||||
// specific headers
|
||||
union ipv4_address_t {
|
||||
U8 octets[4];
|
||||
U32 addr32;
|
||||
};
|
||||
|
||||
// SOCKS 5 control channel commands
|
||||
#define COMMAND_TCP_STREAM 0x01
|
||||
#define COMMAND_TCP_BIND 0x02
|
||||
#define COMMAND_UDP_ASSOCIATE 0x03
|
||||
|
||||
// SOCKS 5 command replies
|
||||
#define REPLY_REQUEST_GRANTED 0x00
|
||||
#define REPLY_GENERAL_FAIL 0x01
|
||||
#define REPLY_RULESET_FAIL 0x02
|
||||
#define REPLY_NETWORK_UNREACHABLE 0x03
|
||||
#define REPLY_HOST_UNREACHABLE 0x04
|
||||
#define REPLY_CONNECTION_REFUSED 0x05
|
||||
#define REPLY_TTL_EXPIRED 0x06
|
||||
#define REPLY_PROTOCOL_ERROR 0x07
|
||||
#define REPLY_TYPE_NOT_SUPPORTED 0x08
|
||||
|
||||
#define FIELD_RESERVED 0x00
|
||||
|
||||
// The standard SOCKS 5 request packet
|
||||
// Push current alignment to stack and set alignment to 1 byte boundary
|
||||
// This enabled us to use structs directly to set up and receive network packets
|
||||
// into the correct fields, without fear of boundary alignment causing issues
|
||||
#pragma pack(push,1)
|
||||
|
||||
// SOCKS 5 command packet
|
||||
struct socks_command_request_t {
|
||||
U8 version;
|
||||
U8 command;
|
||||
U8 reserved;
|
||||
U8 atype;
|
||||
U32 address;
|
||||
U16 port;
|
||||
};
|
||||
|
||||
// Standard SOCKS 5 reply packet
|
||||
struct socks_command_response_t {
|
||||
U8 version;
|
||||
U8 reply;
|
||||
U8 reserved;
|
||||
U8 atype;
|
||||
U8 add_bytes[4];
|
||||
U16 port;
|
||||
};
|
||||
|
||||
#define AUTH_NOT_ACCEPTABLE 0xFF // reply if preferred methods are not available
|
||||
#define AUTH_SUCCESS 0x00 // reply if authentication successful
|
||||
|
||||
// SOCKS 5 authentication request, stating which methods the client supports
|
||||
struct socks_auth_request_t {
|
||||
U8 version;
|
||||
U8 num_methods;
|
||||
U8 methods; // We are only using a single method currently
|
||||
};
|
||||
|
||||
// SOCKS 5 authentication response packet, stating server preferred method
|
||||
struct socks_auth_response_t {
|
||||
U8 version;
|
||||
U8 method;
|
||||
};
|
||||
|
||||
// SOCKS 5 password reply packet
|
||||
struct authmethod_password_reply_t {
|
||||
U8 version;
|
||||
U8 status;
|
||||
};
|
||||
|
||||
// SOCKS 5 UDP packet header
|
||||
struct proxywrap_t {
|
||||
U16 rsv;
|
||||
U8 frag;
|
||||
U8 atype;
|
||||
U32 addr;
|
||||
U16 port;
|
||||
};
|
||||
|
||||
#pragma pack(pop) /* restore original alignment from stack */
|
||||
|
||||
|
||||
// Currently selected HTTP proxy type
|
||||
enum LLHttpProxyType
|
||||
{
|
||||
LLPROXY_SOCKS = 0,
|
||||
LLPROXY_HTTP = 1
|
||||
};
|
||||
|
||||
// Auth types
|
||||
enum LLSocks5AuthType
|
||||
{
|
||||
METHOD_NOAUTH = 0x00, // Client supports no auth
|
||||
METHOD_GSSAPI = 0x01, // Client supports GSSAPI (Not currently supported)
|
||||
METHOD_PASSWORD = 0x02 // Client supports username/password
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Manage SOCKS 5 UDP proxy and HTTP proxy.
|
||||
*
|
||||
* This class is responsible for managing two interconnected tasks,
|
||||
* connecting to a SOCKS 5 proxy for use by LLPacketRing to send UDP
|
||||
* packets and managing proxy settings for HTTP requests.
|
||||
*
|
||||
* <h1>Threading:</h1>
|
||||
* Because HTTP requests can be generated in threads outside the
|
||||
* main thread, it is necessary for some of the information stored
|
||||
* by this class to be available to other threads. The members that
|
||||
* need to be read across threads are in a labeled section below.
|
||||
* To protect those members, a mutex, mProxyMutex should be locked
|
||||
* before reading or writing those members. Methods that can lock
|
||||
* mProxyMutex are in a labeled section below. Those methods should
|
||||
* not be called while the mutex is already locked.
|
||||
*
|
||||
* There is also a LLAtomic type flag (mHTTPProxyEnabled) that is used
|
||||
* to track whether the HTTP proxy is currently enabled. This allows
|
||||
* for faster unlocked checks to see if the proxy is enabled. This
|
||||
* allows us to cut down on the performance hit when the proxy is
|
||||
* disabled compared to before this class was introduced.
|
||||
*
|
||||
* <h1>UDP Proxying:</h1>
|
||||
* UDP datagrams are proxied via a SOCKS 5 proxy with the UDP associate
|
||||
* command. To initiate the proxy, a TCP socket connection is opened
|
||||
* to the SOCKS 5 host, and after a handshake exchange, the server
|
||||
* returns a port and address to send the UDP traffic that is to be
|
||||
* proxied to. The LLProxy class tracks this address and port after the
|
||||
* exchange and provides it to LLPacketRing when required to. All UDP
|
||||
* proxy management occurs in the main thread.
|
||||
*
|
||||
* <h1>HTTP Proxying:</h1>
|
||||
* This class allows all viewer HTTP packets to be sent through a proxy.
|
||||
* The user can select whether to send HTTP packets through a standard
|
||||
* "web" HTTP proxy, through a SOCKS 5 proxy, or to not proxy HTTP
|
||||
* communication. This class does not manage the integrated web browser
|
||||
* proxy, which is handled in llviewermedia.cpp.
|
||||
*
|
||||
* The implementation of HTTP proxying is handled by libcurl. LLProxy
|
||||
* is responsible for managing the HTTP proxy options and provides a
|
||||
* thread-safe method to apply those options to a curl request
|
||||
* (LLProxy::applyProxySettings()). This method is overloaded
|
||||
* to accommodate the various abstraction libcurl layers that exist
|
||||
* throughout the viewer (LLCurlEasyRequest, LLCurl::Easy, and CURL).
|
||||
*
|
||||
* If you are working with LLCurl or LLCurlEasyRequest objects,
|
||||
* the configured proxy settings will be applied in the constructors
|
||||
* of those request handles. If you are working with CURL objects
|
||||
* directly, you will need to pass the handle of the request to
|
||||
* applyProxySettings() before issuing the request.
|
||||
*
|
||||
* To ensure thread safety, all LLProxy members that relate to the HTTP
|
||||
* proxy require the LLProxyMutex to be locked before accessing.
|
||||
*/
|
||||
class LLProxy: public LLSingleton<LLProxy>
|
||||
{
|
||||
LOG_CLASS(LLProxy);
|
||||
public:
|
||||
/*###########################################################################################
|
||||
METHODS THAT DO NOT LOCK mProxyMutex!
|
||||
###########################################################################################*/
|
||||
// Constructor, cannot have parameters due to LLSingleton parent class. Call from main thread only.
|
||||
LLProxy();
|
||||
|
||||
// Static check for enabled status for UDP packets. Call from main thread only.
|
||||
static bool isSOCKSProxyEnabled() { return sUDPProxyEnabled; }
|
||||
|
||||
// Get the UDP proxy address and port. Call from main thread only.
|
||||
LLHost getUDPProxy() const { return mUDPProxy; }
|
||||
|
||||
/*###########################################################################################
|
||||
END OF NON-LOCKING METHODS
|
||||
###########################################################################################*/
|
||||
|
||||
/*###########################################################################################
|
||||
METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED!
|
||||
###########################################################################################*/
|
||||
// Destructor, closes open connections. Do not call directly, use cleanupClass().
|
||||
~LLProxy();
|
||||
|
||||
// Delete LLProxy singleton. Allows the apr_socket used in the SOCKS 5 control channel to be
|
||||
// destroyed before the call to apr_terminate. Call from main thread only.
|
||||
static void cleanupClass();
|
||||
|
||||
// Apply the current proxy settings to a curl request. Doesn't do anything if mHTTPProxyEnabled is false.
|
||||
// Safe to call from any thread.
|
||||
void applyProxySettings(CURL* handle);
|
||||
void applyProxySettings(LLCurl::Easy* handle);
|
||||
void applyProxySettings(LLCurlEasyRequest* handle);
|
||||
|
||||
// Start a connection to the SOCKS 5 proxy. Call from main thread only.
|
||||
S32 startSOCKSProxy(LLHost host);
|
||||
|
||||
// Disconnect and clean up any connection to the SOCKS 5 proxy. Call from main thread only.
|
||||
void stopSOCKSProxy();
|
||||
|
||||
// Use Password auth when connecting to the SOCKS proxy. Call from main thread only.
|
||||
bool setAuthPassword(const std::string &username, const std::string &password);
|
||||
|
||||
// Disable authentication when connecting to the SOCKS proxy. Call from main thread only.
|
||||
void setAuthNone();
|
||||
|
||||
// Proxy HTTP packets via httpHost, which can be a SOCKS 5 or a HTTP proxy.
|
||||
// as specified in type. Call from main thread only.
|
||||
bool enableHTTPProxy(LLHost httpHost, LLHttpProxyType type);
|
||||
bool enableHTTPProxy();
|
||||
|
||||
// Stop proxying HTTP packets. Call from main thread only.
|
||||
void disableHTTPProxy();
|
||||
|
||||
/*###########################################################################################
|
||||
END OF LOCKING METHODS
|
||||
###########################################################################################*/
|
||||
private:
|
||||
/*###########################################################################################
|
||||
METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED!
|
||||
###########################################################################################*/
|
||||
|
||||
// Perform a SOCKS 5 authentication and UDP association with the proxy server.
|
||||
S32 proxyHandshake(LLHost proxy);
|
||||
|
||||
// Get the currently selected auth method.
|
||||
LLSocks5AuthType getSelectedAuthMethod() const;
|
||||
|
||||
// Get the currently selected HTTP proxy type
|
||||
LLHttpProxyType getHTTPProxyType() const;
|
||||
|
||||
std::string getSocksPwd() const;
|
||||
std::string getSocksUser() const;
|
||||
|
||||
/*###########################################################################################
|
||||
END OF LOCKING METHODS
|
||||
###########################################################################################*/
|
||||
|
||||
private:
|
||||
// Is the HTTP proxy enabled? Safe to read in any thread, but do not write directly.
|
||||
// Instead use enableHTTPProxy() and disableHTTPProxy() instead.
|
||||
mutable LLAtomic32<bool> mHTTPProxyEnabled;
|
||||
|
||||
// Mutex to protect shared members in non-main thread calls to applyProxySettings().
|
||||
mutable LLMutex mProxyMutex;
|
||||
|
||||
/*###########################################################################################
|
||||
MEMBERS READ AND WRITTEN ONLY IN THE MAIN THREAD. DO NOT SHARE!
|
||||
###########################################################################################*/
|
||||
|
||||
// Is the UDP proxy enabled?
|
||||
static bool sUDPProxyEnabled;
|
||||
|
||||
// UDP proxy address and port
|
||||
LLHost mUDPProxy;
|
||||
// TCP proxy control channel address and port
|
||||
LLHost mTCPProxy;
|
||||
|
||||
// socket handle to proxy TCP control channel
|
||||
LLSocket::ptr_t mProxyControlChannel;
|
||||
|
||||
/*###########################################################################################
|
||||
END OF UNSHARED MEMBERS
|
||||
###########################################################################################*/
|
||||
|
||||
/*###########################################################################################
|
||||
MEMBERS WRITTEN IN MAIN THREAD AND READ IN ANY THREAD. ONLY READ OR WRITE AFTER LOCKING mProxyMutex!
|
||||
###########################################################################################*/
|
||||
|
||||
// HTTP proxy address and port
|
||||
LLHost mHTTPProxy;
|
||||
|
||||
// Currently selected HTTP proxy type. Can be web or socks.
|
||||
LLHttpProxyType mProxyType;
|
||||
|
||||
// SOCKS 5 selected authentication method.
|
||||
LLSocks5AuthType mAuthMethodSelected;
|
||||
|
||||
// SOCKS 5 username
|
||||
std::string mSocksUsername;
|
||||
// SOCKS 5 password
|
||||
std::string mSocksPassword;
|
||||
|
||||
/*###########################################################################################
|
||||
END OF SHARED MEMBERS
|
||||
###########################################################################################*/
|
||||
};
|
||||
|
||||
#endif
|
||||
217
indra/llmessage/tests/llareslistener_test.cpp
Normal file
217
indra/llmessage/tests/llareslistener_test.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* @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");
|
||||
WrapLL_ERRS capture;
|
||||
LLSD request;
|
||||
request["op"] = "foo";
|
||||
std::string threw;
|
||||
try
|
||||
{
|
||||
LLEventPumps::instance().obtain("LLAres").post(request);
|
||||
}
|
||||
catch (const WrapLL_ERRS::FatalException& e)
|
||||
{
|
||||
threw = e.what();
|
||||
}
|
||||
ensure_contains("LLAresListener bad op", threw, "bad");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void object::test<3>()
|
||||
{
|
||||
set_test_name("bad rewriteURI request");
|
||||
WrapLL_ERRS capture;
|
||||
LLSD request;
|
||||
request["op"] = "rewriteURI";
|
||||
std::string threw;
|
||||
try
|
||||
{
|
||||
LLEventPumps::instance().obtain("LLAres").post(request);
|
||||
}
|
||||
catch (const WrapLL_ERRS::FatalException& e)
|
||||
{
|
||||
threw = e.what();
|
||||
}
|
||||
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");
|
||||
WrapLL_ERRS capture;
|
||||
LLSD request;
|
||||
request["op"] = "rewriteURI";
|
||||
request["reply"] = "nonexistent";
|
||||
std::string threw;
|
||||
try
|
||||
{
|
||||
LLEventPumps::instance().obtain("LLAres").post(request);
|
||||
}
|
||||
catch (const WrapLL_ERRS::FatalException& e)
|
||||
{
|
||||
threw = e.what();
|
||||
}
|
||||
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");
|
||||
WrapLL_ERRS capture;
|
||||
LLSD request;
|
||||
request["op"] = "rewriteURI";
|
||||
request["uri"] = "foo.bar.com";
|
||||
std::string threw;
|
||||
try
|
||||
{
|
||||
LLEventPumps::instance().obtain("LLAres").post(request);
|
||||
}
|
||||
catch (const WrapLL_ERRS::FatalException& e)
|
||||
{
|
||||
threw = e.what();
|
||||
}
|
||||
ensure_contains("LLAresListener bad req", threw, "missing");
|
||||
ensure_contains("LLAresListener bad req", threw, "reply");
|
||||
ensure_does_not_contain("LLAresListener bad req", threw, "uri");
|
||||
}
|
||||
}
|
||||
102
indra/llmessage/tests/llavatarnamecache_test.cpp
Normal file
102
indra/llmessage/tests/llavatarnamecache_test.cpp
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
251
indra/llmessage/tests/llhost_test.cpp
Normal file
251
indra/llmessage/tests/llhost_test.cpp
Normal file
@@ -0,0 +1,251 @@
|
||||
/**
|
||||
* @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 flaky, but we should figure out why...");
|
||||
// skip("setHostByName(\"google.com\"); getHostName() -> (e.g.) \"yx-in-f100.1e100.net\"");
|
||||
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());
|
||||
}
|
||||
}
|
||||
445
indra/llmessage/tests/llmime_test.cpp
Normal file
445
indra/llmessage/tests/llmime_test.cpp
Normal file
@@ -0,0 +1,445 @@
|
||||
/**
|
||||
* @file llmime_test.cpp
|
||||
* @author Phoenix
|
||||
* @date 2006-12-24
|
||||
* @brief BRIEF_DESC of llmime_test.cpp
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llsdserialize.h"
|
||||
|
||||
#include "../llmime.h"
|
||||
|
||||
#include "../test/lltut.h"
|
||||
|
||||
namespace tut
|
||||
{
|
||||
struct mime_index
|
||||
{
|
||||
};
|
||||
typedef test_group<mime_index> mime_index_t;
|
||||
typedef mime_index_t::object mime_index_object_t;
|
||||
tut::mime_index_t tut_mime_index("LLMime");
|
||||
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<1>()
|
||||
{
|
||||
LLMimeIndex mime;
|
||||
ensure("no headers", mime.headers().isUndefined());
|
||||
ensure_equals("invalid offset", mime.offset(), -1);
|
||||
ensure_equals("invalid content length", mime.contentLength(), -1);
|
||||
ensure("no content type", mime.contentType().empty());
|
||||
ensure("not multipart", !mime.isMultipart());
|
||||
ensure_equals("no attachments", mime.subPartCount(), 0);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<2>()
|
||||
{
|
||||
const S32 CONTENT_LENGTH = 6000;
|
||||
const S32 CONTENT_OFFSET = 100;
|
||||
const std::string CONTENT_TYPE = std::string("image/j2c");
|
||||
LLSD headers;
|
||||
headers["Content-Length"] = CONTENT_LENGTH;
|
||||
headers["Content-Type"] = CONTENT_TYPE;
|
||||
LLMimeIndex mime(headers, CONTENT_OFFSET);
|
||||
ensure("headers are map", mime.headers().isMap());
|
||||
ensure_equals("offset", mime.offset(), CONTENT_OFFSET);
|
||||
ensure_equals("content length", mime.contentLength(), CONTENT_LENGTH);
|
||||
ensure_equals("type is image/j2c", mime.contentType(), CONTENT_TYPE);
|
||||
ensure("not multipart", !mime.isMultipart());
|
||||
ensure_equals("no attachments", mime.subPartCount(), 0);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<3>()
|
||||
{
|
||||
const S32 MULTI_CONTENT_LENGTH = 8000;
|
||||
const S32 MULTI_CONTENT_OFFSET = 100;
|
||||
const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed");
|
||||
LLSD headers;
|
||||
headers["Content-Length"] = MULTI_CONTENT_LENGTH;
|
||||
headers["Content-Type"] = MULTI_CONTENT_TYPE;
|
||||
LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET);
|
||||
llinfos << "headers: " << LLSDOStreamer<LLSDNotationFormatter>(headers)
|
||||
<< llendl;
|
||||
|
||||
|
||||
const S32 META_CONTENT_LENGTH = 700;
|
||||
const S32 META_CONTENT_OFFSET = 69;
|
||||
const std::string META_CONTENT_TYPE = std::string(
|
||||
"text/llsd+xml");
|
||||
headers = LLSD::emptyMap();
|
||||
headers["Content-Length"] = META_CONTENT_LENGTH;
|
||||
headers["Content-Type"] = META_CONTENT_TYPE;
|
||||
LLMimeIndex meta(headers, META_CONTENT_OFFSET);
|
||||
mime.attachSubPart(meta);
|
||||
|
||||
const S32 IMAGE_CONTENT_LENGTH = 6000;
|
||||
const S32 IMAGE_CONTENT_OFFSET = 200;
|
||||
const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c");
|
||||
headers = LLSD::emptyMap();
|
||||
headers["Content-Length"] = IMAGE_CONTENT_LENGTH;
|
||||
headers["Content-Type"] = IMAGE_CONTENT_TYPE;
|
||||
LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET);
|
||||
mime.attachSubPart(image);
|
||||
|
||||
// make sure we have a valid multi-part
|
||||
ensure("is multipart", mime.isMultipart());
|
||||
ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET);
|
||||
ensure_equals(
|
||||
"multi content length",
|
||||
mime.contentLength(),
|
||||
MULTI_CONTENT_LENGTH);
|
||||
ensure_equals("two attachments", mime.subPartCount(), 2);
|
||||
|
||||
// make sure ranged gets do the right thing with out of bounds
|
||||
// sub-parts.
|
||||
LLMimeIndex invalid_child(mime.subPart(-1));
|
||||
ensure("no headers", invalid_child.headers().isUndefined());
|
||||
ensure_equals("invalid offset", invalid_child.offset(), -1);
|
||||
ensure_equals(
|
||||
"invalid content length", invalid_child.contentLength(), -1);
|
||||
ensure("no content type", invalid_child.contentType().empty());
|
||||
ensure("not multipart", !invalid_child.isMultipart());
|
||||
ensure_equals("no attachments", invalid_child.subPartCount(), 0);
|
||||
|
||||
invalid_child = mime.subPart(2);
|
||||
ensure("no headers", invalid_child.headers().isUndefined());
|
||||
ensure_equals("invalid offset", invalid_child.offset(), -1);
|
||||
ensure_equals(
|
||||
"invalid content length", invalid_child.contentLength(), -1);
|
||||
ensure("no content type", invalid_child.contentType().empty());
|
||||
ensure("not multipart", !invalid_child.isMultipart());
|
||||
ensure_equals("no attachments", invalid_child.subPartCount(), 0);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<4>()
|
||||
{
|
||||
const S32 MULTI_CONTENT_LENGTH = 8000;
|
||||
const S32 MULTI_CONTENT_OFFSET = 100;
|
||||
const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed");
|
||||
LLSD headers;
|
||||
headers["Content-Length"] = MULTI_CONTENT_LENGTH;
|
||||
headers["Content-Type"] = MULTI_CONTENT_TYPE;
|
||||
LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET);
|
||||
|
||||
const S32 META_CONTENT_LENGTH = 700;
|
||||
const S32 META_CONTENT_OFFSET = 69;
|
||||
const std::string META_CONTENT_TYPE = std::string(
|
||||
"application/llsd+xml");
|
||||
headers = LLSD::emptyMap();
|
||||
headers["Content-Length"] = META_CONTENT_LENGTH;
|
||||
headers["Content-Type"] = META_CONTENT_TYPE;
|
||||
LLMimeIndex meta(headers, META_CONTENT_OFFSET);
|
||||
mime.attachSubPart(meta);
|
||||
|
||||
const S32 IMAGE_CONTENT_LENGTH = 6000;
|
||||
const S32 IMAGE_CONTENT_OFFSET = 200;
|
||||
const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c");
|
||||
headers = LLSD::emptyMap();
|
||||
headers["Content-Length"] = IMAGE_CONTENT_LENGTH;
|
||||
headers["Content-Type"] = IMAGE_CONTENT_TYPE;
|
||||
LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET);
|
||||
mime.attachSubPart(image);
|
||||
|
||||
// check what we have
|
||||
ensure("is multipart", mime.isMultipart());
|
||||
ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET);
|
||||
ensure_equals(
|
||||
"multi content length",
|
||||
mime.contentLength(),
|
||||
MULTI_CONTENT_LENGTH);
|
||||
ensure_equals("two attachments", mime.subPartCount(), 2);
|
||||
|
||||
LLMimeIndex actual_meta = mime.subPart(0);
|
||||
ensure_equals(
|
||||
"meta type", actual_meta.contentType(), META_CONTENT_TYPE);
|
||||
ensure_equals(
|
||||
"meta offset", actual_meta.offset(), META_CONTENT_OFFSET);
|
||||
ensure_equals(
|
||||
"meta content length",
|
||||
actual_meta.contentLength(),
|
||||
META_CONTENT_LENGTH);
|
||||
|
||||
LLMimeIndex actual_image = mime.subPart(1);
|
||||
ensure_equals(
|
||||
"image type", actual_image.contentType(), IMAGE_CONTENT_TYPE);
|
||||
ensure_equals(
|
||||
"image offset", actual_image.offset(), IMAGE_CONTENT_OFFSET);
|
||||
ensure_equals(
|
||||
"image content length",
|
||||
actual_image.contentLength(),
|
||||
IMAGE_CONTENT_LENGTH);
|
||||
}
|
||||
|
||||
/*
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<5>()
|
||||
{
|
||||
}
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<6>()
|
||||
{
|
||||
}
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<7>()
|
||||
{
|
||||
}
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<8>()
|
||||
{
|
||||
}
|
||||
template<> template<>
|
||||
void mime_index_object_t::test<>()
|
||||
{
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
namespace tut
|
||||
{
|
||||
struct mime_parse
|
||||
{
|
||||
};
|
||||
typedef test_group<mime_parse> mime_parse_t;
|
||||
typedef mime_parse_t::object mime_parse_object_t;
|
||||
tut::mime_parse_t tut_mime_parse("LLMimeParse");
|
||||
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<1>()
|
||||
{
|
||||
// parse one mime object
|
||||
const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n");
|
||||
std::stringstream istr;
|
||||
istr.str(SERIALIZED_MIME);
|
||||
LLMimeIndex mime;
|
||||
LLMimeParser parser;
|
||||
bool ok = parser.parseIndex(istr, mime);
|
||||
ensure("Parse successful.", ok);
|
||||
ensure_equals("content type", mime.contentType(), "text/plain");
|
||||
ensure_equals("content length", mime.contentLength(), 200);
|
||||
ensure_equals("offset", mime.offset(), 49);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<2>()
|
||||
{
|
||||
// make sure we only parse one.
|
||||
const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\nContent-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\n");
|
||||
std::stringstream istr;
|
||||
istr.str(SERIALIZED_MIME);
|
||||
LLMimeIndex mime;
|
||||
LLMimeParser parser;
|
||||
bool ok = parser.parseIndex(istr, mime);
|
||||
ensure("Parse successful.", ok);
|
||||
ensure("not multipart.", !mime.isMultipart());
|
||||
ensure_equals("content type", mime.contentType(), "text/plain");
|
||||
ensure_equals("content length", mime.contentLength(), 200);
|
||||
ensure_equals("offset", mime.offset(), 49);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<3>()
|
||||
{
|
||||
// test multi-part and lack of content length for some of it.
|
||||
/*
|
||||
Content-Type: multipart/mixed; boundary="segment"rnContent-Length: 148rnrn--segmentrnContent-Type: text/plainrnrnsome datarnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn
|
||||
*/
|
||||
const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=\"segment\"\r\nContent-Length: 150\r\n\r\n--segment\r\nContent-Type: text/plain\r\n\r\nsome data\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
||||
std::stringstream istr;
|
||||
istr.str(SERIALIZED_MIME);
|
||||
LLMimeIndex mime;
|
||||
LLMimeParser parser;
|
||||
bool ok = parser.parseIndex(istr, mime);
|
||||
ensure("Parse successful.", ok);
|
||||
ensure("is multipart.", mime.isMultipart());
|
||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
||||
ensure_equals("content length", mime.contentLength(), 150);
|
||||
ensure_equals("data offset for multipart", mime.offset(), 74);
|
||||
|
||||
LLMimeIndex mime_plain(mime.subPart(0));
|
||||
ensure_equals(
|
||||
"first part type",
|
||||
mime_plain.contentType(),
|
||||
"text/plain");
|
||||
ensure_equals(
|
||||
"first part content length not known.",
|
||||
mime_plain.contentLength(),
|
||||
-1);
|
||||
ensure_equals("first part offset", mime_plain.offset(), 113);
|
||||
|
||||
LLMimeIndex mime_xml(mime.subPart(1));
|
||||
ensure_equals(
|
||||
"second part type",
|
||||
mime_xml.contentType(),
|
||||
"text/xml; charset=UTF-8");
|
||||
ensure_equals(
|
||||
"second part content length",
|
||||
mime_xml.contentLength(),
|
||||
22);
|
||||
ensure_equals("second part offset", mime_xml.offset(), 198);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<4>()
|
||||
{
|
||||
// test multi-part, unquoted separator, and premature eof conditions
|
||||
/*
|
||||
Content-Type: multipart/mixed; boundary=segmentrnContent-Length: 220rnrn--segmentrnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn */
|
||||
const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
||||
std::stringstream istr;
|
||||
istr.str(SERIALIZED_MIME);
|
||||
LLMimeIndex mime;
|
||||
LLMimeParser parser;
|
||||
bool ok = parser.parseIndex(istr, mime);
|
||||
ensure("Parse successful.", ok);
|
||||
ensure("is multipart.", mime.isMultipart());
|
||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
||||
ensure_equals("content length", mime.contentLength(), 220);
|
||||
ensure_equals("data offset for multipart", mime.offset(), 72);
|
||||
|
||||
LLMimeIndex mime_plain(mime.subPart(0));
|
||||
ensure_equals(
|
||||
"first part type",
|
||||
mime_plain.contentType(),
|
||||
"text/plain");
|
||||
ensure_equals(
|
||||
"first part content length",
|
||||
mime_plain.contentLength(),
|
||||
55);
|
||||
ensure_equals("first part offset", mime_plain.offset(), 131);
|
||||
|
||||
LLMimeIndex mime_xml(mime.subPart(1));
|
||||
ensure_equals(
|
||||
"second part type",
|
||||
mime_xml.contentType(),
|
||||
"text/xml; charset=UTF-8");
|
||||
ensure_equals(
|
||||
"second part content length",
|
||||
mime_xml.contentLength(),
|
||||
22);
|
||||
ensure_equals("second part offset", mime_xml.offset(), 262);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<5>()
|
||||
{
|
||||
// test multi-part with multiple params
|
||||
const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment; comment=\"testing multiple params.\"\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
||||
std::stringstream istr;
|
||||
istr.str(SERIALIZED_MIME);
|
||||
LLMimeIndex mime;
|
||||
LLMimeParser parser;
|
||||
bool ok = parser.parseIndex(istr, mime);
|
||||
ensure("Parse successful.", ok);
|
||||
ensure("is multipart.", mime.isMultipart());
|
||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
||||
ensure_equals("content length", mime.contentLength(), 220);
|
||||
|
||||
LLMimeIndex mime_plain(mime.subPart(0));
|
||||
ensure_equals(
|
||||
"first part type",
|
||||
mime_plain.contentType(),
|
||||
"text/plain");
|
||||
ensure_equals(
|
||||
"first part content length",
|
||||
mime_plain.contentLength(),
|
||||
55);
|
||||
|
||||
LLMimeIndex mime_xml(mime.subPart(1));
|
||||
ensure_equals(
|
||||
"second part type",
|
||||
mime_xml.contentType(),
|
||||
"text/xml; charset=UTF-8");
|
||||
ensure_equals(
|
||||
"second part content length",
|
||||
mime_xml.contentLength(),
|
||||
22);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<6>()
|
||||
{
|
||||
// test multi-part with no specified boundary and eof
|
||||
/*
|
||||
Content-Type: multipart/relatedrnContent-Length: 220rnrn--rnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--rnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn
|
||||
*/
|
||||
const std::string SERIALIZED_MIME("Content-Type: multipart/related\r\nContent-Length: 500\r\n\r\n--\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
||||
std::stringstream istr;
|
||||
istr.str(SERIALIZED_MIME);
|
||||
LLMimeIndex mime;
|
||||
LLMimeParser parser;
|
||||
bool ok = parser.parseIndex(istr, mime);
|
||||
ensure("Parse successful.", ok);
|
||||
ensure("is multipart.", mime.isMultipart());
|
||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
||||
ensure_equals("content length", mime.contentLength(), 500);
|
||||
ensure_equals("data offset for multipart", mime.offset(), 56);
|
||||
|
||||
LLMimeIndex mime_plain(mime.subPart(0));
|
||||
ensure_equals(
|
||||
"first part type",
|
||||
mime_plain.contentType(),
|
||||
"text/plain");
|
||||
ensure_equals(
|
||||
"first part content length",
|
||||
mime_plain.contentLength(),
|
||||
55);
|
||||
ensure_equals("first part offset", mime_plain.offset(), 108);
|
||||
|
||||
LLMimeIndex mime_xml(mime.subPart(1));
|
||||
ensure_equals(
|
||||
"second part type",
|
||||
mime_xml.contentType(),
|
||||
"text/xml; charset=UTF-8");
|
||||
ensure_equals(
|
||||
"second part content length",
|
||||
mime_xml.contentLength(),
|
||||
22);
|
||||
ensure_equals("second part offset", mime_xml.offset(), 232);
|
||||
}
|
||||
|
||||
/*
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<>()
|
||||
{
|
||||
}
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<>()
|
||||
{
|
||||
}
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<>()
|
||||
{
|
||||
}
|
||||
template<> template<>
|
||||
void mime_parse_object_t::test<>()
|
||||
{
|
||||
}
|
||||
*/
|
||||
}
|
||||
66
indra/llmessage/tests/llmockhttpclient.h
Normal file
66
indra/llmessage/tests/llmockhttpclient.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @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_LLMOCKHTTPCLIENT_H
|
||||
#define LL_LLMOCKHTTPCLIENT_H
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llhttpclientinterface.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
class LLMockHTTPClient : public LLHTTPClientInterface
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD2(get, void(const std::string& url, LLCurl::ResponderPtr responder));
|
||||
MOCK_METHOD3(get, void(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers));
|
||||
MOCK_METHOD3(put, void(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder));
|
||||
};
|
||||
|
||||
// A helper to match responder types
|
||||
template<typename T>
|
||||
struct ResponderType
|
||||
{
|
||||
bool operator()(LLCurl::ResponderPtr ptr) const
|
||||
{
|
||||
T* p = dynamic_cast<T*>(ptr.get());
|
||||
return p != NULL;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const LLSD& l, const LLSD& r)
|
||||
{
|
||||
std::ostringstream ls, rs;
|
||||
ls << l;
|
||||
rs << r;
|
||||
return ls.str() == rs.str();
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif //LL_LLMOCKHTTPCLIENT_H
|
||||
|
||||
406
indra/llmessage/tests/llnamevalue_test.cpp
Normal file
406
indra/llmessage/tests/llnamevalue_test.cpp
Normal 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
|
||||
}
|
||||
}
|
||||
216
indra/llmessage/tests/llpartdata_test.cpp
Normal file
216
indra/llmessage/tests/llpartdata_test.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* @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
|
||||
{
|
||||
|
||||
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>()
|
||||
{
|
||||
LLPartData llpdata,llpdata1;
|
||||
U8 pkbuf[128];
|
||||
|
||||
llpdata.setFlags(LLPartData::LL_PART_INTERP_COLOR_MASK | LLPartData::LL_PART_INTERP_SCALE_MASK |
|
||||
LLPartData::LL_PART_BOUNCE_MASK | LLPartData::LL_PART_WIND_MASK | LLPartData::LL_PART_FOLLOW_SRC_MASK |
|
||||
LLPartData::LL_PART_FOLLOW_VELOCITY_MASK | LLPartData::LL_PART_TARGET_POS_MASK | LLPartData::LL_PART_TARGET_LINEAR_MASK |
|
||||
LLPartData::LL_PART_EMISSIVE_MASK | LLPartData::LL_PART_BEAM_MASK | LLPartData::LL_PART_DEAD_MASK);
|
||||
|
||||
llpdata.setMaxAge(29.3f);
|
||||
|
||||
LLVector3 llvec1(1.0f, .5f, .25f);
|
||||
llpdata.setStartColor(llvec1);
|
||||
llpdata.setStartAlpha(.7f);
|
||||
|
||||
LLVector3 llvec2(.2f, .3f, 1.0f);
|
||||
llpdata.setEndColor(llvec2);
|
||||
llpdata.setEndAlpha(1.0f);
|
||||
|
||||
llpdata.setStartScale(3.23f, 4.0f);
|
||||
llpdata.setEndScale(2.4678f, 1.0f);
|
||||
|
||||
LLDataPackerBinaryBuffer dp((U8*)pkbuf, 128);
|
||||
llpdata.pack(dp);
|
||||
|
||||
S32 cur_size = dp.getCurrentSize();
|
||||
|
||||
LLDataPackerBinaryBuffer dp1((U8*)pkbuf, cur_size);
|
||||
llpdata1.unpack(dp1);
|
||||
|
||||
ensure("1.mFlags values are different after unpacking", llpdata1.mFlags == llpdata.mFlags);
|
||||
ensure_approximately_equals("2.mMaxAge values are different after unpacking", llpdata1.mMaxAge, llpdata.mMaxAge, 8);
|
||||
|
||||
ensure_approximately_equals("3.mStartColor[0] values are different after unpacking", llpdata1.mStartColor.mV[0], llpdata.mStartColor.mV[0], 8);
|
||||
ensure_approximately_equals("4.mStartColor[1] values are different after unpacking", llpdata1.mStartColor.mV[1], llpdata.mStartColor.mV[1], 8);
|
||||
ensure_approximately_equals("5.mStartColor[2] values are different after unpacking", llpdata1.mStartColor.mV[2], llpdata.mStartColor.mV[2], 8);
|
||||
ensure_approximately_equals("6.mStartColor[3] values are different after unpacking", llpdata1.mStartColor.mV[3], llpdata.mStartColor.mV[3], 8);
|
||||
|
||||
ensure_approximately_equals("7.mEndColor[0] values are different after unpacking", llpdata1.mEndColor.mV[0], llpdata.mEndColor.mV[0], 8);
|
||||
ensure_approximately_equals("8.mEndColor[1] values are different after unpacking", llpdata1.mEndColor.mV[1], llpdata.mEndColor.mV[1], 8);
|
||||
ensure_approximately_equals("9.mEndColor[2] values are different after unpacking", llpdata1.mEndColor.mV[2], llpdata.mEndColor.mV[2], 8);
|
||||
ensure_approximately_equals("10.mEndColor[2] values are different after unpacking", llpdata1.mEndColor.mV[3], llpdata.mEndColor.mV[3], 8);
|
||||
|
||||
ensure_approximately_equals("11.mStartScale[0] values are different after unpacking", llpdata1.mStartScale.mV[0], llpdata.mStartScale.mV[0], 5);
|
||||
ensure_approximately_equals("12.mStartScale[1] values are different after unpacking", llpdata1.mStartScale.mV[1], llpdata.mStartScale.mV[1], 5);
|
||||
|
||||
ensure_approximately_equals("13.mEndScale[0] values are different after unpacking", llpdata1.mEndScale.mV[0], llpdata.mEndScale.mV[0], 5);
|
||||
ensure_approximately_equals("14.mEndScale[1] values are different after unpacking", llpdata1.mEndScale.mV[1], llpdata.mEndScale.mV[1], 5);
|
||||
}
|
||||
|
||||
|
||||
template<> template<>
|
||||
void partdata_test_object_t::test<2>()
|
||||
{
|
||||
LLPartData llpdata,llpdata1;
|
||||
|
||||
llpdata.setFlags(LLPartData::LL_PART_INTERP_COLOR_MASK | LLPartData::LL_PART_INTERP_SCALE_MASK |
|
||||
LLPartData::LL_PART_BOUNCE_MASK | LLPartData::LL_PART_WIND_MASK | LLPartData::LL_PART_FOLLOW_SRC_MASK |
|
||||
LLPartData::LL_PART_FOLLOW_VELOCITY_MASK | LLPartData::LL_PART_TARGET_POS_MASK | LLPartData::LL_PART_TARGET_LINEAR_MASK |
|
||||
LLPartData::LL_PART_EMISSIVE_MASK | LLPartData::LL_PART_BEAM_MASK | LLPartData::LL_PART_DEAD_MASK);
|
||||
|
||||
llpdata.setMaxAge(29.3f);
|
||||
|
||||
LLVector3 llvec1(1.0f, .5f, .25f);
|
||||
llpdata.setStartColor(llvec1);
|
||||
llpdata.setStartAlpha(.7f);
|
||||
|
||||
LLVector3 llvec2(.2f, .3f, 1.0f);
|
||||
llpdata.setEndColor(llvec2);
|
||||
llpdata.setEndAlpha(1.0f);
|
||||
|
||||
llpdata.setStartScale(3.23f, 4.0f);
|
||||
llpdata.setEndScale(2.4678f, 1.0f);
|
||||
|
||||
LLSD llsd = llpdata.asLLSD();
|
||||
|
||||
llpdata1.fromLLSD(llsd);
|
||||
|
||||
ensure("1.mFlags values are different after unpacking", llpdata1.mFlags == llpdata.mFlags);
|
||||
ensure_approximately_equals("2.mMaxAge values are different after unpacking", llpdata1.mMaxAge, llpdata.mMaxAge, 8);
|
||||
|
||||
ensure_approximately_equals("3.mStartColor[0] values are different after unpacking", llpdata1.mStartColor.mV[0], llpdata.mStartColor.mV[0], 8);
|
||||
ensure_approximately_equals("4.mStartColor[1] values are different after unpacking", llpdata1.mStartColor.mV[1], llpdata.mStartColor.mV[1], 8);
|
||||
ensure_approximately_equals("5.mStartColor[2] values are different after unpacking", llpdata1.mStartColor.mV[2], llpdata.mStartColor.mV[2], 8);
|
||||
ensure_approximately_equals("6.mStartColor[3] values are different after unpacking", llpdata1.mStartColor.mV[3], llpdata.mStartColor.mV[3], 8);
|
||||
|
||||
ensure_approximately_equals("7.mEndColor[0] values are different after unpacking", llpdata1.mEndColor.mV[0], llpdata.mEndColor.mV[0], 8);
|
||||
ensure_approximately_equals("8.mEndColor[1] values are different after unpacking", llpdata1.mEndColor.mV[1], llpdata.mEndColor.mV[1], 8);
|
||||
ensure_approximately_equals("9.mEndColor[2] values are different after unpacking", llpdata1.mEndColor.mV[2], llpdata.mEndColor.mV[2], 8);
|
||||
ensure_approximately_equals("10.mEndColor[2] values are different after unpacking", llpdata1.mEndColor.mV[3], llpdata.mEndColor.mV[3], 8);
|
||||
|
||||
ensure_approximately_equals("11.mStartScale[0] values are different after unpacking", llpdata1.mStartScale.mV[0], llpdata.mStartScale.mV[0], 5);
|
||||
ensure_approximately_equals("12.mStartScale[1] values are different after unpacking", llpdata1.mStartScale.mV[1], llpdata.mStartScale.mV[1], 5);
|
||||
|
||||
ensure_approximately_equals("13.mEndScale[0] values are different after unpacking", llpdata1.mEndScale.mV[0], llpdata.mEndScale.mV[0], 5);
|
||||
ensure_approximately_equals("14.mEndScale[1] values are different after unpacking", llpdata1.mEndScale.mV[1], llpdata.mEndScale.mV[1], 5);
|
||||
}
|
||||
|
||||
|
||||
//*********llpartsysdata***********
|
||||
|
||||
template<> template<>
|
||||
void partdata_test_object_t::test<3>()
|
||||
{
|
||||
LLPartSysData llpsysdata, llpsysdata1;
|
||||
U8 pkbuf[256];
|
||||
llpsysdata.setBurstSpeedMin(33.33f);
|
||||
ensure("1.mBurstSpeedMin coudnt be set", 33.33f == llpsysdata.mBurstSpeedMin);
|
||||
|
||||
llpsysdata.setBurstSpeedMax(44.44f);
|
||||
ensure("2.mBurstSpeedMax coudnt be set", 44.44f == llpsysdata.mBurstSpeedMax);
|
||||
|
||||
llpsysdata.setBurstRadius(45.55f);
|
||||
ensure("3.mBurstRadius coudnt be set", 45.55f == llpsysdata.mBurstRadius);
|
||||
|
||||
LLVector3 llvec(44.44f, 111.11f, -40.4f);
|
||||
llpsysdata.setPartAccel(llvec);
|
||||
|
||||
llpsysdata.mCRC = 0xFFFFFFFF;
|
||||
llpsysdata.mFlags = 0x20;
|
||||
|
||||
llpsysdata.mPattern = LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE_EMPTY;
|
||||
|
||||
llpsysdata.mMaxAge = 99.99f;
|
||||
llpsysdata.mStartAge = 18.5f;
|
||||
llpsysdata.mInnerAngle = 4.234f;
|
||||
llpsysdata.mOuterAngle = 7.123f;
|
||||
llpsysdata.mBurstRate = 245.53f;
|
||||
llpsysdata.mBurstPartCount = 0xFF;
|
||||
llpsysdata.mAngularVelocity = llvec;
|
||||
|
||||
llpsysdata.mPartImageID.generate();
|
||||
llpsysdata.mTargetUUID.generate();
|
||||
|
||||
LLDataPackerBinaryBuffer dp((U8*)pkbuf, 256);
|
||||
llpsysdata.pack(dp);
|
||||
S32 cur_size = dp.getCurrentSize();
|
||||
LLDataPackerBinaryBuffer dp1((U8*)pkbuf, cur_size);
|
||||
llpsysdata1.unpack(dp1);
|
||||
|
||||
ensure("1.mCRC's not equal", llpsysdata.mCRC == llpsysdata1.mCRC);
|
||||
ensure("2.mFlags's not equal", llpsysdata.mFlags == llpsysdata1.mFlags);
|
||||
ensure("3.mPattern's not equal", llpsysdata.mPattern == llpsysdata1.mPattern);
|
||||
ensure_approximately_equals("4.mMaxAge's not equal", llpsysdata.mMaxAge , llpsysdata1.mMaxAge, 8);
|
||||
ensure_approximately_equals("5.mStartAge's not equal", llpsysdata.mStartAge, llpsysdata1.mStartAge, 8);
|
||||
ensure_approximately_equals("6.mOuterAngle's not equal", llpsysdata.mOuterAngle, llpsysdata1.mOuterAngle, 5);
|
||||
ensure_approximately_equals("7.mInnerAngles's not equal", llpsysdata.mInnerAngle, llpsysdata1.mInnerAngle, 5);
|
||||
ensure_approximately_equals("8.mBurstRate's not equal", llpsysdata.mBurstRate, llpsysdata1.mBurstRate, 8);
|
||||
ensure("9.mBurstPartCount's not equal", llpsysdata.mBurstPartCount == llpsysdata1.mBurstPartCount);
|
||||
|
||||
ensure_approximately_equals("10.mBurstSpeedMin's not equal", llpsysdata.mBurstSpeedMin, llpsysdata1.mBurstSpeedMin, 8);
|
||||
ensure_approximately_equals("11.mBurstSpeedMax's not equal", llpsysdata.mBurstSpeedMax, llpsysdata1.mBurstSpeedMax, 8);
|
||||
|
||||
ensure_approximately_equals("12.mAngularVelocity's not equal", llpsysdata.mAngularVelocity.mV[0], llpsysdata1.mAngularVelocity.mV[0], 7);
|
||||
ensure_approximately_equals("13.mAngularVelocity's not equal", llpsysdata.mAngularVelocity.mV[1], llpsysdata1.mAngularVelocity.mV[1], 7);
|
||||
ensure_approximately_equals("14.mAngularVelocity's not equal", llpsysdata.mAngularVelocity.mV[2], llpsysdata1.mAngularVelocity.mV[2], 7);
|
||||
|
||||
ensure_approximately_equals("15.mPartAccel's not equal", llpsysdata.mPartAccel.mV[0], llpsysdata1.mPartAccel.mV[0], 7);
|
||||
ensure_approximately_equals("16.mPartAccel's not equal", llpsysdata.mPartAccel.mV[1], llpsysdata1.mPartAccel.mV[1], 7);
|
||||
ensure_approximately_equals("17.mPartAccel's not equal", llpsysdata.mPartAccel.mV[2], llpsysdata1.mPartAccel.mV[2], 7);
|
||||
|
||||
ensure("18.mPartImageID's not equal", llpsysdata.mPartImageID == llpsysdata1.mPartImageID);
|
||||
ensure("19.mTargetUUID's not equal", llpsysdata.mTargetUUID == llpsysdata1.mTargetUUID);
|
||||
ensure_approximately_equals("20.mBurstRadius's not equal", llpsysdata.mBurstRadius, llpsysdata1.mBurstRadius, 8);
|
||||
}
|
||||
}
|
||||
108
indra/llmessage/tests/llregionpresenceverifier_test.cpp
Normal file
108
indra/llmessage/tests/llregionpresenceverifier_test.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @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 "linden_common.h"
|
||||
|
||||
#include "../test/lltut.h"
|
||||
#include "llregionpresenceverifier.h"
|
||||
#include "llcurl_stub.cpp"
|
||||
#include "llhost.cpp"
|
||||
#include "net.cpp"
|
||||
#include "lltesthttpclientadapter.cpp"
|
||||
|
||||
class LLTestResponse : public LLRegionPresenceVerifier::Response
|
||||
{
|
||||
public:
|
||||
|
||||
virtual bool checkValidity(const LLSD& content) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void onRegionVerified(const LLSD& region_details)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void onRegionVerificationFailed()
|
||||
{
|
||||
}
|
||||
|
||||
virtual LLHTTPClientInterface& getHttpClient()
|
||||
{
|
||||
return mHttpInterface;
|
||||
}
|
||||
|
||||
LLTestHTTPClientAdapter mHttpInterface;
|
||||
};
|
||||
|
||||
namespace tut
|
||||
{
|
||||
struct LLRegionPresenceVerifierData
|
||||
{
|
||||
LLRegionPresenceVerifierData() :
|
||||
mResponse(new LLTestResponse()),
|
||||
mResponder("", LLRegionPresenceVerifier::ResponsePtr(mResponse),
|
||||
LLSD(), 3)
|
||||
{
|
||||
}
|
||||
|
||||
LLTestResponse* mResponse;
|
||||
LLRegionPresenceVerifier::VerifiedDestinationResponder mResponder;
|
||||
};
|
||||
|
||||
typedef test_group<LLRegionPresenceVerifierData> factory;
|
||||
typedef factory::object object;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
tut::factory tf("LLRegionPresenceVerifier");
|
||||
}
|
||||
|
||||
namespace tut
|
||||
{
|
||||
// Test that VerifiedDestinationResponder does retry
|
||||
// on error when shouldRetry returns true.
|
||||
template<> template<>
|
||||
void object::test<1>()
|
||||
{
|
||||
mResponder.error(500, "Internal server error");
|
||||
ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 1);
|
||||
}
|
||||
|
||||
// Test that VerifiedDestinationResponder only retries
|
||||
// on error until shouldRetry returns false.
|
||||
template<> template<>
|
||||
void object::test<2>()
|
||||
{
|
||||
mResponder.error(500, "Internal server error");
|
||||
mResponder.error(500, "Internal server error");
|
||||
mResponder.error(500, "Internal server error");
|
||||
mResponder.error(500, "Internal server error");
|
||||
ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 3);
|
||||
}
|
||||
}
|
||||
|
||||
158
indra/llmessage/tests/llsdmessage_test.cpp
Normal file
158
indra/llmessage/tests/llsdmessage_test.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* @file llsdmessage_test.cpp
|
||||
* @author Nat Goodspeed
|
||||
* @date 2008-12-22
|
||||
* @brief Test of llsdmessage.h
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#if LL_WINDOWS
|
||||
#pragma warning (disable : 4675) // "resolved by ADL" -- just as I want!
|
||||
#endif
|
||||
|
||||
// Precompiled header
|
||||
#include "linden_common.h"
|
||||
// associated header
|
||||
#include "llsdmessage.h"
|
||||
// STL headers
|
||||
#include <iostream>
|
||||
// std headers
|
||||
#include <stdexcept>
|
||||
#include <typeinfo>
|
||||
// external library headers
|
||||
// other Linden headers
|
||||
#include "../test/lltut.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llevents.h"
|
||||
#include "stringize.h"
|
||||
#include "llhost.h"
|
||||
#include "tests/networkio.h"
|
||||
#include "tests/commtest.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* TUT
|
||||
*****************************************************************************/
|
||||
namespace tut
|
||||
{
|
||||
struct llsdmessage_data: public commtest_data
|
||||
{
|
||||
LLEventPump& httpPump;
|
||||
|
||||
llsdmessage_data():
|
||||
httpPump(pumps.obtain("LLHTTPClient"))
|
||||
{
|
||||
LLCurl::initClass();
|
||||
LLSDMessage::link();
|
||||
}
|
||||
};
|
||||
typedef test_group<llsdmessage_data> llsdmessage_group;
|
||||
typedef llsdmessage_group::object llsdmessage_object;
|
||||
llsdmessage_group llsdmgr("llsdmessage");
|
||||
|
||||
template<> template<>
|
||||
void llsdmessage_object::test<1>()
|
||||
{
|
||||
bool threw = false;
|
||||
// This should fail...
|
||||
try
|
||||
{
|
||||
LLSDMessage localListener;
|
||||
}
|
||||
catch (const LLEventPump::DupPumpName&)
|
||||
{
|
||||
threw = true;
|
||||
}
|
||||
catch (const std::runtime_error& ex)
|
||||
{
|
||||
// This clause is because on Linux, on the viewer side, for this
|
||||
// one test program (though not others!), the
|
||||
// LLEventPump::DupPumpName exception isn't caught by the clause
|
||||
// above. Warn the user...
|
||||
std::cerr << "Failed to catch " << typeid(ex).name() << std::endl;
|
||||
// But if the expected exception was thrown, allow the test to
|
||||
// succeed anyway. Not sure how else to handle this odd case.
|
||||
if (std::string(typeid(ex).name()) == typeid(LLEventPump::DupPumpName).name())
|
||||
{
|
||||
threw = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We don't even recognize this exception. Let it propagate
|
||||
// out to TUT to fail the test.
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "Utterly failed to catch expected exception!" << std::endl;
|
||||
// This case is full of fail. We HAVE to address it.
|
||||
throw;
|
||||
}
|
||||
ensure("second LLSDMessage should throw", threw);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void llsdmessage_object::test<2>()
|
||||
{
|
||||
LLSD request, body;
|
||||
body["data"] = "yes";
|
||||
request["payload"] = body;
|
||||
request["reply"] = replyPump.getName();
|
||||
request["error"] = errorPump.getName();
|
||||
bool threw = false;
|
||||
try
|
||||
{
|
||||
httpPump.post(request);
|
||||
}
|
||||
catch (const LLSDMessage::ArgError&)
|
||||
{
|
||||
threw = true;
|
||||
}
|
||||
ensure("missing URL", threw);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void llsdmessage_object::test<3>()
|
||||
{
|
||||
LLSD request, body;
|
||||
body["data"] = "yes";
|
||||
request["url"] = server + "got-message";
|
||||
request["payload"] = body;
|
||||
request["reply"] = replyPump.getName();
|
||||
request["error"] = errorPump.getName();
|
||||
httpPump.post(request);
|
||||
ensure("got response", netio.pump());
|
||||
ensure("success response", success);
|
||||
ensure_equals(result.asString(), "success");
|
||||
|
||||
body["status"] = 499;
|
||||
body["reason"] = "custom error message";
|
||||
request["url"] = server + "fail";
|
||||
request["payload"] = body;
|
||||
httpPump.post(request);
|
||||
ensure("got response", netio.pump());
|
||||
ensure("failure response", ! success);
|
||||
ensure_equals(result["status"].asInteger(), body["status"].asInteger());
|
||||
ensure_equals(result["reason"].asString(), body["reason"].asString());
|
||||
}
|
||||
} // namespace tut
|
||||
58
indra/llmessage/tests/llxfer_file_test.cpp
Normal file
58
indra/llmessage/tests/llxfer_file_test.cpp
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
262
indra/llmessage/tests/testrunner.py
Normal file
262
indra/llmessage/tests/testrunner.py
Normal file
@@ -0,0 +1,262 @@
|
||||
#!/usr/bin/env python
|
||||
"""\
|
||||
@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$
|
||||
"""
|
||||
|
||||
from __future__ import with_statement
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import errno
|
||||
import socket
|
||||
|
||||
VERBOSE = os.environ.get("INTEGRATION_TEST_VERBOSE", "1") # default to verbose
|
||||
# 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
|
||||
|
||||
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 = portiter.next()
|
||||
|
||||
while True:
|
||||
try:
|
||||
# If this value of port works, return as promised.
|
||||
value = expr(port)
|
||||
|
||||
except socket.error, 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 = portiter.next()
|
||||
except StopIteration:
|
||||
raise type, value, 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, err:
|
||||
debug("*** freeport() raising %s: %s", err.__class__.__name__, err)
|
||||
raise
|
||||
|
||||
def run(*args, **kwds):
|
||||
"""All positional arguments collectively form a command line, executed as
|
||||
a synchronous child process.
|
||||
In addition, pass server=new_thread_instance as an explicit keyword (to
|
||||
differentiate it from an additional command-line argument).
|
||||
new_thread_instance should be an instantiated but not yet started Thread
|
||||
subclass instance, e.g.:
|
||||
run("python", "-c", 'print "Hello, world!"', server=TestHTTPServer(name="httpd"))
|
||||
"""
|
||||
# If there's no server= keyword arg, don't start a server thread: simply
|
||||
# run a child process.
|
||||
try:
|
||||
thread = kwds.pop("server")
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
# Start server thread. Note that this and all other comm server
|
||||
# threads should be daemon threads: we'll let them run "forever,"
|
||||
# confident that the whole process will terminate when the main thread
|
||||
# terminates, which will be when the child process terminates.
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
# choice of os.spawnv():
|
||||
# - [v vs. l] pass a list of args vs. individual arguments,
|
||||
# - [no p] don't use the PATH because we specifically want to invoke the
|
||||
# executable passed as our first arg,
|
||||
# - [no e] child should inherit this process's environment.
|
||||
debug("Running %s...", " ".join(args))
|
||||
rc = os.spawnv(os.P_WAIT, args[0], args)
|
||||
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, 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(xrange(5))
|
||||
with exc(socket.error, errno.EADDRINUSE):
|
||||
freeport(ports, lambda port: raiser(inuse))
|
||||
# did we entirely exhaust 'ports'?
|
||||
with exc(StopIteration):
|
||||
ports.next()
|
||||
|
||||
ports = iter(xrange(2))
|
||||
# Any exception but EADDRINUSE should quit immediately
|
||||
with exc(SomeError):
|
||||
freeport(ports, lambda port: raiser(SomeError()))
|
||||
assert_equals(ports.next(), 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(xrange(7777, 7780), newbind)
|
||||
assert_equals(port0, 7777)
|
||||
bound1, port1 = freeport(xrange(7777, 7780), newbind)
|
||||
assert_equals(port1, 7778)
|
||||
bound2, port2 = freeport(xrange(7777, 7780), newbind)
|
||||
assert_equals(port2, 7779)
|
||||
with exc(socket.error, errno.EADDRINUSE):
|
||||
bound3, port3 = freeport(xrange(7777, 7780), newbind)
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_freeport()
|
||||
Reference in New Issue
Block a user