summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2011-07-14 14:00:12 -0400
committerNat Goodspeed <nat@lindenlab.com>2011-07-14 14:00:12 -0400
commit0ab0efc3270f44da3d8b3a9db2845eeddde44dc6 (patch)
treec01efcb9b1c55b677478427b032dbcad2711d535 /indra/llcommon
parentec780a733f46e2fc436ca5d492f42ab4e3e8b516 (diff)
Work around broken Windows command-line processing.
It's wonderful that the Python interpreter will accept a whole multi-line script as a composite -c argument... but because Windows command-line processing is fundamentally flawed, we simply can't count on it for Windows. Instead, accept script text, write a temporary script file in a system- dependent temp directory, ask Python to run that script and delete the file. Also, on Windows, use _spawnl(), much simpler than adding bizarre Windows wait logic to LLProcessLauncher. Use LLProcessLauncher only on Mac & Linux, with waitpid() to capture rc.
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/tests/llsdserialize_test.cpp93
1 files changed, 78 insertions, 15 deletions
diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp
index ff0d8d5f46..4e09a4fe3c 100644
--- a/indra/llcommon/tests/llsdserialize_test.cpp
+++ b/indra/llcommon/tests/llsdserialize_test.cpp
@@ -31,18 +31,28 @@
#if LL_WINDOWS
#include <winsock2.h>
typedef U32 uint32_t;
+#include <process.h>
#else
#include <netinet/in.h>
#include <errno.h>
#include <sys/wait.h>
+#include "llprocesslauncher.h"
#endif
+// As we're not trying to preserve compatibility with old Boost.Filesystem
+// code, but rather writing brand-new code, use the newest available
+// Filesystem API.
+#define BOOST_FILESYSTEM_VERSION 3
+#include "boost/filesystem.hpp"
+#include "boost/filesystem/v3/fstream.hpp"
+#include "boost/range.hpp"
+#include "boost/foreach.hpp"
+
#include "../llsd.h"
#include "../llsdserialize.h"
#include "../llformat.h"
#include "../test/lltut.h"
-#include "llprocesslauncher.h"
#include "stringize.h"
std::vector<U8> string_to_vector(const std::string& str)
@@ -50,6 +60,51 @@ std::vector<U8> string_to_vector(const std::string& str)
return std::vector<U8>(str.begin(), str.end());
}
+// boost::filesystem::temp_directory_path() isn't yet in Boost 1.45! :-(
+// Switch to that one as soon as we update to a Boost that contains it.
+boost::filesystem::path temp_directory_path()
+{
+#if LL_WINDOWS
+ char buffer[PATH_MAX];
+ GetTempPath(sizeof(buffer), buffer);
+ return boost::filesystem::path(buffer);
+
+#else // LL_DARWIN, LL_LINUX
+ static const char* vars[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR" };
+ BOOST_FOREACH(const char* var, vars)
+ {
+ const char* found = getenv(var);
+ if (found)
+ return boost::filesystem::path(found);
+ }
+ return boost::filesystem::path("/tmp");
+#endif // LL_DARWIN, LL_LINUX
+}
+
+// Create a Python script file with specified content "somewhere in the
+// filesystem," cleaning up when it goes out of scope.
+class NamedTempScript
+{
+public:
+ NamedTempScript(const std::string& content):
+ mPath(/*boost::filesystem*/::temp_directory_path() /
+ boost::filesystem::unique_path("%%%%-%%%%-%%%%-%%%%.py"))
+ {
+ boost::filesystem::ofstream file(mPath);
+ file << content << '\n';
+ }
+
+ ~NamedTempScript()
+ {
+ boost::filesystem::remove(mPath);
+ }
+
+ std::string getName() const { return mPath.native(); }
+
+private:
+ boost::filesystem::path mPath;
+};
+
namespace tut
{
struct sd_xml_data
@@ -1496,26 +1551,34 @@ namespace tut
TestPythonCompatible() {}
~TestPythonCompatible() {}
- void python(const std::string& desc, const std::string& script, F32 timeout=5)
+ void python(const std::string& desc, const std::string& script /*, F32 timeout=5 */)
{
const char* PYTHON(getenv("PYTHON"));
ensure("Set $PYTHON to the Python interpreter", PYTHON);
+
+ NamedTempScript scriptfile(script);
+
+#if LL_WINDOWS
+ std::string q("\"");
+ std::string qPYTHON(q + PYTHON + q);
+ std::string qscript(q + scriptfile.getName() + q);
+ int rc(_spawnl(_P_WAIT, PYTHON, qPYTHON.c_str(), qscript.c_str(), NULL));
+ if (rc == -1)
+ {
+ char buffer[256];
+ strerror_s(buffer, errno); // C++ can infer the buffer size! :-O
+ ensure(STRINGIZE("Couldn't run Python " << desc << "script: " << buffer), false);
+ }
+ else
+ {
+ ensure_equals(STRINGIZE(desc << " script terminated with rc " << rc), rc, 0);
+ }
+
+#else // LL_DARWIN, LL_LINUX
LLProcessLauncher py;
py.setExecutable(PYTHON);
- py.addArgument("-c");
- py.addArgument(script);
+ py.addArgument(scriptfile.getName());
ensure_equals(STRINGIZE("Couldn't launch " << desc << " script"), py.launch(), 0);
-
-#if LL_WINDOWS
- ensure_equals(STRINGIZE(desc << " script ran beyond "
- << std::fixed << std::setprecision(1)
- << timeout << " seconds"),
- WaitForSingleObject(py.getProcessHandle(), DWORD(timeout * 1000)),
- WAIT_OBJECT_0);
- DWORD rc(0);
- GetExitCodeProcess(py.getProcessHandle(), &rc);
- ensure_equals(STRINGIZE(desc << " script terminated with rc " << rc), rc, 0);
-#else
// Implementing timeout would mean messing with alarm() and
// catching SIGALRM... later maybe...
int status(0);