[HN Gopher] Quartz: A Deterministic Time Testing Library for Go
       ___________________________________________________________________
        
       Quartz: A Deterministic Time Testing Library for Go
        
       Author : ammario
       Score  : 127 points
       Date   : 2024-07-15 18:30 UTC (1 days ago)
        
 (HTM) web link (coder.com)
 (TXT) w3m dump (coder.com)
        
       | wizzard0 wrote:
       | Very cool! Anything similar for .net?
        
         | neonsunset wrote:
         | Comes out of box: https://devblogs.microsoft.com/dotnet/fake-
         | it-til-you-make-i...
         | 
         | This is yet another area where .NET offers a better package,
         | unfortunately Go community is too self-centered to notice
         | what's happening elsewhere.
        
           | lloydatkinson wrote:
           | I was about to comment the same - even before ITimeProvider
           | existed it was already very common to have an ITime or IDate
           | or IDateTime etc that would then be implemented as you need
           | for tests.
           | 
           | Having this now as a built-in is excellent.
        
           | Thaxll wrote:
           | .NET 8 released 5 months ago, what are you talking about?
        
             | neonsunset wrote:
             | It was released 8 months ago. It seems this implies some
             | sort of argument, could you expand on that?
        
               | Thaxll wrote:
               | OP ask for a similar pattern for .net, you come here with
               | unnecessary aggressive stance on something that was
               | released 8 month ago, looking at your history it does not
               | surprises though since you seems to have a grudge with
               | Go.
        
               | neonsunset wrote:
               | You are misreading this as aggression towards OP, which
               | there is none. Instead, this is a general despair at the
               | damage done to our industry by Go and its community that
               | keeps touting this mediocre language with weak compiler,
               | unsound ecosystem, many footguns, lackluster type system
               | and backwards design as something that can even remotely
               | hope to compete with Rust or current state of C#.
        
               | dalyons wrote:
               | They're in every thread that mentions go, calling it
               | terrible and saying people are idiots for not using c#
               | instead.
               | 
               | It's become predictable and tiring
        
           | wizzard0 wrote:
           | Um, yes, TimeProvider is cool but works only insofar as ...
           | 
           | > If you provide a fake time provider in all those places
           | 
           | I'm looking for something more akin to
           | https://go.dev/issue/67434 (i.e. testing the code that calls
           | third-party libraries that might just call Thread.Sleep and
           | so on)
        
           | dang wrote:
           | Can you please stop posting language flamewar comments to HN?
           | It's the kind of thing we're trying to avoid here, and you've
           | unfortunately been doing it repeatedly.
           | 
           | https://news.ycombinator.com/newsguidelines.html
        
             | neonsunset wrote:
             | Alright :)
        
       | playingalong wrote:
       | It feels like every second, sorry every other time-related
       | library is called Quartz.
        
         | rob74 wrote:
         | Well, in PHP the de facto standard library is called Carbon (as
         | in radiocarbon dating I guess - which is different, but at the
         | risk of sounding, well, fossilized)
        
         | Joker_vD wrote:
         | Yeah, why not something like Klepsudra?
        
       | elchief wrote:
       | not a great name considering Quartz schedular for java...
        
         | lloydatkinson wrote:
         | Or for .NET
        
           | lloydatkinson wrote:
           | only on HN would a .NET comment get downvoted
        
             | devjab wrote:
             | Why would you say that? It's an archaic framework which
             | sticks around because it's "good enough" for anything with
             | a complexity low enough to be handled by its "magic". As
             | soon as you need something to scale or handle real
             | complexity where you have to step outside all the comfort
             | zone .net developers tend to operate in, it's one of the
             | worst frameworks that will constantly get in your way.
             | 
             | It's also an ecosystem riddled with traps that is still so
             | stuck in its OOP past that very few programming languages
             | operating on it are even capable of having functions
             | without a class object.
             | 
             | Don't get me wrong. It's a good language when you're
             | building relatively simple backend APIs that are small
             | enough that they can actually use things like entity
             | framework. Even more so if you're putting them into Azure
             | and letting your security be handled by EntraID.
             | 
             | But how many people on HN do you expect that is?
        
               | neonsunset wrote:
               | This may be your personal experience but it is used
               | successfully and happily by many in a variety of domains
               | way different to "boring OOP back-ends". No popular
               | general purpose language is confined to a single scenario
               | the way you describe (even Swift and Kotlin are
               | expanding). C# lets you do things like writing a
               | competitive Redis implementation[0], advanced physics
               | engine that beats Jolt[1] or a game engine that does not
               | rely on C++ or C[2], cross-platform applications[3] and
               | so on and so forth. It is possible to successfully do
               | both high level FP style approach for business domain
               | modeling and very low-level data crunching that is
               | competitive with systems programming languages.
               | 
               | [0]: https://microsoft.github.io/garnet/docs/benchmarking
               | /results...
               | 
               | [1]: https://github.com/bepu/bepuphysics2
               | 
               | [2]: https://www.stride3d.net
               | 
               | [3]: https://avaloniaui.net
        
         | 01HNNWZ0MV43FF wrote:
         | Or Quartz Composer, the rendering thingy for macOS
        
         | zikani_03 wrote:
         | In particular, there is also another library for task
         | scheduling named go-quartz: https://github.com/reugn/go-quartz.
         | 
         | Naming is indeed hard.
        
       | neild wrote:
       | Of possible interest to anyone testing concurrent Go code in
       | general and time in particular, a proposed standard library
       | package: https://go.dev/issue/67434
        
         | matttproud wrote:
         | This looks infinitely preferable.
        
           | padraicmahoney wrote:
           | What do you like better about it?
           | 
           | --- (btw: just read your blog on R -- love it)
        
         | slantedview wrote:
         | I'm curious if the author of Quartz has seen this proposal and
         | could provide a comparison?
        
           | spikecurtis1 wrote:
           | I'm Quartz's primary author, and I hadn't seen this proposal
           | until today.
           | 
           | They are similar in the sense of using a faked clock to make
           | things deterministic. Other than not having to inject the
           | Clock interface, tests using Quartz will probably look fairly
           | similar to this proposal in many cases.
           | 
           | The proposal has a simpler API than Quartz, being able to
           | just run some goroutines and wait until everything is
           | blocked.
           | 
           | However, this brings some limitations on what can be tested,
           | such as time elapsing while computation is occurring (not
           | just elapsing while things are waiting for something else).
           | IMO this is an important limitation, as many interesting
           | time-of-check, time-of-use bugs and edge cases occur because
           | time does elapse during computation in real systems.
           | 
           | An example of this from coder/coder that motivated the design
           | of Quartz's API: https://github.com/coder/coder/blob/a5e4bf38
           | fec66c5e7ecc96b0...
        
         | Groxx wrote:
         | That looks amazing. Advancing time while things are idle sounds
         | practically perfect, and that's _essentially_ impossible to
         | build as a library. As much as I like the sound of Quartz (the
         | issues they call out are real and very painful and I was
         | getting close to building my own version to solve some), that
         | issue might remove my need for it entirely.
        
         | bheadmaster wrote:
         | Thanks for sharing this. This is one of the best testing
         | features I've ever seen - I've had so many troubles with timing
         | tests and refactoring around them. I really hope this gets
         | merged.
        
         | oefrha wrote:
         | Related: the behavior of time in this proposal was implemented
         | in Go playground more than a decade ago:
         | https://go.dev/blog/playground#faking-time. Unfortunately it
         | was never exposed.
        
         | jerf wrote:
         | I still don't like that it assumes global monotonic time. It is
         | completely possible for an event to be scheduled in 100ms on
         | one thread and in 200ms in another, and for the latter to run
         | and/or finish first. A time testing system ought to let you
         | test that case, because you're going to hit it in production.
         | 
         | For that you really have no choice but to abandon the time
         | package's API anyhow because you're going to need some way to
         | trigger those things out-of-order.
         | 
         | I've been using this for a while now:
         | https://github.com/thejerf/abtime (my package) and it really
         | lets me get down and dirty with order of operations, when that
         | matters.
        
       | wolfspaw wrote:
       | Nice, Golang is Awesome!
        
         | myvoiceismypass wrote:
         | Why is Golang awesome? Because in 2024 there is now a decent
         | mock clock library for testing? I thought that one of go's
         | selling points was the stdlib and tooling being great out of
         | the box?
        
       | nsguy wrote:
       | I have a fair bit of experience writing tests for concurrent code
       | that uses timers on Go. We started with an open source test
       | library ( https://pkg.go.dev/github.com/benbjohnson/clock ). It
       | had a lot of problems. This was many years ago, looks like it's
       | seen some maintenance since so maybe it's better? Then we tried
       | to fix it. Fixed all the obvious bugs but still had a lot of
       | problems using it in practice. It's not enough to just handle the
       | calls without context of who is calling them in concurrent code.
       | Then we switched to using gomock which ended up also being hard
       | to use.
       | 
       | It's quite tricky is sort of the bottom line. It's not enough to
       | just create fake time there's a lot more to it.
        
         | jiveturkey wrote:
         | It's been abandoned/archived. I've since been using
         | github.com/jonboulle/clockwork which is much less problematic.
         | For my use it is perfectly fine.
        
       | alpb wrote:
       | I think https://pkg.go.dev/k8s.io/utils/clock and
       | https://pkg.go.dev/k8s.io/utils/clock/testing is already doing
       | these?
        
         | Groxx wrote:
         | At a glance, that looks almost identical to (an older version
         | of) https://github.com/jonboulle/clockwork (there are several
         | that are structurally very similar)
         | 
         | In which case no, it falls into the same kind of issues that
         | the post is describing as being problematic.
        
       | rmetzler wrote:
       | For linux, there is faketime, which will set a specific date and
       | time for all child processes. This enables you to test software
       | you don't even compile for time-based problems, e.g. logic around
       | Feb 29th or daylight saving time.
        
         | zokier wrote:
         | LD_PRELOAD is bit yucky though in my opinion. I suppose ptrace
         | is the only other option though :/
        
           | deivid wrote:
           | It's not the _only_ other option! It 's not less yucky, but
           | you can creatively stomp on the vDSO functions which back the
           | time-related functions (gettimeofday, clock_gettime, time);
           | I've written about it at [0] and have a "library" (more like
           | a proof of concept) at [1].
           | 
           | [0]: https://blog.davidv.dev/posts/cursing-a-process-vdso-
           | for-tim...
           | 
           | [1]: https://github.com/DavidVentura/tpom
        
         | TheDong wrote:
         | Since go don't use the libc related time functions on linux,
         | but rather makes syscalls directly, faketime will not work for
         | any programs written in Go.
        
       | jamesrr39 wrote:
       | At the risk of appearing low-tech, a much more simple, Goroutine-
       | safe solution for dealing with "now-dependent" code:
       | 
       | type NowFunc func() time.Time
       | 
       | func getGreeting(nowFunc NowFunc) string {                 now :=
       | nowFunc()            if now.Hour() < 12 {              return
       | "Good Morning"            }            return "Good day"
       | 
       | }
       | 
       | And just pass in `time.Now` in for live code, and your own inline
       | function for simulating a time in tests.
        
       ___________________________________________________________________
       (page generated 2024-07-16 23:01 UTC)