Skip to content

Commit 15781a9

Browse files
committed
identify context cancellation error in packages.loader.loadPackage
1 parent 533eb26 commit 15781a9

File tree

2 files changed

+66
-3
lines changed

2 files changed

+66
-3
lines changed

go/packages/packages.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ const (
324324
ListError
325325
ParseError
326326
TypeError
327+
ContextCancelError
327328
)
328329

329330
func (err Error) Error() string {
@@ -781,14 +782,23 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) {
781782

782783
default:
783784
// unexpected impoverished error from parser?
785+
errKind := UnknownError
786+
787+
// check if err from context
788+
if ld.Context.Err() != nil {
789+
errKind = ContextCancelError
790+
}
791+
784792
errs = append(errs, Error{
785793
Pos: "-",
786794
Msg: err.Error(),
787-
Kind: UnknownError,
795+
Kind: errKind,
788796
})
789797

790-
// If you see this error message, please file a bug.
791-
log.Printf("internal error: error %q (%T) without position", err, err)
798+
if errKind == UnknownError {
799+
// If you see this error message, please file a bug.
800+
log.Printf("internal error: error %q (%T) without position", err, err)
801+
}
792802
}
793803

794804
lpkg.Errors = append(lpkg.Errors, errs...)

go/packages/packages_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2121,6 +2121,59 @@ func testReturnErrorForUnexpectedDirectoryLayout(t *testing.T, exporter packages
21212121
}
21222122
}
21232123

2124+
func TestReturnErrorForContextCanceled(t *testing.T) {
2125+
packagestest.TestAll(t, testReturnErrorForContextCanceled)
2126+
}
2127+
2128+
type slowContext struct {
2129+
context.Context
2130+
delay time.Duration
2131+
}
2132+
2133+
func (ctx slowContext) Err() error {
2134+
time.Sleep(ctx.delay)
2135+
return ctx.Context.Err()
2136+
}
2137+
2138+
func testReturnErrorForContextCanceled(t *testing.T, exporter packagestest.Exporter) {
2139+
exported := packagestest.Export(t, exporter, []packagestest.Module{{
2140+
Name: "golang.org/fake",
2141+
Files: map[string]interface{}{
2142+
"a/a.go": `package a; const A = "a" `,
2143+
}}})
2144+
defer exported.Cleanup()
2145+
2146+
ctx, cancel := context.WithCancel(context.Background())
2147+
// we need to slow a Load function to be able to test ctx cancellation
2148+
// in the middle of loading packages
2149+
slowCtx := slowContext{ctx, 10 * time.Millisecond}
2150+
2151+
go func() {
2152+
// should have delay before canceling
2153+
// otherwise returns early with 'signal killed'
2154+
time.Sleep(8 * time.Millisecond)
2155+
cancel()
2156+
}()
2157+
2158+
exported.Config.Mode = packages.LoadAllSyntax
2159+
exported.Config.Context = slowCtx
2160+
pkgs, err := packages.Load(exported.Config, "golang.org/fake/a")
2161+
if err != nil {
2162+
t.Fatal(err)
2163+
}
2164+
// flaky test, because of timings
2165+
// sometimes Load returns early with err "signal: killed" when tested under Module
2166+
want := packages.ContextCancelError
2167+
if len(pkgs) > 0 {
2168+
errKind := pkgs[0].Errors[0].Kind
2169+
if want != errKind {
2170+
t.Fatalf("want error kind: %v, got: %v", want, errKind)
2171+
}
2172+
} else {
2173+
t.Fatal("unexpected no packages returned")
2174+
}
2175+
}
2176+
21242177
func TestMissingDependency(t *testing.T) { packagestest.TestAll(t, testMissingDependency) }
21252178
func testMissingDependency(t *testing.T, exporter packagestest.Exporter) {
21262179
exported := packagestest.Export(t, exporter, []packagestest.Module{{

0 commit comments

Comments
 (0)