Why does Go test with blocked channel not reporting deadlock
Asked Answered
L

0

6

I met a strange issue when doing test with channels.

In a normal main function, the following code will report the deadlock error.

package main

import (
    "fmt"
)

func main() {
    c := make(chan int)
    c <- 1
    fmt.Println(<-c)
}

But on my machine, this simple test seems deadlocked or blocked forever or just fails to exit for whatever reason I don't know. I invoked the test in both Emacs and terminal, and I got the same result. The command is go test -run TestChan\$ . -v -count=1. I tried with a simpler command (go test -run TestChan) but still got the same result. I tried it on Go playground (here) and it reported the deadlock error. Is there something wrong with my Go environment?

package main

import (
    "fmt"
    "testing"
)

func TestChan(t *testing.T) {
    c := make(chan int)
    c <- 1
    fmt.Println(<-c)
}

----------------------------------------------------------------------------------------------------

Update

Looks like I haven't made my question clear. The situation is: the same test behaves differently on my machine and on Go playground. Now I set -timeout 5s, but the error message is different from that on Go playground. Another thing I found different with my local is that the test runner seems different from my local. It's under package go-faketime.

local output

$ go test main_test.go -timeout 5s
panic: test timed out after 5s

goroutine 17 [running]:
testing.(*M).startAlarm.func1()
    /usr/local/go/src/testing/testing.go:1460 +0xdf
created by time.goFunc
    /usr/local/go/src/time/sleep.go:168 +0x44

goroutine 1 [chan receive]:
testing.(*T).Run(0xc000108120, 0x1141975, 0x8, 0x114a528, 0x1075a96)
    /usr/local/go/src/testing/testing.go:1044 +0x37e
testing.runTests.func1(0xc000108000)
    /usr/local/go/src/testing/testing.go:1285 +0x78
testing.tRunner(0xc000108000, 0xc000066e10)
    /usr/local/go/src/testing/testing.go:992 +0xdc
testing.runTests(0xc00000c060, 0x1236220, 0x1, 0x1, 0x0)
    /usr/local/go/src/testing/testing.go:1283 +0x2a7
testing.(*M).Run(0xc000106000, 0x0)
    /usr/local/go/src/testing/testing.go:1200 +0x15f
main.main()
    _testmain.go:44 +0x135

goroutine 6 [chan send]:
command-line-arguments.TestChan(0xc000108120)
    /Users/james/prog/allez/mtest/main_test.go:10 +0x59
testing.tRunner(0xc000108120, 0x114a528)
    /usr/local/go/src/testing/testing.go:992 +0xdc
created by testing.(*T).Run
    /usr/local/go/src/testing/testing.go:1043 +0x357
FAIL    command-line-arguments  5.013s
FAIL

Go playground output

=== RUN   TestChan
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
testing.(*T).Run(0xc00011a120, 0x4f71c0, 0x8, 0x4ff688, 0x498336)
    /usr/local/go-faketime/src/testing/testing.go:1043 +0x37e
testing.runTests.func1(0xc00011a000)
    /usr/local/go-faketime/src/testing/testing.go:1284 +0x78
testing.tRunner(0xc00011a000, 0xc000066df8)
    /usr/local/go-faketime/src/testing/testing.go:991 +0xdc
testing.runTests(0xc00010c040, 0xc00010c020, 0x1, 0x1, 0x0)
    /usr/local/go-faketime/src/testing/testing.go:1282 +0x2a7
testing.(*M).Run(0xc000118000, 0x0)
    /usr/local/go-faketime/src/testing/testing.go:1199 +0x15f
testing.Main(0x4ff690, 0xc00010c020, 0x1, 0x1, 0x0, 0x0, 0x0, 0x5e8860, 0x0, 0x0)
    /usr/local/go-faketime/src/testing/testing.go:1126 +0xd4
main.main()
    /tmp/sandbox970213620/prog.go:24 +0x9c

goroutine 18 [chan send]:
main.TestChan(0xc00011a120)
    /tmp/sandbox970213620/prog.go:10 +0x59
testing.tRunner(0xc00011a120, 0x4ff688)
    /usr/local/go-faketime/src/testing/testing.go:991 +0xdc
created by testing.(*T).Run
    /usr/local/go-faketime/src/testing/testing.go:1042 +0x357

My questions are

  • Why does Go test with blocked channel not reporting deadlock?
  • If it's work-as-design (because there are other goroutines running meanwhile), then how does the same test in Go playground reports the same error message as if the code is run in a main func? (this question diverges from the domain of Go channel to how Go Playground handles test)
Lowminded answered 15/5, 2020 at 14:30 Comment(7)
If you are running go test, there are other goroutines running, hence no deadlock. Compile and run the binary itself.Larder
FTR: the test will fail after 10 minutes. This timeout can be changed with the -timeout flag.Lied
thank you @Larder for your comment. I updated my question.Lowminded
thank you @Lied for your comment. I updated my question.Lowminded
The update doesn’t change anything, you’re still running go test while the playground is not. Build and run the main binary.Larder
@Larder Yes. I'm running go test. That's where my questions arose. I know running the main binary will report the deadlock message. btw, do you know whether the Go playground is actually building and running the main binary for tests?Lowminded
Yes, the playground is compiling the test binary and running that directly, not under the go test command. Whether a deadlock is reported or not is not really interesting, as deadlocks can only be detected in basic cases; detecting a deadlock in any sufficiently complex program is akin to solving the halting problem.Larder

© 2022 - 2024 — McMap. All rights reserved.