summaryrefslogtreecommitdiff
path: root/indra/llcommon/tests
AgeCommit message (Collapse)Author
2012-03-02Add LLLeap unit tests for strange data on child stdout.Nat Goodspeed
2012-03-02Add "load test" LLLeap unit tests: many small messages, one large.Nat Goodspeed
These tests rule out corruption as we cross buffer boundaries in OS pipes and the LLLeap implementation itself.
2012-03-02Drag in Python llsd module, which greatly simplifies tests.Nat Goodspeed
It only took a few examples of trying to wrangle notation LLSD as string data to illustrate how clumsy that is. I'd forgotten that a couple other TUT tests already invoke Python code that depends on the llsd module. The trick is to recognize that at least as of now, there's still an obsolete version of the module in the viewer's own source tree. Python code is careful to try importing llbase.llsd before indra.base.llsd, so that if/when we finally do clear indra/lib/python from the viewer repo, we need only require that llbase be installed on every build machine.
2012-03-01Refactor llleap_test.cpp to streamline adding more unit tests.Nat Goodspeed
Migrate logic from specific test to common reader module, notably parsing the wakeup message containing the reply-pump name. Make test script post to Result struct to communicate success/failure to C++ TUT test, rather than just writing to log. Make test script insensitive to key order in serialized LLSD::Map.
2012-03-01Break out std::ostream << CaptureLog routine for general use.Nat Goodspeed
2012-03-01Add LLLeap class, initial implementation, initial unit tests.Nat Goodspeed
Instantiating LLLeap with a command to execute a particular child process sets up machinery to speak LLSD Event API Plugin protocol with that child process. LLLeap is an LLInstanceTracker subclass, so the code that instantiates need not hold the pointer. LLLeap monitors child-process termination and deletes itself when done.
2012-03-01Allow CaptureLog's consumer to specify desired log level.Nat Goodspeed
Of course, given the way the log machinery works, it's really "everything at that level or stronger."
2012-03-01Make CaptureLog::withMessage() raise tut::failure if not found.Nat Goodspeed
All known callers were using ensure(! withMessage(...).empty()). Centralize that logic. Make failure message report the string being sought and the log messages in which it wasn't found. In case someone does want to permit the search to fail, add an optional 'required' parameter, default true. Leverage new functionality in llprocess_test.cpp.
2012-03-01Break out TestRecorder class as CaptureLog into wrapllerrs.h.Nat Goodspeed
Giving more unit tests the ability to capture and examine log output is generally useful. Renaming the class just makes it less ambiguous: what's a TestRecorder? Something that records tests?
2012-02-29Guarantee LLProcess::Params::postend listener any ReadPipe data.Nat Goodspeed
Previously one might get process-terminated notification but still have to wait for the child process's final data to arrive on one or more ReadPipes. That required complex consumer timing logic to handle incomplete pending ReadPipe data, e.g. a partial last line with no terminating newline. New code guarantees that by the time LLProcess sends process-terminated notification, all pending pipe data will have been buffered in ReadPipes. Document LLProcess::ReadPipe::getPump() notification event; add "eof" key. Add LLProcess::ReadPipe::getline() and read() convenience methods. Add static LLProcess::getline() and basename() convenience methods, publishing logic already present elsewhere. Use ReadPipe::getline() and read() in unit tests. Add unit test for "eof" event on ReadPipe::getPump(). Add unit test verifying that final data have been buffered by termination notification event.
2012-02-27Reduce redundancy in llprocess_test.cpp using get_test_name().Nat Goodspeed
2012-02-27Automated merge with file:///Users/nat/linden/viewer-leap-daggyNat Goodspeed
2012-02-27Add LLInstanceTracker test for exception in subclass constructor.Nat Goodspeed
We want to verify the sequence: LLInstanceTracker constructor adds instance to underlying container Subclass constructor throws exception LLInstanceTracker destructor removes instance from underlying container.
2012-02-27Automated merge with file:///Users/nat/linden/viewer-leap-daggyNat Goodspeed
2012-02-27Make LLInstanceTracker<T, T*>::getInstance(T*) validate passed T*.Nat Goodspeed
For the T* specialization (no string, or whatever, key), the original getInstance() method simply returned the passed-in T* value. It was defined, as the comments noted, for completeness of the analogy with the keyed LLInstanceTracker specialization. It turns out, though, that getInstance(T*) can still be useful to ask whether the T* you have in hand still references a valid T instance. Support that usage.
2012-02-26Add LLStringUtil::getTokens() test for quoted empty string.Nat Goodspeed
This is an important differentiator between getTokens() and the present LLCommandLineParser::parseCommandLineString() logic: you cannot currently --set SomeVar to an empty string value because parseCommandLineString() discards empty strings.
2012-02-24Get rid of indra/llcommon/tests/setpython.py.Nat Goodspeed
run_build_test.py already has the capability to set environment variables, and we may as well direct it to set PYTHON to the running Python interpreter. That completely eliminates one level of process wrapper.
2012-02-24Add LLStringUtil::getTokens() overload handling quoted substrings.Nat Goodspeed
We didn't have any tokenizer suitable for scanning something like a bash command line. We do have a couple hacks, e.g. LLExternalEditor::tokenize() and LLCommandLineParser::parseCommandLineString(). Both try to work around boost::tokenizer limitations; but existing boost::tokenizer support just doesn't address this case. Neither of the above is available as a general scanner anyway, and parseCommandLineString() fails outright when passed "". New getTokens() also distinguishes between "drop delimiters" (e.g. space, return, newline) to be discarded from the token stream, versus "keep delimiters" (e.g. "+-*/") to be returned as tokens in their own right. There's an overload that honors escapes and a more efficient one that doesn't; each has a convenience overload that returns the scanned string vector rather than requiring a separate declaration. Tweak and comment older getTokens() implementation. Add unit tests for both old and new getTokens() implementations. Break out StringVec and std::ostream << StringVec from indra/llcommon/tests/listener.h to StringVec.h: that's coming in handy for a number of different TUT test sources.
2012-02-23Tighten up LLProcess pipe support, per Richard's code review.Nat Goodspeed
Clarify wording in some of the doc comments; be a bit more explicit about some of the parameter fields. Make some query methods 'const'. Change default LLProcess::ReadPipe::getLimit() value to 0: don't post any incoming data with notification event unless caller requests it. But do post pertinent FILESLOT in case caller reuses same listener for both stdout and stderr. Use more idiomatic, readable syntax for accessing LLProcess::Params data.
2012-02-20Let LLProcess consumer specify desired description for logging.Nat Goodspeed
If caller runs (e.g.) a Python script, it's not very helpful to a human log reader to keep seeing LLProcess instances logged as /pathname/to/python (pid). If caller is aware, the code can at least use the script name as the desc -- or maybe even a hint as to the script's purpose. If caller doesn't explicitly pass a desc, at least shorten to just the basename of the executable.
2012-02-20Make LLProcess post termination event to specified pump if desired.Nat Goodspeed
This way a caller need not spin on isRunning(); we can just listen for the requested termination event. Post a similar event containing error message if for any reason LLProcess::create() failed to launch the child. Add unit tests for both cases.
2012-02-16Fix typos in a few LLProcess::ReadPipe::find() unit tests.Nat Goodspeed
The typos didn't make for invalid tests, but they made a few tests redundant while leaving other (subtly different) cases untested.
2012-02-16Fix bug in LLProcess::ReadPipe::peek() substring computation.Nat Goodspeed
Add unit tests for peek() with substring args, reimplemented contains(), various forms of find(). (yay unit tests)
2012-02-16Add unit test for LLProcess::ReadPipe::setLimit().Nat Goodspeed
2012-02-16Add LLProcess::ReadPipe::find() methods, with corresponding npos.Nat Goodspeed
If it's useful to have contains() to tell you whether incoming data contains a particular substring, and if it's useful for contains() and peek() to accept an offset within that data, then it's useful to allow you to get the offset of a desired substring within that data. But of course a find() returning offset needs something like std::string::npos for "not found"; borrow that convention. Support both find(const std::string&) and find(char); the latter permits a more efficient implementation. In fact, make find(string) recognize a string of length 1 and leverage the find(char) implementation. Given that, reimplement contains(mumble) as shorthand for find(mumble) != npos. Implement find() overloads using std::search() and std::find() on boost::asio::streambuf character iterators, rather than copying to std::string and then using string search like previous contains() implementation. Reimplement WritePipeImpl::tick() and ReadPipeImpl::tick() to write/read directly from/to boost::asio::streambuf data, instead of copying to/from a temporary flat buffer. As long as ReadPipeImpl::tick() keeps successfully filling buffers, keep reading. Previous implementation would only handle a long child write over successive tick() calls. Stop on read error or when we come up short.
2012-02-15Add unit test for listening on LLProcess::ReadPipe::getPump().Nat Goodspeed
2012-02-15Don't be confused by "\r\n" line endings on pipe on Windows.Nat Goodspeed
These are all very well when we just want to dump the output to a log, or whatever, but in a unit-test context it matters for comparison.
2012-02-15Add LLProcess::ReadPipe::size(), peek(), contains().Nat Goodspeed
Also add "len" key to event data on LLProcess::getPump(). If you've used setLimit(), event["data"].length() may not reflect the length of the accumulated data in the ReadPipe. Add unit test with stdin/stdout handshake with child process.
2012-02-15Fix llprocess_test.cpp's exception catching for Linux.Nat Goodspeed
In the course of re-enabling the indra/test tests last year, Log generalized a workaround I'd introduced in llsdmessage_test.cpp. In Linux viewer land, a test program trying to catch an expected exception can't seem to catch it by its specific class (across the libllcommon.so boundary), but must instead catch std::runtime_error and validate the typeid().name() string. Log added a macro for this idiom in llevents_tut.cpp. Generalize that macro further for normal-case processing as well, move it to a header file of its own and use it in all known places -- plus the new exception-catching tests in llprocess_test.cpp.
2012-02-15Add tests for LLProcess::get[Opt][Read|Write]Pipe() validations.Nat Goodspeed
2012-02-15Preliminary pipe support for LLProcess.Nat Goodspeed
Add LLProcess::FileParam to specify how to construct each child's standard file slot, with lots of comments about features designed but not yet implemented. The point is to design it with enough flexibility to be able to extend to foreseeable use cases. Add LLProcess::Params::files to collect up to 3 FileParam items. Naturally this extends the accepted LLSD syntax as well. Implement type="" (child inherits parent file descriptor) and "pipe" (parent constructs anonymous pipe to pass to child). Add LLProcess::FILESLOT enum, plus methods: getReadPipe(FILESLOT), getOptReadPipe(FILESLOT) getWritePipe(), getOptWritePipe() getPipeName(FILESLOT): placeholder implementation for now Add LLProcess::ReadPipe and WritePipe classes, as returned by get*Pipe(). WritePipe supports get_ostream() method for streaming to child stdin. ReadPipe supports get_istream() method for reading from child stdout/stderr. It also provides getPump() returning LLEventPump& so interested parties can listen for arrival of new data on the aforementioned std::istream. For "pipe" slots, instantiate appropriate *Pipe class. ReadPipe and WritePipe classes are pure virtual bases for ReadPipeImpl and WritePipeImpl, respectively: all implementation data are hidden in the latter classes, visible only in llprocess.cpp. In fact each *PipeImpl class registers itself for "mainloop" ticks, attempting nonblocking I/O to the underlying apr_file_t on each tick. Data are buffered in a boost::asio::streambuf, which bridges between std::[io]stream and the APR I/O calls. Sanity-test ReadPipeImpl by using a pipe to absorb the Python "SyntaxError" output from the successful syntax_error test, rather than alarming the user. Add first few unit tests for validating FileParam. More tests coming!
2012-02-13Use per-frame ticks on "mainloop" LLEventPump to update LLProcess.Nat Goodspeed
When we reimplemented LLProcess on APR, necessitating APR's funny callback mechanism to sense child-process status, every isRunning() or getStatus() call called the APR poll function that calls ALL registered LLProcess callbacks. In other words, every time any consumer called any LLProcess::isRunning() method, all LLProcess callbacks were redundantly fired. Change that so that the single APR poll function is called once per frame, courtesy of the "mainloop" LLEventPump. Once per viewer frame should be well within the realtime duration in which it's reasonable to expect child-process status to change. In effect, this changes LLProcess's public API to introduce a dependency on "mainloop" ticks. Add such ticks to llprocess_test.cpp as well.
2012-02-13Add unit tests for LLProcess::Status functionality.Nat Goodspeed
2012-02-07Use os.path.normcase(os.path.normpath()) when comparing directories.Nat Goodspeed
Once again we've been bitten by comparison failure between "c:\somepath" and "C:\somepath". Normalize paths in both Python helper scripts to make that comparison more robust.
2012-02-07Convert LLProcess implementation from platform-specific to using APR.Nat Goodspeed
Include logic to engage Linden apr_procattr_autokill_set() extension: on Windows, magic CreateProcess() flag must be pushed down into apr_proc_create() level. When using an APR package without that extension, present implementation should lock (e.g.) SLVoice.exe lifespan to viewer's on Windows XP but probably won't on Windows 7: need magic flag on CreateProcess(). Using APR child-termination callback requires us to define state (e.g. LLProcess::RUNNING). Take the opportunity to present Status, capturing state and (if terminated) rc or signal number; but since most of the time all caller really wants is to log the outcome, also present status string, encapsulating logic to examine state and describe exited-with-rc vs. killed-by-signal. New Status logic may report clearer results in the case of a Windows child process killed by exception. Clarify that static LLProcess::isRunning(handle) overload is only for use when the original LLProcess object has been destroyed: really only for unit tests. We necessarily retain our original platform-specific implementations for just that one method. (Nonstatic isRunning() no longer calls static method.) Clarify log output from llprocess_test.cpp in a couple places.
2012-01-30Expose 'handle' as well as 'id' on LLProcess objects.Nat Goodspeed
On Posix, these and the corresponding getProcessID()/getProcessHandle() accessors produce the same pid_t value; but on Windows, it's useful to distinguish an int-like 'id' useful to human log readers versus an opaque 'handle' for passing to platform-specific API functions. So make the distinction in a platform-independent way.
2012-01-21Convert LLProcess consumers from LLSD to LLProcess::Params block.Nat Goodspeed
Using a Params block gives compile-time checking against attribute typos. One might inadvertently set myLLSD["autofill"] = false and only discover it when things behave strangely at runtime; but trying to set myParams.autofill will produce a compile error. However, it's excellent that the same LLProcess::create() method can accept either LLProcess::Params or a properly-constructed LLSD block.
2012-01-20Per Richard, replace LLProcessLauncher with LLProcess.Nat Goodspeed
LLProcessLauncher had the somewhat fuzzy mandate of (1) accumulating parameters with which to launch a child process and (2) sometimes tracking the lifespan of the ensuing child process. But a valid LLProcessLauncher object might or might not have ever been associated with an actual child process. LLProcess specifically tracks a child process. In effect, it's a fairly thin wrapper around a process HANDLE (on Windows) or pid_t (elsewhere), with lifespan management thrown in. A static LLProcess::create() method launches a new child; create() accepts an LLSD bundle with child parameters. So building up a parameter bundle is deferred to LLSD rather than conflated with the process management object. Reconcile all known LLProcessLauncher consumers in the viewer code base, notably the class unit tests.
2012-01-18Make embedded Python scripts compatible with Python 2.5 *SIGH*Nat Goodspeed
Apparently our TeamCity build machines are still not up to Python 2.6.
2012-01-18Add tests for implicit-kill-on-destroy, also orphan() method.Nat Goodspeed
2012-01-17Add tests for child-process args management and for kill() method.Nat Goodspeed
2012-01-17Refactor llprocesslauncher_test.cpp for better code reuse.Nat Goodspeed
Instead of free python() and python_out() functions containing a local temporary LLProcessLauncher instance, with a 'tweak' callback param to "do stuff" to that inaccessible object, change to a PythonProcessLauncher class that sets up a (public) LLProcessLauncher member, then allows you to run() or run() and then readfile() the output. Now you can construct an instance and tweak to your heart's content -- without funky callback syntax -- before running the script. Move all such helpers from TUT fixture struct to namespace scope. While fixture-struct methods can freely call one another, introducing a nested class gets awkward: constructor must explicitly require and bind a fixture-struct pointer or reference. Namespace scope solves this. (Truthfully, I only put them in the fixture struct originally because I thought it necessary for calling ensure() et al. But ensure() and friends are free functions; need only qualify them with tut:: namespace.)
2012-01-17Add first couple of LLProcessLauncher tests.Nat Goodspeed
Run INTEGRATION_TEST_llprocesslauncher using setpython.py so we can find the Python interpreter of interest. Introduce python() function to run a Python script specified using NamedTempFile conventions. Introduce a convention by which we can read output from a Python script using only the limited pre-January-2012 LLProcessLauncher API. Introduce python_out() function to leverage that convention. Exercise a couple of LLProcessLauncher methods using all the above.
2012-01-13Extract APR and temp-fixture-file helper code to indra/test.Nat Goodspeed
Specifically: Introduce ManageAPR class in indra/test/manageapr.h. This is useful for a simple test program without lots of static constructors. Extract NamedTempFile from llsdserialize_test.cpp to indra/test/ namedtempfile.h. Refactor to use APR file operations rather than platform- dependent APIs. Use NamedTempFile for llprocesslauncher_test.cpp.
2012-01-12Add LLStreamQueue::size() and tests to exercise it.Nat Goodspeed
2012-01-05Introduce LLStreamQueue to buffer nonblocking I/O.Nat Goodspeed
Add unit tests to verify basic functionality.
2011-12-23Fix sleep(0.5) to sleep(1) -- truncation to int makes that dubious.Nat Goodspeed
2011-12-23Should we expect EOF on one pipe before we finish reading the other?Nat Goodspeed
Defend test against the ambiguous answer to that question by not recording, or testing for, EOF history events. Enrich output for history-verification failures: display whole history array.
2011-12-23Automated merge with ssh://hg.lindenlab.com/nat/viewer-leapNat Goodspeed
2011-12-23Make pipe-management logic more robust.Nat Goodspeed
Previous logic was vulnerable to the case in which both pipes reached EOF in the same loop iteration. Now we use std::list instead of std::vector, allowing us to iterate and delete with a single pass.