github.com/pingcap/failpoint@v0.0.0-20240412033321-fd0796e60f86/failpoints_test.go (about) 1 // Copyright 2021 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package failpoint_test 16 17 import ( 18 "io/ioutil" 19 "os" 20 "testing" 21 "time" 22 23 "github.com/pingcap/errors" 24 "github.com/pingcap/failpoint" 25 "github.com/stretchr/testify/require" 26 ) 27 28 func TestFailpoints(t *testing.T) { 29 var fps failpoint.Failpoints 30 31 err := fps.Enable("failpoints-test-1", "return(1)") 32 require.NoError(t, err) 33 val, err := fps.Eval("failpoints-test-1") 34 require.NoError(t, err) 35 require.Equal(t, 1, val.(int)) 36 37 err = fps.Enable("failpoints-test-2", "invalid") 38 require.EqualError(t, err, `error on failpoints-test-2: failpoint: failed to parse "invalid" past "invalid"`) 39 40 val, err = fps.Eval("failpoints-test-2") 41 require.Error(t, err) 42 require.Nil(t, val) 43 44 err = fps.Disable("failpoints-test-1") 45 require.NoError(t, err) 46 47 val, err = fps.Eval("failpoints-test-1") 48 require.Error(t, err) 49 require.Nil(t, val) 50 51 err = fps.Disable("failpoints-test-1") 52 require.NoError(t, err) 53 54 err = fps.Enable("failpoints-test-1", "return(1)") 55 require.NoError(t, err) 56 57 status, err := fps.Status("failpoints-test-1") 58 require.NoError(t, err) 59 require.Equal(t, "return(1)", status) 60 61 err = fps.Enable("failpoints-test-3", "return(2)") 62 require.NoError(t, err) 63 64 ch := make(chan struct{}) 65 go func() { 66 time.Sleep(time.Second) 67 err := fps.Disable("gofail/testPause") 68 require.NoError(t, err) 69 close(ch) 70 }() 71 err = fps.Enable("gofail/testPause", "pause") 72 require.NoError(t, err) 73 start := time.Now() 74 v, err := fps.Eval("gofail/testPause") 75 require.NoError(t, err) 76 require.Nil(t, v) 77 78 require.True(t, time.Since(start) > 100*time.Millisecond) 79 <-ch 80 81 err = fps.Enable("failpoints-test-4", "50.0%return(5)") 82 require.NoError(t, err) 83 var succ int 84 for i := 0; i < 1000; i++ { 85 val, err = fps.Eval("failpoints-test-4") 86 if err == nil && val != nil { 87 succ++ 88 require.Equal(t, 5, val.(int)) 89 } 90 } 91 92 if succ < 450 || succ > 550 { 93 require.FailNow(t, "prop failure: %v", succ) 94 } 95 96 err = fps.Enable("failpoints-test-5", "50*return(5)") 97 require.NoError(t, err) 98 for i := 0; i < 50; i++ { 99 val, err = fps.Eval("failpoints-test-5") 100 require.NoError(t, err) 101 require.Equal(t, 5, val.(int)) 102 } 103 val, err = fps.Eval("failpoints-test-5") 104 require.Equal(t, failpoint.ErrNotAllowed, errors.Cause(err)) 105 require.Nil(t, val) 106 107 points := map[string]struct{}{} 108 for _, fp := range fps.List() { 109 points[fp] = struct{}{} 110 } 111 require.Contains(t, points, "failpoints-test-1") 112 require.Contains(t, points, "failpoints-test-2") 113 require.Contains(t, points, "failpoints-test-3") 114 require.Contains(t, points, "failpoints-test-4") 115 require.Contains(t, points, "failpoints-test-5") 116 117 err = fps.Enable("failpoints-test-6", "50*return(5)->1*return(true)->1*return(false)->10*return(20)") 118 require.NoError(t, err) 119 // 50*return(5) 120 for i := 0; i < 50; i++ { 121 val, err = fps.Eval("failpoints-test-6") 122 require.NoError(t, err) 123 require.Equal(t, 5, val.(int)) 124 } 125 // 1*return(true) 126 val, err = fps.Eval("failpoints-test-6") 127 require.NoError(t, err) 128 require.True(t, val.(bool)) 129 // 1*return(false) 130 val, err = fps.Eval("failpoints-test-6") 131 require.NoError(t, err) 132 require.False(t, val.(bool)) 133 // 10*return(20) 134 for i := 0; i < 10; i++ { 135 val, err = fps.Eval("failpoints-test-6") 136 require.NoError(t, err) 137 require.Equal(t, 20, val.(int)) 138 } 139 val, err = fps.Eval("failpoints-test-6") 140 require.Equal(t, failpoint.ErrNotAllowed, errors.Cause(err)) 141 require.Nil(t, val) 142 143 val, err = fps.Eval("failpoints-test-7") 144 require.Equal(t, failpoint.ErrNotExist, errors.Cause(err)) 145 require.Nil(t, val) 146 147 val, err = failpoint.Eval("failpoint-env1") 148 require.NoError(t, err) 149 require.Equal(t, 10, val.(int)) 150 val, err = failpoint.Eval("failpoint-env2") 151 require.NoError(t, err) 152 require.True(t, val.(bool)) 153 154 // Tests for sleep 155 ch = make(chan struct{}) 156 go func() { 157 defer close(ch) 158 time.Sleep(time.Second) 159 err := failpoint.Disable("gofail/test-sleep") 160 require.NoError(t, err) 161 }() 162 err = failpoint.Enable("gofail/test-sleep", "sleep(100)") 163 require.NoError(t, err) 164 start = time.Now() 165 v, err = failpoint.Eval("gofail/test-sleep") 166 require.NoError(t, err) 167 require.Nil(t, v) 168 require.GreaterOrEqual(t, time.Since(start).Milliseconds(), int64(90)) 169 <-ch 170 171 // Tests for sleep duration 172 ch = make(chan struct{}) 173 go func() { 174 defer close(ch) 175 time.Sleep(time.Second) 176 err := failpoint.Disable("gofail/test-sleep2") 177 require.NoError(t, err) 178 }() 179 err = failpoint.Enable("gofail/test-sleep2", `sleep("100ms")`) 180 require.NoError(t, err) 181 start = time.Now() 182 v, err = failpoint.Eval("gofail/test-sleep2") 183 require.NoError(t, err) 184 require.Nil(t, v) 185 require.GreaterOrEqual(t, time.Since(start).Milliseconds(), int64(90)) 186 <-ch 187 188 // Tests for print 189 oldStdio := os.Stdout 190 r, w, err := os.Pipe() 191 require.NoError(t, err) 192 os.Stdout = w 193 err = fps.Enable("test-print", `print("hello world")`) 194 require.NoError(t, err) 195 val, err = fps.Eval("test-print") 196 require.NoError(t, err) 197 require.Nil(t, val) 198 outC := make(chan string) 199 // copy the output in a separate goroutine so printing can't block indefinitely 200 go func() { 201 defer close(outC) 202 s, err := ioutil.ReadAll(r) 203 require.NoError(t, err) 204 outC <- string(s) 205 }() 206 require.NoError(t, w.Close()) 207 os.Stdout = oldStdio 208 out := <-outC 209 require.Equal(t, "failpoint print: hello world\n", out) 210 211 // Tests for panic 212 require.PanicsWithValue(t, "failpoint panic: {}", testPanic) 213 214 err = fps.Enable("failpoints-test-7", `return`) 215 require.NoError(t, err) 216 val, err = fps.Eval("failpoints-test-7") 217 require.NoError(t, err) 218 require.Equal(t, struct{}{}, val) 219 220 err = fps.Enable("failpoints-test-8", `return()`) 221 require.NoError(t, err) 222 val, err = fps.Eval("failpoints-test-8") 223 require.NoError(t, err) 224 require.Equal(t, struct{}{}, val) 225 } 226 227 func testPanic() { 228 _ = failpoint.Enable("test-panic", `panic`) 229 _, _ = failpoint.Eval("test-panic") 230 }