英文:
Goconvey causing panic with go routine on Jenkins
问题
我有一组使用GoConvey和Go 1.3.1的测试,在本地运行得很好。但是当我使用Jenkins触发构建时,也是使用Go 1.3.1,我会从Goconvey中得到一个与我在测试中使用的goroutine相关的panic错误。
这里是测试代码:
func TestListApplication(t *testing.T) {
s := &Session{}
s.Username = "foo"
s.Password = "bar"
ts := serveHTTP(t)
defer ts.Close()
s.Baseurl = ts.URL
s.initialize()
go func() {
<-s.Comms.AppCount
}()
Convey("TestListApplication", t, func() {
s.Comms.MainWaitGroup.Add(1)
application := &Application{}
err := json.Unmarshal(applicationJSON(), application)
So(err, ShouldBeNil)
revisions := &Revisions{}
err = json.Unmarshal(revisionsJSON(), revisions)
So(err, ShouldBeNil)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
line := <-s.Comms.Msg
So(line, ShouldEqual, "3 admin foo\n")
}()
s.listApplication(application, revisions)
wg.Wait()
})
}
这里是错误信息:
86 assertions thus far
..
88 assertions thus far
panic: Convey operation made without context on goroutine stack.
Hint: Perhaps you meant to use `Convey(..., func(c C){...})` ?
goroutine 115 [running]:
runtime.panic(0x350d80, 0xc208083050)
/Users/administrator/jenkins/tools/org.jenkinsci.plugins.golang.GolangInstallation/1.3.1/src/pkg/runtime/panic.c:279 +0xf5
github.com/smartystreets/goconvey/convey.conveyPanic(0x4960d0, 0x78, 0x0, 0x0, 0x0)
/Users/administrator/jenkins/workspace/tropoCLI/golang/src/github.com/smartystreets/goconvey/convey/context.go:20 +0x6a
github.com/smartystreets/goconvey/convey.mustGetCurrentContext(0x5ecea0)
/Users/administrator/jenkins/workspace/tropoCLI/golang/src/github.com/smartystreets/goconvey/convey/context.go:52 +0x57
github.com/smartystreets/goconvey/convey.So(0x2d78e0, 0xc208001e80, 0x48f210, 0xc208001e60, 0x1, 0x1)
/Users/administrator/jenkins/workspace/tropoCLI/golang/src/github.com/smartystreets/goconvey/convey/doc.go:123 +0x1e
_/Users/administrator/jenkins/workspace/tropoCLI.func·048()
/Users/administrator/jenkins/workspace/tropoCLI/tropoCLI_test.go:222 +0x17d
created by _/Users/administrator/jenkins/workspace/tropoCLI.func·049
/Users/administrator/jenkins/workspace/tropoCLI/tropoCLI_test.go:223 +0x398
goroutine 16 [chan receive]:
testing.RunTests(0x48f340, 0x5ed680, 0x29, 0x29, 0x48f701)
/Users/administrator/jenkins/tools/org.jenkinsci.plugins.golang.GolangInstallation/1.3.1/src/pkg/testing/testing.go:505 +0x923
testing.Main(0x48f340, 0x5ed680, 0x29, 0x29, 0x5f5b40, 0x0, 0x0, 0x5f5b40, 0x0, 0x0)
/Users/administrator/jenkins/tools/org.jenkinsci.plugins.golang.GolangInstallation/1.3.1/src/pkg/testing/testing.go:435 +0x84
main.main()
_/Users/administrator/jenkins/workspace/tropoCLI/_test/_testmain.go:127 +0x9c
希望对你有所帮助!
英文:
I have a set of test that use GoConvey with Go 1.3.1 that work just fine locally. But when I trigger a build with Jenkins, with the Go 1.3.1 as well, I get a panic from Goconvey related to a go routine I use in my test.
The test may be seen here:
func TestListApplication(t *testing.T) {
s := &Session{}
s.Username = "foo"
s.Password = "bar"
ts := serveHTTP(t)
defer ts.Close()
s.Baseurl = ts.URL
s.initialize()
go func() {
<-s.Comms.AppCount
}()
Convey("TestListApplication", t, func() {
s.Comms.MainWaitGroup.Add(1)
application := &Application{}
err := json.Unmarshal(applicationJSON(), application)
So(err, ShouldBeNil)
revisions := &Revisions{}
err = json.Unmarshal(revisionsJSON(), revisions)
So(err, ShouldBeNil)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
line := <-s.Comms.Msg
So(line, ShouldEqual, "3 admin foo\n")
}()
s.listApplication(application, revisions)
wg.Wait()
})
}
The error here:
86 assertions thus far
..
88 assertions thus far
panic: Convey operation made without context on goroutine stack.
Hint: Perhaps you meant to use `Convey(..., func(c C){...})` ?
goroutine 115 [running]:
runtime.panic(0x350d80, 0xc208083050)
/Users/administrator/jenkins/tools/org.jenkinsci.plugins.golang.GolangInstallation/1.3.1/src/pkg/runtime/panic.c:279 +0xf5
github.com/smartystreets/goconvey/convey.conveyPanic(0x4960d0, 0x78, 0x0, 0x0, 0x0)
/Users/administrator/jenkins/workspace/tropoCLI/golang/src/github.com/smartystreets/goconvey/convey/context.go:20 +0x6a
github.com/smartystreets/goconvey/convey.mustGetCurrentContext(0x5ecea0)
/Users/administrator/jenkins/workspace/tropoCLI/golang/src/github.com/smartystreets/goconvey/convey/context.go:52 +0x57
github.com/smartystreets/goconvey/convey.So(0x2d78e0, 0xc208001e80, 0x48f210, 0xc208001e60, 0x1, 0x1)
/Users/administrator/jenkins/workspace/tropoCLI/golang/src/github.com/smartystreets/goconvey/convey/doc.go:123 +0x1e
_/Users/administrator/jenkins/workspace/tropoCLI.func·048()
/Users/administrator/jenkins/workspace/tropoCLI/tropoCLI_test.go:222 +0x17d
created by _/Users/administrator/jenkins/workspace/tropoCLI.func·049
/Users/administrator/jenkins/workspace/tropoCLI/tropoCLI_test.go:223 +0x398
goroutine 16 [chan receive]:
testing.RunTests(0x48f340, 0x5ed680, 0x29, 0x29, 0x48f701)
/Users/administrator/jenkins/tools/org.jenkinsci.plugins.golang.GolangInstallation/1.3.1/src/pkg/testing/testing.go:505 +0x923
testing.Main(0x48f340, 0x5ed680, 0x29, 0x29, 0x5f5b40, 0x0, 0x0, 0x5f5b40, 0x0, 0x0)
/Users/administrator/jenkins/tools/org.jenkinsci.plugins.golang.GolangInstallation/1.3.1/src/pkg/testing/testing.go:435 +0x84
main.main()
_/Users/administrator/jenkins/workspace/tropoCLI/_test/_testmain.go:127 +0x9c
答案1
得分: 11
因为您正在尝试从另一个goroutine执行断言,所以您需要在func()
签名中使用最近添加的上下文结构体(C
),然后从该上下文调用So
。这是稍作修改的版本:
Convey("TestListApplication", t, func(c C) {
s.Comms.MainWaitGroup.Add(1)
application := &Application{}
err := json.Unmarshal(applicationJSON(), application)
So(err, ShouldBeNil)
revisions := &Revisions{}
err = json.Unmarshal(revisionsJSON(), revisions)
So(err, ShouldBeNil)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
line := <-s.Comms.Msg
c.So(line, ShouldEqual, "3 admin foo\n")
}()
s.listApplication(application, revisions)
wg.Wait()
})
这是请求 #264的结果。
英文:
Because you are trying to perform an assertion from another goroutine, you'll need to make use of the recently added context struct (C
) in the func()
signature, then call So
off of that context. Here's your version with a slight modification:
Convey("TestListApplication", t, func(c C) {
s.Comms.MainWaitGroup.Add(1)
application := &Application{}
err := json.Unmarshal(applicationJSON(), application)
So(err, ShouldBeNil)
revisions := &Revisions{}
err = json.Unmarshal(revisionsJSON(), revisions)
So(err, ShouldBeNil)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
line := <-s.Comms.Msg
c.So(line, ShouldEqual, "3 admin foo\n")
}()
s.listApplication(application, revisions)
wg.Wait()
})
This was a result of pull request #264.
答案2
得分: 0
这个异常是由context.go#mustGetCurrentContext()
引发的。你可以在story_conventions_test.go#TestFailureModeNoContext
中看到触发相同异常的测试。
Convey("Foo", t, func() {
done := make(chan int, 1)
go func() {
defer func() { done <- 1 }()
defer expectPanic(t, noStackContext)
So(len("I have no context"), ShouldBeGreaterThan, 0)
}()
<-done
})
从测试示例中可以看出,如果在Convey测试中从一个goroutine中调用另一个goroutine,可能会触发无上下文的panic。
由于Jenkins是从一个goroutine中启动测试,这可能解释了为什么你的GoConvey测试失败(即使在直接调用go test
时,在Jenkins之外运行时是正常的)。
英文:
This exception is launched by context.go#mustGetCurrentContext()
.
you can see a test triggering that same exception in story_conventions_test.go#TestFailureModeNoContext
Convey("Foo", t, func() {
done := make(chan int, 1)
go func() {
defer func() { done <- 1 }()
defer expectPanic(t, noStackContext)
So(len("I have no context"), ShouldBeGreaterThan, 0)
}()
<-done
})
From the test example, if seems that calling a goroutine from within a goroutine from within a Convey test would trigger the no context panic.
Since Jenkins launches the tests from a goroutine, that might explain why your GoConvey test fails (even though it runs when you are calling go test
directly, outside of Jenkins)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论