4 ms·
I also started using benbjohnson/clock about a year ago, but discovered that it wasn't a perfect fit: - Even though Clock is an interface, Timer is not. This m
by EdSchouten 6y ago
I also started using benbjohnson/clock about a year ago, but discovered that it wasn't a perfect fit:
- Even though Clock is an interface, Timer is not. This means that if you want to use that package in combination with gomock, you're out of luck.
- The Clock interface doesn't provide a wrapper for context.WithTimeout(), which also depends on the system clock.
- Nit: The Clock interface also exposes functions like time.After(), which should in my opinion never be used in production code, as they don't support efficient cancelation. You should use timers instead.
In the end I resorted to writing my own set of interfaces.
Code: https://github.com/buildbarn/bb-storage/tree/master/pkg/clock https://github.com/buildbarn/bb-storage/tree/master/pkg/cloc...
Documentation: https://pkg.go.dev/github.com/buildbarn/bb-storage/pkg/clock https://pkg.go.dev/github.com/buildbarn/bb-storage/pkg/clock
- devonkim 6y agoNot a mock obviously but in the interest of getting things done on schedule I’d suggest running tests in a container with https://github.com/wolfcw/libfaketime https://github.com/wolfcw/libfaketime and orchestrating edge cases like leap seconds external to the test suite itself.
- TheDong 6y agoInterestingly, libfaketime probably won't work in go due to their allergy to using libc on linux. I believe they only use syscalls directly for time-related functionality, meaning that any LD_PRELOAD hack won't work.
- zeroxfe 6y ago> The Clock interface also exposes functions like time.After(), which should in my opinion never be used in production code, as they don't support efficient cancelation. Can you expand on this? I find time.After super useful for time arithmetic in control flow, like checking for expiry, validating leases, etc.
- EdSchouten 6y agoKeep in mind that there are two functions called After(). One is a method of time.Time and can be used to compare timestamps. That’s the one you are likely talking about, and is perfectly fine to use! I’m talking about the free function After() that’s part of the time package: https://golang.org/pkg/time/#After https://golang.org/pkg/time/#After That one can be used to create a channel that triggers after a certain amount of time. The reason you shouldn’t be using that one is because you can’t clean it up before it triggers. This means that any code that bails out early ends up leaking memory temporarily.
- zeroxfe 6y agoAh, gotcha -- I was thinking of the timestamp comparison method. (Agreed about the other case.)
- closeparen 6y ago>if you want to use that package in combination with gomock, you're out of luck In general, libraries should offer structs, and you should declare your own interfaces with the subset of methods that you require. This is somewhat messy here because the timer channel is accessed by a field rather than a method, but you could write a struct that embeds time.Timer and adds C() as a method. Then both your wrapped time.Timer and your mock/fake could fulfill your interface.
- EdSchouten 6y agoThough that is true, remember that Go doesn’t support co/contravariance on interface types. Defining interfaces around existing types works, but quickly falls apart as soon as methods return concrete types. In those cases you need to write more complex wrappers, which is often not worth the hassle.