Hi Amnon, Thank you for your suggestion. I have taken a look at the package but it does not seem to really work. It seems to rely on runtime.Gosched() to suspend the current go routine until all other go routines are blocked. That is, it relies on runtime.Gosched() to provide functionality similar to what I wanted with the fictional runtime.registerDeadlockCallback function.
However, runtime.Gosched() is not documented to do that. Also, I confirmed with a test that it also does not do that in practice. Here is what I did for anyone interested. I ran this program based on the example from https://github.com/facebookarchive/clock: package main import ( "fmt" "runtime" "time" "github.com/facebookarchive/clock" ) func main() { mock := clock.NewMock() count := 0 // Kick off a timer to increment every 1 mock second. go func() { ticker := mock.Ticker(1 * time.Second) for { <-ticker.C count++ // New code inserted by me to use CPU: j := rand.Int() for i := 1; i < 10000000; i++ { j++ } fmt.Printf("Value: %v\n", j) } }() runtime.Gosched() // Move the clock forward 10 second. mock.Add(10 * time.Second) // This prints 10. fmt.Println(count) } Now, with my modification the program no longer prints 10. For me it printed: Value: 9999999 Value: 9999999 Value: 9999999 4 Best, Christian On Thu, Jan 28, 2021 at 10:34 PM Amnon <amno...@gmail.com> wrote: > Try something like > github.com/facebookgo/clock > > > On Thursday, 28 January 2021 at 21:15:50 UTC Christian Worm Mortensen > wrote: > >> Hi! >> >> Suppose I want to unit test this function: >> >> func generator() <-chan int { >> ret := make(chan int) >> go func() { >> for i := 0; i < 10; i++ { >> ret <- i >> time.Sleep(time.Second) >> } >> }() >> return ret >> } >> >> What is a good way to do that? One way is to do it is like this: >> >> func testGenerator() { >> start := time.Now() >> g := generator() >> for i := 0; i < 10; i++ { >> v := <-g >> if v != i { >> panic("Wrong value") >> } >> } >> elapsed := time.Now().Sub(start) >> if elapsed < 9*time.Second || elapsed > 11*time.Second { >> panic("Wrong execution time") >> } >> } >> >> However there are several issues with this: >> >> 1) The unit test takes a long time to run - 10 seconds. >> 2) The unit test is fragile to fluctuations in CPU availability >> 3) The unit test is not very accurate >> >> Of course this is a simple example. But what if I want to test a >> complicated piece of code with many go routines interacting in complicated >> ways and with long timeouts? >> >> In other programming languages, I have been able to implement a form of >> virtual time which increases only when all threads are waiting for time to >> increase. This allows functions like generator above to be tested basically >> instantly and this has been extremely useful for me in many projects over >> the years. >> >> Can I do something similar in Go? I would expect I would need to wrap >> time.Now, time.Sleep and time.After which I will be happy to do. >> >> I can see that Go has a deadlock detector. If somehow it was possible to >> have Go start a new Go routine when a deadlock was detected, I think it >> would be pretty straight forward to implement virtual time as described. I >> could then do something like: >> >> runtime.registerDeadlockCallback(func () { >> // Increase virtual time and by that: >> // * Make one or more wrapped time.Sleep calls return or >> // * Write to one or more channels returned by wrapped time.After. >> }) >> >> Obviously this would only be needed for test code, not production code. >> >> Thanks, >> >> Christian >> > -- > You received this message because you are subscribed to a topic in the > Google Groups "golang-nuts" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/golang-nuts/Y9Ccen0uMcs/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > golang-nuts+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/d58a4e2a-eead-4ec9-b9a9-c0a43a699e89n%40googlegroups.com > <https://groups.google.com/d/msgid/golang-nuts/d58a4e2a-eead-4ec9-b9a9-c0a43a699e89n%40googlegroups.com?utm_medium=email&utm_source=footer> > . > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CABTkUoakmJWkCbBkC2%3Ddu96gPN%2BGQ9ODQibQTVJXnChWBcqGPg%40mail.gmail.com.