From 7b9636e239ba2bb907071e3a4994b13f2510ed4d Mon Sep 17 00:00:00 2001 From: Pritesh Bandi Date: Thu, 14 Nov 2024 11:06:45 -0800 Subject: [PATCH] chore: Improve error message in case of plugin timeout (#472) When a plugin exceeds the specified timeout or deadline for content processing, the current error message displayed is ```signal: killed```. This PR updates the error message to a more informative message: ```[plugin_name] [command_name] command execution timeout: signal: killed``` --------- Signed-off-by: Pritesh Bandi --- plugin/plugin.go | 3 +++ plugin/plugin_test.go | 23 ++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/plugin/plugin.go b/plugin/plugin.go index 8b8959a3..d7f0a932 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -222,6 +222,9 @@ func (c execCommander) Output(ctx context.Context, name string, command plugin.C cmd.Stdout = &stdout err := cmd.Run() if err != nil { + if errors.Is(ctx.Err(), context.DeadlineExceeded) { + return nil, stderr.Bytes(), fmt.Errorf("'%s %s' command execution timeout: %w", name, string(command), err); + } return nil, stderr.Bytes(), err } return stdout.Bytes(), nil, nil diff --git a/plugin/plugin_test.go b/plugin/plugin_test.go index 171767b8..fc77d13a 100644 --- a/plugin/plugin_test.go +++ b/plugin/plugin_test.go @@ -19,9 +19,11 @@ import ( "errors" "os" "reflect" + "runtime" "strconv" "strings" "testing" + "time" "github.com/notaryproject/notation-go/plugin/proto" ) @@ -181,7 +183,7 @@ func TestValidateMetadata(t *testing.T) { } } -func TestNewCLIPlugin_PathError(t *testing.T) { +func TestNewCLIPlugin_Error(t *testing.T) { ctx := context.Background() t.Run("plugin directory exists without executable.", func(t *testing.T) { p, err := NewCLIPlugin(ctx, "emptyplugin", "./testdata/plugins/emptyplugin/notation-emptyplugin") @@ -203,6 +205,25 @@ func TestNewCLIPlugin_PathError(t *testing.T) { t.Errorf("NewCLIPlugin() plugin = %v, want nil", p) } }) + + t.Run("plugin timeout error", func(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on Windows") + } + expectedErrMsg := "'sleep 2' command execution timeout: signal: killed" + ctxWithTimout, cancel := context.WithTimeout(ctx, 10 * time.Millisecond) + defer cancel() + + var twoSeconds proto.Command + twoSeconds = "2" + _, _, err := execCommander{}.Output(ctxWithTimout, "sleep", twoSeconds, nil); + if err == nil { + t.Errorf("execCommander{}.Output() expected error = %v, got nil", expectedErrMsg) + } + if err.Error() != expectedErrMsg { + t.Errorf("execCommander{}.Output() error = %v, want %v", err, expectedErrMsg) + } + }) } func TestNewCLIPlugin_ValidError(t *testing.T) {