-
Notifications
You must be signed in to change notification settings - Fork 35
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
Implement sleep failpoint status #47
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
package runtime_test | ||
|
||
import ( | ||
"strings" | ||
"testing" | ||
|
||
"go.etcd.io/gofail/runtime" | ||
) | ||
|
||
// This variable mimics the code generated by gofail code package. | ||
// This works in tandem with exampleFunc function. | ||
var __fp_ExampleString *runtime.Failpoint //nolint:stylecheck | ||
|
||
// check if failpoint is initialized as gofail | ||
// tests can clear global variables of runtime packages | ||
func initFP() { | ||
fps := runtime.List() | ||
if fps != nil { | ||
s_fps := strings.Join(fps, " ") | ||
if strings.Contains(s_fps, "ExampleString") { | ||
return | ||
} | ||
} | ||
__fp_ExampleString = runtime.NewFailpoint("ExampleString") //nolint:stylecheck | ||
} | ||
|
||
func TestTermsCounter(t *testing.T) { | ||
testcases := []struct { | ||
name string | ||
fp string | ||
failpointTerm string | ||
runBeforeEnabling int | ||
runAfterEnabling int | ||
wantCount int | ||
}{ | ||
{ | ||
name: "Terms limit Failpoint", | ||
fp: "ExampleString", | ||
failpointTerm: `10*sleep(10)->1*return("abc")`, | ||
runAfterEnabling: 12, | ||
// This example tests mods which allows users to restrict the | ||
// number of failpoint actions as against their callsite executions. | ||
// This is the reason why wantCount < runAfterEnabling | ||
// In a real world example you can hit a code spot a million times but | ||
// using mods restrict the associated fallpoint actions to run twice. | ||
wantCount: 11, | ||
}, | ||
{ | ||
name: "Inbetween Enabling Failpoint", | ||
fp: "ExampleString", | ||
failpointTerm: `10*sleep(10)->1*return("abc")`, | ||
runBeforeEnabling: 2, | ||
runAfterEnabling: 3, | ||
wantCount: 3, | ||
}, | ||
{ | ||
name: "Before Enabling Failpoint", | ||
fp: "ExampleString", | ||
failpointTerm: `10*sleep(10)->1*return("abc")`, | ||
runBeforeEnabling: 2, | ||
runAfterEnabling: 0, | ||
wantCount: 0, | ||
}, | ||
} | ||
|
||
initFP() | ||
for _, tc := range testcases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
|
||
for i := 0; i < tc.runBeforeEnabling; i++ { | ||
exampleFunc() | ||
} | ||
|
||
err := runtime.Enable(tc.fp, tc.failpointTerm) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
defer runtime.Disable(tc.fp) | ||
for i := 0; i < tc.runAfterEnabling; i++ { | ||
exampleFunc() | ||
} | ||
_, count, err := runtime.Status(tc.fp) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if tc.wantCount != count { | ||
t.Fatal("counter is not properly incremented") | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestEnablingNewTermResetsCount(t *testing.T) { | ||
testcases := []struct { | ||
name string | ||
fp string | ||
oldTerm string | ||
newTerm string | ||
runOldTerm int | ||
runNewTerm int | ||
wantCount int | ||
}{ | ||
{ | ||
name: "Change and Reset Counter", | ||
fp: "ExampleString", | ||
oldTerm: `10*sleep(10)->1*return("abc")`, | ||
newTerm: "sleep(10)", | ||
runOldTerm: 2, | ||
runNewTerm: 3, | ||
wantCount: 3, | ||
}, | ||
} | ||
|
||
initFP() | ||
for _, tc := range testcases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
err := runtime.Enable(tc.fp, tc.oldTerm) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
for i := 0; i < tc.runOldTerm; i++ { | ||
exampleFunc() | ||
} | ||
err = runtime.Enable(tc.fp, tc.newTerm) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
defer runtime.Disable(tc.fp) | ||
|
||
for i := 0; i < tc.runNewTerm; i++ { | ||
exampleFunc() | ||
} | ||
_, count, err := runtime.Status(tc.fp) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if tc.wantCount != count { | ||
t.Fatal("counter is not properly incremented") | ||
} | ||
}) | ||
} | ||
|
||
} | ||
|
||
// This function mimics a customized code that is generated by gofail code package. | ||
func exampleFunc() string { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: can you add some comments about this test setup. My understanding is that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have added a comment for this function and the variable that together mimics the actions of code package. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need exampleFunc in this test file? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It simulates the triggering of the failpoint. We can achieve the same thing by a combination of "envTerms" and "Acquire()" as seen in failpoint_test.go. I can remove and replace if that is the preferred way. |
||
if vExampleString, __fpErr := __fp_ExampleString.Acquire(); __fpErr == nil { //nolint:stylecheck | ||
ExampleString, __fpTypeOK := vExampleString.(string) //nolint:stylecheck | ||
if !__fpTypeOK { //nolint:stylecheck | ||
goto __badTypeExampleString //nolint:stylecheck | ||
} | ||
return ExampleString | ||
__badTypeExampleString: //nolint:stylecheck | ||
__fp_ExampleString.BadType(vExampleString, "string") //nolint:stylecheck | ||
} | ||
return "example" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be a field/attribute of Failpoint, and we need to clearly define what does counter exactly mean. There are two options:
40.0%return(true)
means 40% possibility to returntrue
. If it returns false (falls into the other 60% possibility), then we don't increment thecounter
.Your current implementation should be the second option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have updated the definition of counter. Regarding making it a field of Failpoint, I have the following concerns
Should these be addressed as a refactor in a separate PR ?