generated from kubernetes/kubernetes-template-project
-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #118 from harshanarayana/feature/git-112/enable-fr…
…amework-fail-fast-mode GIT-112: enable framework specific fail-fast mode
- Loading branch information
Showing
6 changed files
with
272 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# Fail Fast Mode | ||
|
||
When writing test feature using `e2e-framework` it is possible that you can write test assessments grouped under the same feature that are dependent on each other. | ||
This is possible as the framework ensures that the assessments are processed in sequence of how they are registered. This key behavior bring up a need to be able to | ||
optionally terminate the Feature(s) under test when a specific assessment fails. | ||
|
||
## Why not use `test.failfast`? | ||
|
||
`go test` provides a handy way to terminate test execution of first sign of failure via the `-failfast` argument. | ||
However, this terminates the entire test suite in question. | ||
|
||
Such termination of the suite is not desirable for the framework as the rest of the Tests can still be processed | ||
in case if an assessment in one test fails. This bring in the need to introduce a framework specific `fail-fast` | ||
mode that can perform the following. | ||
|
||
1. It should Terminate the feature(s) under test and mark the test as failure | ||
2. Skip the Teardown workflow of the feature(s) under test to enable easy debug | ||
|
||
## Framework specific `--fail-fast` Mode | ||
|
||
`e2e-framework` introduces a new CLI argument flag that can be invoked while triggering the test to achieve the | ||
fail-fast behavior built into the framework. | ||
|
||
There are certain caveats to how this feature works. | ||
|
||
1. The `fail-fast` mode doesn't work in conjunction with the `parallel` test mode | ||
2. Test developers have to explicitly invoke the `t.Fail()` or `t.FailNow()` handlers in the assessment to inform | ||
the framework that the fail-fast mode needs to be triggered | ||
|
||
## Example Assessment | ||
Below section shows a simple example of how the feature can be leveraged in the assessment. This should be combined with `--fail-fast` argument while invoking the test to leverage the full feature. | ||
|
||
```go | ||
func TestFeatureOne(t *testing.T) { | ||
featureOne := features.New("feature-one"). | ||
Assess("this fails", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { | ||
if 1 != 2 { | ||
t.Log("1 != 2") | ||
t.FailNow() // mark test case as failed here, don't continue execution | ||
} else { | ||
t.Log("1 == 2") | ||
} | ||
return ctx | ||
}). | ||
Teardown(func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context { | ||
t.Log("This teardown should not be invoked") | ||
return ctx | ||
}). | ||
Feature() | ||
testenv.Test(t, failFeature, nextFeature) | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
# Fail Fast Mode | ||
|
||
There are times in your test infra that you want the rest of your feature assessments to fail in | ||
case if one of the current executing assessments fail. | ||
This can aid in getting a better turn around time especially in cases where your assessments are | ||
inter-related and a failed assessment in step 1 can mean that running the rest of the assessment | ||
is guaranteed to fail. This can be done with the help of a `--fail-fast` flag provided at the | ||
framework level. | ||
|
||
This works similar to how the `-failfast` mode of the `go test` works but provides the same | ||
feature at the context of the `e2e-framework`. | ||
|
||
# How to Use this feature ? | ||
|
||
1. Invoke the tests using `--fail-fast` argument | ||
2. Test developers should make sure they invoke either `t.Fail()` or `t.FailNow()` from the assessment to make sure the | ||
additional handlers kick in to stop the test execution of the feature in question where the assessment has failed | ||
|
||
|
||
When the framework specific `--fail-fast` mode is used, this works as follows: | ||
|
||
1. It stops the rest of the assessments from getting executed for the feature under test | ||
2. This stops the next feature from getting executed in case if the feature under test fails as per step 1. | ||
3. Marks the feature and test associated with it as Failure. | ||
4. Skips the teardown sequence to make sure it is easier to debug the test failure | ||
|
||
> Current limitation is that this can't be combined with the `--parallel` switch | ||
Since this can lead to a test failure, we have just documented an example of this. Thanks to @divmadan for the example. | ||
|
||
```go | ||
// main_test.go | ||
package example | ||
|
||
import ( | ||
"log" | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"sigs.k8s.io/e2e-framework/pkg/env" | ||
) | ||
|
||
var testenv env.Environment | ||
|
||
func TestMain(m *testing.M) { | ||
cfg, _ := envconf.NewFromFlags() | ||
testenv = env.NewWithConfig(cfg) | ||
|
||
os.Exit(testenv.Run(m)) | ||
} | ||
``` | ||
|
||
```go | ||
// example_test.go | ||
package example | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"sigs.k8s.io/e2e-framework/pkg/envconf" | ||
"sigs.k8s.io/e2e-framework/pkg/features" | ||
) | ||
|
||
func TestExample(t *testing.T) { | ||
failFeature := features.New("fail-feature"). | ||
Assess("1==2", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { | ||
if 1 != 2 { | ||
t.Log("1 != 2") | ||
t.FailNow() // mark test case as failed here, don't continue execution | ||
} else { | ||
t.Log("1 == 2") | ||
} | ||
return ctx | ||
}). | ||
Assess("print", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { | ||
t.Log("THIS LINE SHOULDN'T BE PRINTED") | ||
return ctx | ||
}). | ||
Teardown(func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context { | ||
t.Log("This teardown should not be invoked") | ||
return ctx | ||
}). | ||
Feature() | ||
|
||
nextFeature := features.New("next-feature"). | ||
Assess("print", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { | ||
t.Log("THIS LINE ALSO SHOULDN'T BE PRINTED") | ||
return ctx | ||
}). | ||
Feature() | ||
|
||
testenv.Test(t, failFeature, nextFeature) | ||
} | ||
|
||
// even if the previous testcase fails, execute this testcase | ||
func TestNext(t *testing.T) { | ||
nextFeature := features.New("next-test-feature"). | ||
Assess("print", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { | ||
t.Log("THIS LINE SHOULD BE PRINTED") | ||
return ctx | ||
}). | ||
Teardown(func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context { | ||
t.Log("This teardown should be invoked") | ||
return ctx | ||
}). | ||
Feature() | ||
|
||
testenv.Test(t, nextFeature) | ||
} | ||
``` | ||
|
||
When run this using `--fail-fast` you get the following behavior. | ||
|
||
```bash | ||
❯ go test . -test.v -args --fail-fast | ||
|
||
=== RUN TestExample | ||
=== RUN TestExample/fail-feature | ||
=== RUN TestExample/fail-feature/1==2 | ||
example_test.go:15: 1 != 2 | ||
--- FAIL: TestExample (0.00s) | ||
--- FAIL: TestExample/fail-feature (0.00s) | ||
--- FAIL: TestExample/fail-feature/1==2 (0.00s) | ||
=== RUN TestNext | ||
=== RUN TestNext/next-test-feature | ||
=== RUN TestNext/next-test-feature/print | ||
example_test.go:42: THIS LINE SHOULD BE PRINTED | ||
--- PASS: TestNext (0.00s) | ||
--- PASS: TestNext/next-test-feature (0.00s) | ||
--- PASS: TestNext/next-test-feature/print (0.00s) | ||
FAIL | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.