Skip to content

Adding distinct error codes for custom test failures #5501

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 10, 2021
168 changes: 140 additions & 28 deletions docs/content/en/api/skaffold.swagger.json

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions docs/content/en/docs/references/api/grpc.md
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,14 @@ For Cancelled Error code, use range 800 to 850.<br>
| TEST_USER_CONFIG_ERR | 1101 | Error expanding paths |
| TEST_CST_USER_ERR | 1102 | Error running container-structure-test |
| TEST_IMG_PULL_ERR | 1103 | Unable to docker pull image |
| TEST_CT_USER_ERR | 1104 | Error running custom test |
| TEST_CT_CMD_PARSE_ERR | 1105 | Unable to parse test command |
| TEST_CT_CMD_NON_ZERO_EXIT_ERR | 1106 | Command returned non-zero exit code |
| TEST_CT_CMD_TIMEDOUT_OR_CANCELLED_ERR | 1107 | command cancelled or timed out |
| TEST_CT_CMD_EXITED_ERR | 1108 | command exited |
| TEST_CT_CMD_RUN_ERR | 1110 | error running cmd |
| TEST_CT_DEPS_CMD_ERR | 1111 | Error getting dependencies from command |
| TEST_CT_DEPS_UNMARSHALL_ERR | 1112 | Unmarshalling dependency output error |



Expand Down
18 changes: 8 additions & 10 deletions pkg/skaffold/test/custom/custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package custom
import (
"context"
"encoding/json"
"fmt"
"io"
"os/exec"
"runtime"
Expand Down Expand Up @@ -54,7 +53,7 @@ func New(cfg docker.Config, wd string, ct latest.CustomTest) (*Runner, error) {
// Test is the entrypoint for running custom tests
func (ct *Runner) Test(ctx context.Context, out io.Writer, _ []build.Artifact) error {
if err := doRunCustomCommand(ctx, out, ct.customTest); err != nil {
return fmt.Errorf("running custom test command: %w", err)
return cutomTestErr(err)
}

return nil
Expand All @@ -64,7 +63,7 @@ func runCustomCommand(ctx context.Context, out io.Writer, test latest.CustomTest
// Expand command
command, err := util.ExpandEnvTemplate(test.Command, nil)
if err != nil {
return fmt.Errorf("unable to parse test command %q: %w", test.Command, err)
return parsingTestCommandErr(test.Command, err)
}

if test.TimeoutSeconds <= 0 {
Expand Down Expand Up @@ -93,7 +92,7 @@ func runCustomCommand(ctx context.Context, out io.Writer, test latest.CustomTest
// If the process exited by itself, just return the error
if e.Exited() {
color.Red.Fprintf(out, "Command finished with non-0 exit code.\n")
return fmt.Errorf("command finished with non-0 exit code: %w", e)
return commandNonZeroExitErr(err)
}
// If the context is done, it has been killed by the exec.Command
select {
Expand All @@ -103,12 +102,12 @@ func runCustomCommand(ctx context.Context, out io.Writer, test latest.CustomTest
} else if ctx.Err() == context.Canceled {
color.Red.Fprintf(out, "Command cancelled\n")
}
return ctx.Err()
return commandExecutionCancelledOrTimedoutErr(ctx.Err())
default:
return e
return commandExited(e)
}
}
return err
return runCmdErr(err)
}
color.Green.Fprintf(out, "Command finished successfully\n")

Expand All @@ -118,7 +117,6 @@ func runCustomCommand(ctx context.Context, out io.Writer, test latest.CustomTest
// TestDependencies returns dependencies listed for a custom test
func (ct *Runner) TestDependencies() ([]string, error) {
test := ct.customTest
// var set orderedFileSet

if test.Dependencies != nil {
switch {
Expand All @@ -133,11 +131,11 @@ func (ct *Runner) TestDependencies() ([]string, error) {

output, err := util.RunCmdOut(cmd)
if err != nil {
return nil, fmt.Errorf("getting dependencies from command: %q: %w", test.Dependencies.Command, err)
return nil, gettingDependenciesCommandErr(test.Dependencies.Command, err)
}
var deps []string
if err := json.Unmarshal(output, &deps); err != nil {
return nil, fmt.Errorf("unmarshalling dependency output into string array: %w", err)
return nil, dependencyOutputUnmarshallErr(err)
}
return deps, nil

Expand Down
96 changes: 96 additions & 0 deletions pkg/skaffold/test/custom/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
Copyright 2021 The Skaffold Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package custom

import (
"fmt"

sErrors "github.com/GoogleContainerTools/skaffold/pkg/skaffold/errors"
"github.com/GoogleContainerTools/skaffold/proto/v1"
)

func cutomTestErr(err error) error {
return sErrors.NewError(err,
proto.ActionableErr{
Message: fmt.Sprintf("running custom test command: %s", err),
ErrCode: proto.StatusCode_TEST_CT_USER_ERR,
},
)
}

func parsingTestCommandErr(command string, err error) error {
return sErrors.NewError(err,
proto.ActionableErr{
Message: fmt.Sprintf("unable to parse test command %s: %s", command, err),
ErrCode: proto.StatusCode_TEST_CT_CMD_PARSE_ERR,
},
)
}

func commandNonZeroExitErr(err error) error {
return sErrors.NewError(err,
proto.ActionableErr{
Message: fmt.Sprintf("command finished with non-0 exit code: %s", err),
ErrCode: proto.StatusCode_TEST_CT_CMD_NON_ZERO_EXIT_ERR,
},
)
}

func commandExecutionCancelledOrTimedoutErr(err error) error {
return sErrors.NewError(err,
proto.ActionableErr{
Message: fmt.Sprintf("command cancelled or timed out: %s", err),
ErrCode: proto.StatusCode_TEST_CT_CMD_TIMEDOUT_OR_CANCELLED_ERR,
},
)
}

func commandExited(err error) error {
return sErrors.NewError(err,
proto.ActionableErr{
Message: fmt.Sprintf("command exited: %s", err),
ErrCode: proto.StatusCode_TEST_CT_CMD_EXITED_ERR,
},
)
}

func runCmdErr(err error) error {
return sErrors.NewError(err,
proto.ActionableErr{
Message: fmt.Sprintf("error running cmd: %s", err),
ErrCode: proto.StatusCode_TEST_CT_CMD_RUN_ERR,
},
)
}

func gettingDependenciesCommandErr(command string, err error) error {
return sErrors.NewError(err,
proto.ActionableErr{
Message: fmt.Sprintf("getting dependencies from command: %s: %s", command, err),
ErrCode: proto.StatusCode_TEST_CT_DEPS_CMD_ERR,
},
)
}

func dependencyOutputUnmarshallErr(err error) error {
return sErrors.NewError(err,
proto.ActionableErr{
Message: fmt.Sprintf("unmarshalling dependency output into string array: %s", err),
ErrCode: proto.StatusCode_TEST_CT_DEPS_UNMARSHALL_ERR,
},
)
}
Loading