From e6f0252c5d2515c75f2f9d21eaab49134c54dea4 Mon Sep 17 00:00:00 2001 From: CatalinSnyk Date: Mon, 10 Mar 2025 16:48:41 +0200 Subject: [PATCH] chore: add errors and a few tests --- cliv2/internal/cliv2/cliv2.go | 47 ++++++++++++---------- cliv2/internal/cliv2/cliv2_test.go | 64 ++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/cliv2/internal/cliv2/cliv2.go b/cliv2/internal/cliv2/cliv2.go index e212a27d36..c764a922c4 100644 --- a/cliv2/internal/cliv2/cliv2.go +++ b/cliv2/internal/cliv2/cliv2.go @@ -67,6 +67,12 @@ const ( ERROR_HAS_BEEN_DISPLAYED = "hasBeenDisplayed" ) +var ( + ErrIPCNoDataSent = errors.New("no data was sent through the IPC") + ErrIPCFailedToRead = errors.New("error while reading IPC file") + ErrIPCFailedToDeserialize = errors.New("error while deserializing IPC file") +) + func NewCLIv2(config configuration.Configuration, debugLogger *log.Logger, ri runtimeinfo.RuntimeInfo) (*CLI, error) { cacheDirectory := config.GetString(configuration.CACHE_PATH) @@ -461,56 +467,53 @@ func (c *CLI) executeV1Default(proxyInfo *proxy.ProxyInfo, passThroughArgs []str return ctx.Err() } - if err == nil { - return nil - } - - if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() < 2 { + sentErr, ipcErr := GetErrorFromFile(err, filePath, c.globalConfig) + if ipcErr != nil { + c.DebugLogger.Println(ipcErr.Error()) return err } - if sentErrs, fileErr := c.getErrorFromFile(filePath); fileErr == nil { - err = errors.Join(err, sentErrs) + return sentErr +} + +func GetErrorFromFile(execErr error, errFilePath string, config configuration.Configuration) (data error, ipcReadErr error) { + if execErr == nil { + return nil, nil } - return err -} + if exitErr, ok := execErr.(*exec.ExitError); ok && exitErr.ExitCode() < 2 { + return nil, nil + } -func (c *CLI) getErrorFromFile(errFilePath string) (data error, err error) { bytes, fileErr := os.ReadFile(errFilePath) if os.IsNotExist(fileErr) { - c.DebugLogger.Println("No data was sent through the IPC file.") - return nil, fileErr + return nil, ErrIPCNoDataSent } if fileErr != nil { - c.DebugLogger.Println("Failed to read error file: ", fileErr) - return nil, fileErr + return nil, fmt.Errorf("%w: %w", ErrIPCFailedToRead, fileErr) } jsonErrors, serErr := snyk_errors.FromJSONAPIErrorBytes(bytes) if serErr != nil { - c.DebugLogger.Println("Failed to deserialize file: ", serErr) - return nil, fileErr + return nil, fmt.Errorf("%w: %w", ErrIPCFailedToDeserialize, serErr) } if len(jsonErrors) != 0 { - hasBeenDisplayed := GetErrorDisplayStatus(c.globalConfig) + hasBeenDisplayed := GetErrorDisplayStatus(config) errs := make([]error, len(jsonErrors)+1) + errs = append(errs, execErr) for _, jerr := range jsonErrors { jerr.Meta["orign"] = "Typescript-CLI" jerr.Meta[ERROR_HAS_BEEN_DISPLAYED] = hasBeenDisplayed errs = append(errs, jerr) } - err = errors.Join(errs...) - c.DebugLogger.Println("Error file contained ", len(jsonErrors), " errors: ", err) - return err, nil + return errors.Join(errs...), nil } - c.DebugLogger.Println("The file didn't contain any errors") - return nil, errors.New("no errorrs were sent thought the error file") + return execErr, ErrIPCNoDataSent } func (c *CLI) Execute(proxyInfo *proxy.ProxyInfo, passThroughArgs []string) error { diff --git a/cliv2/internal/cliv2/cliv2_test.go b/cliv2/internal/cliv2/cliv2_test.go index cf608694e7..3065903176 100644 --- a/cliv2/internal/cliv2/cliv2_test.go +++ b/cliv2/internal/cliv2/cliv2_test.go @@ -14,6 +14,7 @@ import ( "testing" "time" + "github.com/snyk/error-catalog-golang-public/snyk_errors" "github.com/snyk/go-application-framework/pkg/app" "github.com/snyk/go-application-framework/pkg/configuration" "github.com/snyk/go-application-framework/pkg/local_workflows/output_workflow" @@ -587,3 +588,66 @@ func Test_GetErrorDisplayStatus(t *testing.T) { }) } } + +func Test_GetErrorFromFile(t *testing.T) { + // returns an ExitError instances with the specified exit code + getExitError := func(exitCode int) error { + var err error + command := fmt.Sprintf("exit %d", exitCode) + if runtime.GOOS == "windows" { + cmd := exec.Command("cmd", "/C", command) + err = cmd.Run() + } else { + cmd := exec.Command("sh", "-c", command) + err = cmd.Run() + } + + return err + } + + // Setup + jsonAPIErrorBytes := []byte(`{"jsonapi":{"version":"1.0"},"errors":[{"id":"1","links":{"about":"https://docs.snyk.io/scan-with-snyk/error-catalog#snyk-os-7001"},"status":"504","code":"SNYK-OS-7001","title":"Request to Snyk API timeout","detail":"connection is timedout","meta":{"links":["https://status.snyk.io/"],"isErrorCatalogError":true,"classification":"UNEXPECTED"}}]}`) + validFilePath := path.Join(t.TempDir(), "valid-err-file") + err := os.WriteFile(validFilePath, jsonAPIErrorBytes, 0664) + assert.Nil(t, err) + + notJsonBytes := []byte(`this is not a valid json`) + invalidFilePath := path.Join(t.TempDir(), "invalid-err-file") + err = os.WriteFile(invalidFilePath, notJsonBytes, 0664) + assert.Nil(t, err) + + // notFoundFilePath := path.Join(t.TempDir(), "not-found-file") + + jsonApiError, err := snyk_errors.FromJSONAPIErrorBytes(jsonAPIErrorBytes) + assert.Nil(t, err) + jsonAPIError := jsonApiError[0] + + config := configuration.NewWithOpts(configuration.WithAutomaticEnv()) + + t.Run("does not send error for exit code 0", func(t *testing.T) { + exitCodeErr := getExitError(0) + sentErr, err := cliv2.GetErrorFromFile(exitCodeErr, validFilePath, config) + + assert.Nil(t, sentErr) + assert.Nil(t, err) + }) + + t.Run("does not send error for exit code 1", func(t *testing.T) { + exitCodeErr := getExitError(1) + sentErr, err := cliv2.GetErrorFromFile(exitCodeErr, validFilePath, config) + + assert.Nil(t, sentErr) + assert.Nil(t, err) + }) + + t.Run("sends error for exit code 2", func(t *testing.T) { + exitCodeErr := getExitError(2) + sentErr, err := cliv2.GetErrorFromFile(exitCodeErr, validFilePath, config) + + snykErr := snyk_errors.Error{} + assert.ErrorIs(t, sentErr, exitCodeErr) + assert.ErrorAs(t, sentErr, &snykErr) + assert.Equal(t, snykErr.ErrorCode, jsonAPIError.ErrorCode) + assert.Nil(t, err) + }) +}