summaryrefslogtreecommitdiff
path: root/indra/llcommon/tests
AgeCommit message (Collapse)Author
2023-12-15Merge branch 'main' into DRTVWR-489Andrey Lihatskiy
# Conflicts: # indra/newview/fonts/DejaVu-license.txt # indra/newview/fonts/DejaVuSans-Bold.ttf # indra/newview/fonts/DejaVuSans-BoldOblique.ttf # indra/newview/fonts/DejaVuSans-Oblique.ttf # indra/newview/fonts/DejaVuSans.ttf # indra/newview/fonts/DejaVuSansMono.ttf
2023-12-05Merge branch 'main' into DRTVWR-489Alexander Gavriliuk
2023-11-29Merge branch 'DRTVWR-559' into marchcat/587-v-pbr-mergeAndrey Lihatskiy
# Conflicts: # indra/llcommon/CMakeLists.txt # indra/newview/llspatialpartition.cpp # indra/newview/llviewergenericmessage.cpp # indra/newview/llvoavatar.cpp
2023-10-29DRTVWR-587: Fix LL::apply(function, LLSD array).Nat Goodspeed
We define a specialization of LLSDParam<const char*> to support passing an LLSD object to a const char* function parameter. Needless to remark, passing object.asString().c_str() would be Bad: destroying the temporary std::string returned by asString() would immediately invalidate the pointer returned by its c_str(). But when you pass LLSDParam<const char*>(object) as the parameter, that specialization itself stores the std::string so the c_str() pointer remains valid as long as the LLSDParam object does. Then there's LLSDParam<LLSD>, used when we don't have the parameter type available to select the LLSDParam specialization. LLSDParam<LLSD> defines a templated conversion operator T() that constructs an LLSDParam<T> to provide the actual parameter value. So far, so good. The trouble was with the implementation of LLSDParam<LLSD>: it constructed a _temporary_ LLSDParam<T>, implicitly called its operator T() and immediately destroyed it. Destroying LLSDParam<const char*> destroyed its stored string, thus invalidating the c_str() pointer before the target function was entered. Instead, make LLSDParam<LLSD>::operator T() capture each LLSDParam<T> it constructs, extending its lifespan to the lifespan of the LLSDParam<LLSD> instance. For this, derive each LLSDParam specialization from LLSDParamBase, a trivial base class that simply establishes the virtual destructor. We can then capture any specialization as a pointer to LLSDParamBase. Also restore LazyEventAPI tests on Mac.
2023-10-27DRTVWR-587: Skip Visual Studio LLSDParam<const char*> tests for now.Nat Goodspeed
They do work fine on clang... unblocking the rest of the team during diagnosis.
2023-10-25Merge remote-tracking branch 'origin/main' into DRTVWR-559Brad Linden
2023-10-25Post merge build fixAndrey Kleshchev
2023-10-25Merge branch 'main' into DRTVWR-587-maint-VAndrey Lihatskiy
# Conflicts: # autobuild.xml # indra/llcommon/tests/llleap_test.cpp # indra/newview/viewer_manifest.py
2023-10-12SL-18837: Unify all llrand_test.cpp in-range tests.Nat Goodspeed
The header file documents that no llrand function should ever return a value equal to the passed extent, so the one test in llrand_test.cpp that checked less than or equal to the high end of the range was anomalous. But changing that to an exclusive range means that we no longer need separate exclusive range and inclusive range functions. Replace ensure_in_range_using(), ensure_in_exc_range() and ensure_in_inc_range() with a grand unified (simplified) ensure_in_range() function.
2023-10-05SL-18837: When llrand_test.cpp fails, display the failing value.Nat Goodspeed
It's frustrating and unactionable to have a failing test report merely that the random value was greater than the specified high end. Okay, so what was the value? If it's supposed to be less than the high end, did it happen to be equal? Or was it garbage? We can't reproduce the failure by rerunning! The new ensure_in_exc_range(), ensure_in_inc_range() mechanism is somewhat complex because exactly one test allows equality with the high end of the expected range, where the rest mandate that the function return less than the high end. If that's a bug in the test -- if every llrand function is supposed to return less than the high end -- then we could simplify the test logic.
2023-09-08SL-18837: Make llsdserialize_test debug output conditional.Nat Goodspeed
Move hexdump() and hexmix() stream formatters to new hexdump.h for potential use by other tests. In toPythonUsing() helper function, add a temp file to receive Python script debug output, and direct debug output to that file. On test failure, dump the contents of that file to the log. Give NamedTempFile::peep() an optional target std::ostream; refactor implementation as peep_via() that accepts a callable to process each text line. Add operator<<() to stream the contents of a NamedTempFile object to ostream -- but don't use that with LL_DEBUGS(), as it flattens the file contents into a single log line. Instead add peep_log(), which streams each individual text line to LL_DEBUGS().
2023-09-08SL-18837: Add debugging output to llsdserialize_test.cpp.Nat Goodspeed
2023-09-07SL-18837: Fix minor merge glitch.Nat Goodspeed
2023-09-07SL-18837: Merge branch 'main' into actionsNat Goodspeed
2023-08-24Merge remote-tracking branch 'origin/main' into DRTVWR-489Andrey Kleshchev
# Conflicts: # indra/llcommon/llsdserialize.cpp # indra/llcommon/llsdserialize.h # indra/llmath/llvolume.cpp # indra/llrender/llgl.cpp # indra/llxml/llcontrol.cpp # indra/newview/llpanelnearbymedia.cpp # indra/newview/llsceneview.cpp # indra/newview/llselectmgr.cpp # indra/newview/llstartup.cpp # indra/newview/lltextureview.cpp # indra/newview/llvovolume.cpp # indra/newview/skins/default/xui/en/menu_viewer.xml
2023-08-23Merge branch 'main' into DRTVWR-587-maint-VAndrey Lihatskiy
# Conflicts: # autobuild.xml
2023-08-23Merge remote-tracking branch 'origin/main' into DRTVWR-559Brad Linden
2023-07-27DRTVWR-587: Skip some tests that only fail with older Visual StudioNat Goodspeed
2023-07-18Merge remote-tracking branch 'origin/xcode-14.3' into DRTVWR-559 (#292)Brad Linden
2023-07-17SL-18837: Lowercasing pathname for string compare is Windows-only.Nat Goodspeed
2023-07-13DRTVWR-558: Fix a few lleventdispatcher_test merge glitches.Nat Goodspeed
2023-07-13DRTVWR-558: Extend LLEventDispatcher::add() overloads.Nat Goodspeed
Add LL::always_return<T>(), which takes a callable and variadic arguments. It calls the callable with those arguments and, if the returned type is convertible to T, converts it and returns it. Otherwise it returns T(). always_return() is generalized from, and supersedes, LLEventDispatcher::ReturnLLSD. Add LL::function_arity<CALLABLE>, which extends boost::function_types::function_arity by reporting results for both std::function<CALLABLE> and boost::function<CALLABLE>. Use for LL::apply(function, LLSD array) as well as for LLEventDispatcher. Make LLEventDispatcher::add() overloads uniformly distinguish between a callable (whether non-static member function or otherwise) that accepts a single LLSD parameter, versus any other signature. Accepting exactly one LLSD parameter signals that the callable will accept the composite arguments LLSD blob, instead of asking LLEventDispatcher to unpack the arguments blob into individual arguments. Support add(subclass method) overloads for arbitrary-parameters methods as well as for (const LLSD&) methods. Update tests accordingly: we need no longer pass the boilerplate lambda instance getter that binds and returns 'this'. Extract to the two LLEventDispatcher::make_invoker() overloads the LL::apply() logic formerly found in ReturnLLSD. Change lleventdispatcher_test.cpp tests from boost::bind(), which accepts variadic arguments (even though it only passes a fixed set to the target callable), to fixed-signature lambdas. This is because the revamped add() overloads care about signature. Add a test for a non-static method that accepts (const LLSD&), in other words the composite arguments LLSD blob, and likewise returns LLSD. (cherry picked from commit 95b787f7d7226ee9de79dfc9816f33c8bf199aad)
2023-07-13DRTVWR-558: Add tests for batched LLDispatchListener operations.Nat Goodspeed
Specifically, add tests for: - successful map batch - map batch with some errors and a reply pump - map batch with some errors and no reply - successful array batch - array batch with some errors and a reply pump - array batch with some errors and no reply (cherry picked from commit 078f0f5c9fb5075a8ad01cac417e1d7ee2b6a919)
2023-07-13DRTVWR-558: Make DispatchResult methods use their arguments.Nat Goodspeed
Fix lleventdispatcher_test.cpp's test class DispatchResult::strfunc(), intfunc(), mapfunc() and arrayfunc() to return values derived from (not identical to) their arguments, so we can reuse these functions for further testing of passing arguments to a named callable. Adjust existing tests accordingly. (cherry picked from commit 07e09a8daea008d28b97399920db60a147cf75c0)
2023-07-13DRTVWR-558: Add tests for LLDispatchListener functionality.Nat Goodspeed
Refine the special case of calling a nullary target function from an (event) method, notably via LLDispatchListener. (cherry picked from commit edcc52a9f60b1ec9b8f53603d6e2676558d41294)
2023-07-13DRTVWR-558: Clean up LLEventDispatcher argument and result handling.Nat Goodspeed
Add a new LLEventDispatcher constructor accepting not only the map key to extract a requested function name, but a second map key to extract the arguments -- when required. In Doxygen comments, clarify the difference between the two constructors. Move interaction with the LLEventPump subsystem to LLDispatchListener. LLEventDispatcher is intended to be directly called. On error, instead of looking for a "reply" key in the invocation LLSD, throw DispatchError. Publish DispatchError, formerly an implementation detail, and its new subclass DispatchMissing. Make both LLEventDispatcher::operator()() overloads return LLSD, leveraging the new internal ReturnLLSD logic that returns a degenerate LLSD blob for a void target callable and, for compatible types, converts the returned value to LLSD. Notably, the public try_call() overloads still return bool; any value returned by the target callable is discarded. Clarify the operator() and try_call() argument requirements for target callables registered to accept an LLSD array, in Doxygen comments and in code. In particular, the 'event' passed to (event) overloads (vs. the (name, event) overloads) must be an LLSD map, so it must contain an "args" key (or the new arguments map key specified to the constructor) containing the LLSD args array. Since the use of the new args key depends on whether the target callable is registered to accept an array or a map, pass it into DispatchEntry::call() (and all subclass overrides), along with a bool to disambiguate whether we reached that method from an LLEventDispatcher (event) invocation method or a (name, event) invocation method. Allow streaming an LLEventDispatcher instance to std::ostream, primarily to facilitate construction of proper error messages. Revert the 'name' argument of internal try_call(key, name, event) to std::string. Ditch try_call_log(), try_call_one() and reply(). Fold try_call_one() logic into three-argument try_call(). Refactor callFail() as a template method accepting both the exception to throw and arbitrary stringize() arguments from which to construct the exception message. Non-static callFail() implicitly prepends the instance and a colon to the rest of the arguments, and calls static sCallFail(). The latter constructs the exception message, logs it and throws the specified exception. This obviates try_call_log(). Make implementation detail helper class LLSDArgsMapper a private member of LLEventDispatcher so it can access sCallFail(): we now want all error handling to go through that method. Add LLSDArgsMapper::callFail() resembling LLSDEventDispatcher::callFail(), but without having to specify the exception: only LLEventDispatcher will throw anything but generic DispatchError. Give LLEventDispatcher::ParamsDispatchEntry and its subclasses ArrayParamsDispatchEntry and MapParamsDispatchEntry a new 'name' argument to identify error messages. Store it and use it implicitly in new callFail() method, very like LLSDArgsMapper::callFail(). Make LLEventDispatcher:: addArrayParamsDispatchEntry() and addMapParamsDispatchEntry() pass a 'name' that includes the LLEventDispatcher instance name as well as the name of the specific registered callable. This way we need not intercept a low-level error and annotate it with contextual data: we can just let the exception propagate. Make ParamsDispatchEntry::call() override catch LL::apply_error thrown by an invoker_function, and pass its message to callFail(), i.e. rethrow as LLEventDispatcher::DispatchError. Introduce ArrayParamsDispatchEntry::call() override for the special logic to extract an arguments array from a passed LLSD map -- but only under the circumstances described in the Doxygen comment. Add similar logic to MapParamsDispatchEntry::call(), but with both argskey itself and a value for argskey optional in the passed LLSD map. Because LLEventDispatcher now has two constructor overloads, allow subclass constructor LLDispatchListener() to accept zero or more trailing arguments. This is different than giving LLDispatchListener's constructor a default final argument, in that the subclass doesn't need to specify its default value: that's up to the base-class constructor. But it does require that the subclass constructor move to the header file. Move private LLEventDispatcher::reply() method to LLDispatchListener. Extend LLDispatchListener::process() to handle DispatchError by attempting to reply with a map containing an "error" key, per convention. (In other words, move that logic from LLEventDispatcher to LLDispatchListener.) Also, for a map LLSD result, attempt to reply with that result; for other defined LLSD types, attempt to reply with a map containing a "data" key. This is backwards compatible with previous behavior because all previous LLDispatchListener subclass methods returned void, which now produces an undefined LLSD blob, which we don't bother trying to send in reply. In lleventdispatcher_test.cpp, rework tut::lleventdispatcher_data::call_exc() yet again to catch DispatchError instead of listening for an LLEventPump reply event. Similarly, make call_logerr() catch DispatchError. Since the exception should also be logged, we ignore it and focus on the log, as before. Add tests <23> to <27>, exercising calls to new class DispatchResult methods returning string, int, LLSD map, LLSD array and void. (cherry picked from commit 2f9c915dd3d5137b5b2b1a57f0179e1f7a090f8c)
2023-07-13DRTVWR-558: Allow directly streaming test helper class CaptureLog.Nat Goodspeed
(cherry picked from commit 374eb409b98795158b36e232f670d1302f31b9ff)
2023-07-13DRTVWR-558: LLEventDispatcher uses LL::apply(), not boost::fusion.Nat Goodspeed
While calling a C++ function with arguments taken from a runtime-variable data structure necessarily involves a bit of hocus-pocus, the best you can say for the boost::fusion based implementation is that it worked. Sadly, template recursion limited its applicability to a handful of function arguments. Now that we have LL::apply(), use that instead. This implementation is much more straightforward. In particular, the LLSDArgsSource class, whose job was to dole out elements of an LLSD array one at a time for the template recursion, goes away entirely. Make virtual LLEventDispatcher::DispatchEntry::call() return LLSD instead of void. All LLEventDispatcher target functions so far have been void; any function that wants to respond to its invoker must do so explicitly by calling sendReply() or constructing an LLEventAPI::Response instance. Supporting non- void functions permits LLEventDispatcher to respond implicitly with the returned value. Of course this requires a wrapper for void target functions that returns LLSD::isUndefined(). Break out LLEventDispatcher::reply() from callFail(), so we can reply with success as well as failure. Make LLEventDispatcher::try_call_log() prepend the actual leaf class name and description to any error returned by three-arg try_call(). That try_call() overload reported "LLEventDispatcher(desc): " for a couple specific errors, but no others. Hoist to try_call_log() to apply uniformly. Introduce new try_call_one() method to diagnose name-not-found errors and catch internal DispatchError and LL::apply_error exceptions. try_call_one() returns a std::pair, containing either an error message or an LLSD value. Make try_call_log() and three-arg try_call() accept LLSD 'name' instead of plain std::string, allowing for the possibility of an array or map. That lets us extend three-arg try_call() to break out new cases for the function selector LLSD: isUndefined(), isArray(), isMap() and (current case) scalar String. If try_call_one() reports an error, log it and try to send reply, as now. If it returns LLSD::isUndefined(), e.g. from a void target function wrapper, do nothing. But if it returns an LLSD map, try to send that back to the invoker. And if it returns an LLSD scalar or array, wrap it in a map with key "data" to respond to the invoker. Allowing a target function to return its result rather than explicitly sending it opens the possibility of batched requests (aggregate 'name') returning batched responses. Almost every place that constructs LLEventDispatcher's internal DispatchError exception called stringize() to format the what() string. Simplify calls by making DispatchError accept variadic arguments and forward to stringize(). Add LL::invoke() to apply.h. Like LL::apply(), this is a (limited) C++14 foreshadowing of std::invoke(), with preprocessor conditionals to switch to std::invoke() when that's available. Introduce LL::invoke() to handle a callable that's actually a pointer to method. Now our C++14 apply() implementation can accept pointer to method, using invoke() to generalize the actual function call. Also anticipate std::bind_front() with LL::bind_front(). For apply(func, std::array) and our extensions apply(func, std::vector) and apply(func, LLSD), we can't pass a pointer to method as the func unless the second argument happens to be an array or vector of pointers (or references) to instances of exactly the right class -- and of course LLSD can't store such at all. It's tempting to pass std::bind(std::mem_fn(ptr_to_method), instance), but that won't work: std::bind() requires a value or placeholder for each argument to pass to the bound function. The bind() expression above would only work for a nullary method. std::bind_front() would work, but that doesn't arrive until C++20. Again, once we get there we'll defer to the std:: implementation. Instead of the generic __cplusplus, check the appropriate feature-test macro for availability of each of std::invoke(), std::apply() and std::bind_front(). Change apply() error handling from assert() to new LL::apply_error exception. LLEventDispatcher must be able to intercept apply() errors. Move validation and synthesis of the relevant error message to new apply.cpp source file. Add to llptrto.h new LL::get_ref() and LL::get_ptr() template functions to unify the cases of a calling template accepting either a pointer or a reference. Wrapping the parameter in either get_ref() or get_ptr() allows dereferencing the parameter as desired. Move LL::apply(function, LLSD) argument validation/manipulation to a non- template function in llsdutil.cpp: no need to replicate that logic in the template for every CALLABLE specialization. The trouble with passing bind_front(std::mem_fn(ptr_to_method), instance) to apply() is that since bind_front() accepts and forwards variadic additional arguments, apply() can't infer the arity of the bound ptr_to_method. Address that by introducing apply_n<arity>(function, LLSD), permitting a caller to infer the arity of ptr_to_method and explicitly pass it to apply_n(). Polish up lleventdispatcher_test.cpp accordingly. Wrong LLSD type and wrong number of arguments now produce different (somewhat more informative) error messages. Moreover, passing too many entries in an LLSD array used to work: the extra arguments used to be ignored. Now we require that the size of the array match the arity of the target function. Change the too-many-arguments tests from success testing to error testing. Replace 'foreach' aka BOOST_FOREACH macro invocations with range 'for'. Replace STRINGIZE(item0 << item1 << ...) with stringize(item0, item1, ...). (cherry picked from commit 9c049563b5480bb7e8ed87d9313822595b479c3b)
2023-07-13DRTVWR-558: Add LL::apply() test for function(const LLSD&).Nat Goodspeed
(cherry picked from commit 7d33e00d925614911a7602da1bd79916cc849ad7)
2023-07-13DRTVWR-558: Add unit test for VAPPLY().Nat Goodspeed
Add to apply_test.cpp a collect() function that incrementally accumulates an arbitrary number of arguments into a std::vector<std::string>. Construct a std::array<std::string> to pass it, using VAPPLY(). Clarify in header comments that LL::apply() can't call a variadic function with arguments of dynamic size: std::vector or LLSD. The compiler can deduce how many arguments to pass to a function with a fixed argument list; it can deduce how many arguments to pass to a variadic function with a fixed number of arguments. But it can't compile a call to a variadic function with an arguments data structure whose size can vary at runtime. (cherry picked from commit ceed33396266b123896f7cfb9b90abdf240e1eec)
2023-07-13DRTVWR-558: Extend LL::apply() to LLSD array arguments.Nat Goodspeed
Make apply(function, std::array) and apply(function, std::vector) available even when we borrow the C++17 implementation of apply(function, std::tuple). Add apply(function, LLSD) with interpretations: * isUndefined() is treated as an empty array, for calling a nullary function * scalar LLSD is treated as a single-entry array, for calling a unary function * isArray() converts function parameters using LLSDParam * isMap() is an error. Add unit tests for all flavors of LL::apply(). (cherry picked from commit 3006c24251c6259d00df9e0f4f66b8a617e6026d)
2023-07-13DRTVWR-558: Fix builds on macOS 12.5 Monterey.Nat Goodspeed
Always search for python3[.exe] instead of plain 'python'. macOS Monterey no longer bundles Python 2 at all. Explicitly make PYTHON_EXECUTABLE a cached value so if the user edits it in CMakeCache.txt, it won't be overwritten by indra/cmake/Python.cmake. Do NOT set DYLD_LIBRARY_PATH for test executables! That has Bad Effects, as discussed in https://stackoverflow.com/q/73418423/5533635. Instead, create symlinks from build-mumble/sharedlibs/Resources -> Release/Resources and from build-mumble/test/Resources -> ../sharedlibs/Release/Resources. For test executables in sharedlibs/RelWithDebInfo and test/RelWithDebInfo, this supports our dylibs' baked-in load path @executable_path/../Resources. That load path assumes running in a standard app bundle (which the viewer in fact does), but we've been avoiding creating an app bundle for every test program. These symlinks allow us to continue doing that while avoiding DYLD_LIBRARY_PATH. Add indra/llcommon/apply.h. The LL::apply() function and its wrapper macro VAPPLY were very useful in diagnosing the problem. Tweak llleap_test.cpp. This source was modified extensively for diagnostic purposes; these are the small improvements that remain. (cherry picked from commit 15d37713b9113a6f70dde48c764df02c76e18cbc) (cherry picked from commit a1adcf1905d1fbc5fe07ff5a627295ccfe461ac4)
2023-07-12SL-18330: Merge commit '6b53036' into DRTVWR-587-maint-VNat Goodspeed
Bring over part of the LLEventDispatcher work inspired by DRTVWR-558.
2023-07-10SL-18837: Windows failures in setWorkingDirectory(): C: vs. c: (sigh)Nat Goodspeed
Normalize the case of the name of the temp directory for string comparison.
2023-07-10SL-18837: Disable APR_LOG for now, but leave notes for the future.Nat Goodspeed
2023-07-10SL-18837: Revert "Force llprocess_test and llleap_test to use just 'python'."Nat Goodspeed
Turns out that the pathname of the Python executable wasn't the issue. This reverts commit 7dc6211ad5ea83685a35c6fff740278343aa8b9d.
2023-07-08SL-18837: Force llprocess_test and llleap_test to use just 'python'.Nat Goodspeed
On GitHub Windows runners, trying to make build.yaml set PYTHON=python in the environment doesn't work: integration tests still fail with "Access is denied" because they're still trying to execute the interpreter's full pathname. Instead, make llprocess_test and llleap_test detect the case of GitHub Windows and override the environment variable PYTHON with a baked-in string constant "python".
2023-07-08SL-18837: Set APR_LOG once for the whole jobNat Goodspeed
instead of a new value for each LLProcess::create() invocation. Since the internal apr_log() function only looks at APR_LOG once per process, the first test (which succeeded, hence no log file dump) left the log file open with that same original pathname. Resetting the APR_LOG environment variable for subsequent runs only made the new code in llprocess_test look for files that were never created.
2023-07-08SL-18837: Don't use LLDir, use NamedTempFile::temp_path.Nat Goodspeed
Remove llcommon circular dependency on llfilesystem, which doesn't work for this case anyway.
2023-07-07SL-18837: Ditch unreferenced name of caught exceptionNat Goodspeed
2023-07-07SL-18837: Hook in LLDir to allow reading APR log file.Nat Goodspeed
2023-07-07SL-18837: Fix spurious semiNat Goodspeed
2023-07-07SL-18837: Fix "lldir.h" #includeNat Goodspeed
2023-07-07SL-18837: Coax APR to log LLProcess launch attempts; show log file.Nat Goodspeed
2023-07-07SL-18837: Partially revert e933ace, keeping useful tweaks.Nat Goodspeed
Introducing indirection via test_python_script.py did NOT address the "Access is denied" errors on GitHub Windows runners.
2023-07-07SL-18837: Try to bypass Windows perm problem with Python indirection.Nat Goodspeed
2023-06-06SL-18837: Ditch Boost.Phoenix implicit lambda syntax.Nat Goodspeed
It's cool to be able to write 'arg1 << "stuff" << var ...;' for a lambda accepting a std::ostream reference, but cascading compile errors mean it's no longer worth trying to make that work -- given actual C++ lambdas. Also clean up a lingering BOOST_FOREACH() and a boost::bind() while at it.
2023-06-06SL-18837: NamedTempFile back to std::function, use boost::phoenix <<Nat Goodspeed
It seems the problem addressed by aab769e wasn't some synergy between Boost.Phoenix and Boost.Function, but rather the lack of a Phoenix header file introducing operator<<().
2023-06-05SL-18837: Try giving temp Python scripts a .py extension.Nat Goodspeed
On GitHub Windows Actions runners, we're getting permissions errors trying to tell the Python interpreter to run a NamedTempFile script. Try using NamedExtTempFile to give each such script a .py extension.
2023-06-05SL-18837: Bump the granularity of WorkQueue timing tests.Nat Goodspeed
On a low-powered GitHub Mac runner, the system doesn't wake up as soon as it should, and we get spurious "too late" errors. Try a bigger time increment.