Skip to content

Commit

Permalink
GIT-141: enable panic handlers for ensuring Finish Steps
Browse files Browse the repository at this point in the history
  • Loading branch information
harshanarayana committed Jun 9, 2022
1 parent e93ce38 commit 50d84f2
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 69 deletions.
38 changes: 25 additions & 13 deletions pkg/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,26 +336,38 @@ func (e *testEnv) Run(m *testing.M) int {
setups := e.getSetupActions()
// fail fast on setup, upon err exit
var err error

defer func() {
// Recover and see if the panic handler is disabled. If it is disabled, panic and stop the workflow.
// Otherwise, log and continue with running the Finish steps of the Test suite
rErr := recover()
if rErr != nil {
if e.cfg.DisableGracefulTeardown() {
panic(rErr)
}
klog.Error("Recovering from panic and running finish actions", rErr)
}

finishes := e.getFinishActions()
// attempt to gracefully clean up.
// Upon error, log and continue.
for _, fin := range finishes {
// context passed down to each finish step
if e.ctx, err = fin.run(e.ctx, e.cfg); err != nil {
klog.V(2).ErrorS(err, "Finish action handlers")
}
}
}()

for _, setup := range setups {
// context passed down to each setup
if e.ctx, err = setup.run(e.ctx, e.cfg); err != nil {
klog.Fatal(err)
}
}

exitCode := m.Run() // exec test suite

finishes := e.getFinishActions()
// attempt to gracefully clean up.
// Upon error, log and continue.
for _, fin := range finishes {
// context passed down to each finish step
if e.ctx, err = fin.run(e.ctx, e.cfg); err != nil {
klog.V(2).ErrorS(err, "Finish action handlers")
}
}

return exitCode
// Execute the test suite
return m.Run()
}

func (e *testEnv) getActionsByRole(r actionRole) []action {
Expand Down
39 changes: 27 additions & 12 deletions pkg/envconf/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,19 @@ import (

// Config represents and environment configuration
type Config struct {
client klient.Client
kubeconfig string
namespace string
assessmentRegex *regexp.Regexp
featureRegex *regexp.Regexp
labels map[string]string
skipFeatureRegex *regexp.Regexp
skipLabels map[string]string
skipAssessmentRegex *regexp.Regexp
parallelTests bool
dryRun bool
failFast bool
client klient.Client
kubeconfig string
namespace string
assessmentRegex *regexp.Regexp
featureRegex *regexp.Regexp
labels map[string]string
skipFeatureRegex *regexp.Regexp
skipLabels map[string]string
skipAssessmentRegex *regexp.Regexp
parallelTests bool
dryRun bool
failFast bool
disableGracefulTeardown bool
}

// New creates and initializes an empty environment configuration
Expand Down Expand Up @@ -83,6 +84,7 @@ func NewFromFlags() (*Config, error) {
e.parallelTests = envFlags.Parallel()
e.dryRun = envFlags.DryRun()
e.failFast = envFlags.FailFast()
e.disableGracefulTeardown = envFlags.DisableGracefulTeardown()

return e, nil
}
Expand Down Expand Up @@ -259,6 +261,19 @@ func (c *Config) FailFast() bool {
return c.failFast
}

// WithDisableGracefulTeardown can be used to programmatically disabled the panic
// recovery enablement on test startup. This will prevent test Finish steps
// from being executed on panic
func (c *Config) WithDisableGracefulTeardown() *Config {
c.disableGracefulTeardown = true
return c
}

// DisableGracefulTeardown is used to check the panic recovery handler should be enabled
func (c *Config) DisableGracefulTeardown() bool {
return c.disableGracefulTeardown
}

func randNS() string {
return RandomName("testns-", 32)
}
Expand Down
12 changes: 12 additions & 0 deletions pkg/envconf/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,15 @@ func TestConfig_New_WithFailFastAndIgnoreFinalize(t *testing.T) {
t.Error("expected fail-fast mode to be enabled when -fail-fast argument is passed")
}
}

func TestConfig_New_WithIgnorePanicRecovery(t *testing.T) {
flag.CommandLine = &flag.FlagSet{}
os.Args = []string{"test-binary", "-disable-graceful-teardown"}
cfg, err := NewFromFlags()
if err != nil {
t.Error("failed to parse args", err)
}
if !cfg.DisableGracefulTeardown() {
t.Error("expected ignore-panic-recovery mode to be enabled when -disable-graceful-teardown argument is passed")
}
}
103 changes: 60 additions & 43 deletions pkg/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,18 @@ import (
)

const (
flagNamespaceName = "namespace"
flagKubecofigName = "kubeconfig"
flagFeatureName = "feature"
flagAssessName = "assess"
flagLabelsName = "labels"
flagSkipLabelName = "skip-labels"
flagSkipFeatureName = "skip-features"
flagSkipAssessmentName = "skip-assessment"
flagParallelTestsName = "parallel"
flagDryRunName = "dry-run"
flagFailFast = "fail-fast"
flagNamespaceName = "namespace"
flagKubecofigName = "kubeconfig"
flagFeatureName = "feature"
flagAssessName = "assess"
flagLabelsName = "labels"
flagSkipLabelName = "skip-labels"
flagSkipFeatureName = "skip-features"
flagSkipAssessmentName = "skip-assessment"
flagParallelTestsName = "parallel"
flagDryRunName = "dry-run"
flagFailFast = "fail-fast"
flagDisableGracefulTeardown = "disable-graceful-teardown"
)

// Supported flag definitions
Expand Down Expand Up @@ -81,26 +82,30 @@ var (
Name: flagDryRunName,
Usage: "Run Test suite in dry-run mode. This will list the tests to be executed without actually running them",
}

failFastFlag = flag.Flag{
Name: flagFailFast,
Usage: "Fail immediately and stop running untested code",
}
disableGracefulTeardownFlag = flag.Flag{
Name: flagDisableGracefulTeardown,
Usage: "Ignore panic recovery while running tests. This will prevent test finish steps from getting executed on panic",
}
)

// EnvFlags surfaces all resolved flag values for the testing framework
type EnvFlags struct {
feature string
assess string
labels LabelsMap
kubeconfig string
namespace string
skiplabels LabelsMap
skipFeatures string
skipAssessments string
parallelTests bool
dryRun bool
failFast bool
feature string
assess string
labels LabelsMap
kubeconfig string
namespace string
skiplabels LabelsMap
skipFeatures string
skipAssessments string
parallelTests bool
dryRun bool
failFast bool
disableGracefulTeardown bool
}

// Feature returns value for `-feature` flag
Expand Down Expand Up @@ -164,6 +169,12 @@ func (f *EnvFlags) FailFast() bool {
return f.failFast
}

// DisableGracefulTeardown is used to indicate that the panic handlers should not be registered while
// starting the test execution. This will prevent the test Finish steps from getting executed
func (f *EnvFlags) DisableGracefulTeardown() bool {
return f.disableGracefulTeardown
}

// Parse parses defined CLI args os.Args[1:]
func Parse() (*EnvFlags, error) {
return ParseArgs(os.Args[1:])
Expand All @@ -173,15 +184,16 @@ func Parse() (*EnvFlags, error) {
// and returns a set of environment flag values.
func ParseArgs(args []string) (*EnvFlags, error) {
var (
feature string
assess string
namespace string
kubeconfig string
skipFeature string
skipAssessment string
parallelTests bool
dryRun bool
failFast bool
feature string
assess string
namespace string
kubeconfig string
skipFeature string
skipAssessment string
parallelTests bool
dryRun bool
failFast bool
disableGracefulTeardown bool
)

labels := make(LabelsMap)
Expand Down Expand Up @@ -231,6 +243,10 @@ func ParseArgs(args []string) (*EnvFlags, error) {
flag.BoolVar(&failFast, failFastFlag.Name, false, failFastFlag.Usage)
}

if flag.Lookup(disableGracefulTeardownFlag.Name) == nil {
flag.BoolVar(&disableGracefulTeardown, disableGracefulTeardownFlag.Name, false, disableGracefulTeardownFlag.Usage)
}

// Enable klog/v2 flag integration
klog.InitFlags(nil)

Expand All @@ -249,17 +265,18 @@ func ParseArgs(args []string) (*EnvFlags, error) {
}

return &EnvFlags{
feature: feature,
assess: assess,
labels: labels,
namespace: namespace,
kubeconfig: kubeconfig,
skiplabels: skipLabels,
skipFeatures: skipFeature,
skipAssessments: skipAssessment,
parallelTests: parallelTests,
dryRun: dryRun,
failFast: failFast,
feature: feature,
assess: assess,
labels: labels,
namespace: namespace,
kubeconfig: kubeconfig,
skiplabels: skipLabels,
skipFeatures: skipFeature,
skipAssessments: skipAssessment,
parallelTests: parallelTests,
dryRun: dryRun,
failFast: failFast,
disableGracefulTeardown: disableGracefulTeardown,
}, nil
}

Expand Down
6 changes: 5 additions & 1 deletion pkg/flags/flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestParseFlags(t *testing.T) {
}{
{
name: "with all",
args: []string{"-assess", "volume test", "--feature", "beta", "--labels", "k0=v0, k1=v1, k2=v2", "--skip-labels", "k0=v0, k1=v1", "-skip-features", "networking", "-skip-assessment", "volume test", "-parallel", "--dry-run"},
args: []string{"-assess", "volume test", "--feature", "beta", "--labels", "k0=v0, k1=v1, k2=v2", "--skip-labels", "k0=v0, k1=v1", "-skip-features", "networking", "-skip-assessment", "volume test", "-parallel", "--dry-run", "--disable-graceful-teardown"},
flags: &EnvFlags{assess: "volume test", feature: "beta", labels: LabelsMap{"k0": "v0", "k1": "v1", "k2": "v2"}, skiplabels: LabelsMap{"k0": "v0", "k1": "v1"}, skipFeatures: "networking", skipAssessments: "volume test"},
},
}
Expand Down Expand Up @@ -76,6 +76,10 @@ func TestParseFlags(t *testing.T) {
if !testFlags.DryRun() {
t.Errorf("unmatched flag parsed. Expected dryRun to be true.")
}

if !testFlags.DisableGracefulTeardown() {
t.Errorf("unmatched flag parsed. Expected disableGracefulTeardown to be true")
}
})
}
}

0 comments on commit 50d84f2

Please sign in to comment.