• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rom8726 / chaoskit / 19610792979

23 Nov 2025 11:58AM UTC coverage: 45.033% (+0.6%) from 44.428%
19610792979

push

github

rom8726
Add no-op ChaosContext implementation with build tag isolation and update documentation.

0 of 56 new or added lines in 4 files covered. (0.0%)

2 existing lines in 1 file now uncovered.

2049 of 4550 relevant lines covered (45.03%)

747.41 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/testing/testing.go
1
package testing
2

3
import (
4
        "context"
5
        "fmt"
6

7
        "github.com/rom8726/chaoskit"
8
)
9

10
// TestingT is an interface that matches testing.T and similar types
11
type TestingT interface {
12
        Errorf(format string, args ...interface{})
13
        FailNow()
14
        Helper()
15
}
16

17
// ChaosTestOption configures chaos testing
18
type ChaosTestOption func(*chaosTestConfig)
19

20
type chaosTestConfig struct {
21
        repeat         int
22
        failurePolicy  chaoskit.FailurePolicy
23
        executorOpts   []chaoskit.ExecutorOption
24
        skipReport     bool
25
        reportToStderr bool
26
        thresholds     *chaoskit.SuccessThresholds
27
        skipVerdict    bool
28
}
29

30
// WithRepeat sets the number of times to repeat the test scenario
31
func WithRepeat(n int) ChaosTestOption {
×
32
        return func(c *chaosTestConfig) {
×
33
                c.repeat = n
×
34
        }
×
35
}
36

37
// WithFailurePolicy sets how to handle failures (FailFast or ContinueOnFailure)
38
func WithFailurePolicy(policy chaoskit.FailurePolicy) ChaosTestOption {
×
39
        return func(c *chaosTestConfig) {
×
40
                c.failurePolicy = policy
×
41
        }
×
42
}
43

44
// WithExecutorOptions passes options to the underlying executor
45
func WithExecutorOptions(opts ...chaoskit.ExecutorOption) ChaosTestOption {
×
46
        return func(c *chaosTestConfig) {
×
47
                c.executorOpts = append(c.executorOpts, opts...)
×
48
        }
×
49
}
50

51
// WithoutReport skips printing the report after execution
52
func WithoutReport() ChaosTestOption {
×
53
        return func(c *chaosTestConfig) {
×
54
                c.skipReport = true
×
55
        }
×
56
}
57

58
// WithReportToStderr prints the report to stderr instead of stdout
59
func WithReportToStderr() ChaosTestOption {
×
60
        return func(c *chaosTestConfig) {
×
61
                c.reportToStderr = true
×
62
        }
×
63
}
64

65
// WithThresholds sets custom success thresholds for verdict calculation
66
func WithThresholds(thresholds *chaoskit.SuccessThresholds) ChaosTestOption {
×
67
        return func(c *chaosTestConfig) {
×
68
                c.thresholds = thresholds
×
69
        }
×
70
}
71

72
// WithDefaultThresholds uses default success thresholds (95% success rate)
73
func WithDefaultThresholds() ChaosTestOption {
×
74
        return func(c *chaosTestConfig) {
×
75
                c.thresholds = chaoskit.DefaultThresholds()
×
76
        }
×
77
}
78

79
// WithStrictThresholds uses strict success thresholds (100% success rate)
80
func WithStrictThresholds() ChaosTestOption {
×
81
        return func(c *chaosTestConfig) {
×
82
                c.thresholds = chaoskit.StrictThresholds()
×
83
        }
×
84
}
85

86
// WithRelaxedThresholds uses relaxed success thresholds (80% success rate)
87
func WithRelaxedThresholds() ChaosTestOption {
×
88
        return func(c *chaosTestConfig) {
×
89
                c.thresholds = chaoskit.RelaxedThresholds()
×
90
        }
×
91
}
92

93
// WithoutVerdict skips verdict calculation (only basic report)
94
func WithoutVerdict() ChaosTestOption {
×
95
        return func(c *chaosTestConfig) {
×
96
                c.skipVerdict = true
×
97
        }
×
98
}
99

100
// RunChaos creates a chaos test function that uses the full ChaosKit framework.
101
// It creates a scenario using ScenarioBuilder, runs it with an Executor, and validates results.
102
//
103
// The builderFn receives a pre-initialized ScenarioBuilder with the target already set.
104
// You should add steps, injectors, and validators to the builder.
105
//
106
// Usage:
107
//
108
//        func TestWithChaos(t *testing.T) {
109
//            target := &MyTarget{}
110
//
111
//            chaoskit.RunChaos(t, "name", target, func(s *chaoskit.ScenarioBuilder) *chaoskit.ScenarioBuilder {
112
//                return s.
113
//                    Step("step1", func(ctx context.Context, target chaoskit.Target) error {
114
//                        // Your test logic
115
//                        return DoSomething()
116
//                    }).
117
//                    Inject("delay", injectors.RandomDelay(10*time.Millisecond, 50*time.Millisecond)).
118
//                    Assert("goroutines", validators.GoroutineLimit(100))
119
//            },
120
//                WithRepeat(10),
121
//                WithDefaultThresholds(), // Enables verdict with 95% success rate
122
//            )
123
//        }
124
func RunChaos(
125
        t TestingT,
126
        name string,
127
        target chaoskit.Target,
128
        builderFn func(*chaoskit.ScenarioBuilder) *chaoskit.ScenarioBuilder,
129
        opts ...ChaosTestOption,
130
) {
×
131
        t.Helper()
×
132

×
133
        // Apply options
×
134
        config := &chaosTestConfig{
×
135
                repeat:        1,
×
136
                failurePolicy: chaoskit.FailFast,
×
137
                thresholds:    chaoskit.DefaultThresholds(), // Use default thresholds
×
138
        }
×
139
        for _, opt := range opts {
×
140
                opt(config)
×
141
        }
×
142

143
        // Create scenario builder
144
        builder := chaoskit.NewScenario(name).WithTarget(target)
×
145

×
146
        // Let user configure the scenario
×
147
        builder = builderFn(builder)
×
148

×
149
        // Set repeat count
×
150
        builder = builder.Repeat(config.repeat)
×
151

×
152
        // Build scenario
×
153
        scenario := builder.Build()
×
154

×
155
        // Create executor with options
×
156
        executorOpts := append(
×
157
                []chaoskit.ExecutorOption{chaoskit.WithFailurePolicy(config.failurePolicy)},
×
158
                config.executorOpts...,
×
159
        )
×
160
        executor := chaoskit.NewExecutor(executorOpts...)
×
161

×
162
        // Run scenario
×
163
        ctx := context.Background()
×
164
        if err := executor.Run(ctx, scenario); err != nil {
×
165
                t.Errorf("chaos test execution failed: %v", err)
×
166

×
167
                // Print report on failure
×
168
                if !config.skipReport {
×
169
                        printReport(t, executor, config)
×
170
                }
×
171

172
                t.FailNow()
×
NEW
173

×
UNCOV
174
                return
×
175
        }
176

177
        // Calculate verdict and print report
178
        if !config.skipReport || !config.skipVerdict {
×
179
                verdict := evaluateVerdict(t, executor, config)
×
180

×
181
                // Fail test if verdict is FAIL
×
182
                if verdict == chaoskit.VerdictFail {
×
183
                        t.Errorf("chaos test verdict: FAIL")
×
184
                        t.FailNow()
×
185
                }
×
186
        }
187
}
188

189
// printReport prints the test report
190
func printReport(t TestingT, executor *chaoskit.Executor, config *chaosTestConfig) {
×
191
        if config.skipVerdict {
×
192
                // Print simple report
×
193
                report := executor.Reporter().GenerateReport()
×
194
                if logger, ok := t.(interface{ Logf(string, ...interface{}) }); ok {
×
195
                        logger.Logf("\n%s", report)
×
196
                }
×
197
        } else {
×
198
                // Print detailed report with verdict
×
199
                report, err := executor.Reporter().GetVerdict(config.thresholds)
×
200
                if err != nil {
×
201
                        if logger, ok := t.(interface{ Logf(string, ...interface{}) }); ok {
×
202
                                logger.Logf("\nFailed to generate verdict: %v", err)
×
203
                                logger.Logf("\n%s", executor.Reporter().GenerateReport())
×
204
                        }
×
205

UNCOV
206
                        return
×
207
                }
208

209
                textReport := executor.Reporter().GenerateTextReport(report)
×
210
                if logger, ok := t.(interface{ Logf(string, ...interface{}) }); ok {
×
211
                        logger.Logf("\n%s", textReport)
×
212
                }
×
213
        }
214
}
215

216
// evaluateVerdict evaluates the verdict and returns it
217
func evaluateVerdict(t TestingT, executor *chaoskit.Executor, config *chaosTestConfig) chaoskit.Verdict {
×
218
        if config.skipVerdict {
×
219
                return chaoskit.VerdictPass
×
220
        }
×
221

222
        // Get verdict
223
        report, err := executor.Reporter().GetVerdict(config.thresholds)
×
224
        if err != nil {
×
225
                t.Errorf("failed to generate verdict: %v", err)
×
NEW
226

×
227
                return chaoskit.VerdictFail
×
228
        }
×
229

230
        // Print report
231
        if !config.skipReport {
×
232
                textReport := executor.Reporter().GenerateTextReport(report)
×
233
                if logger, ok := t.(interface{ Logf(string, ...interface{}) }); ok {
×
234
                        logger.Logf("\n%s", textReport)
×
235
                }
×
236
        }
237

238
        return report.Verdict
×
239
}
240

241
// RunChaosSimple is a simplified version that takes steps, injectors, and validators directly.
242
// This is useful when you don't need the full builder flexibility.
243
//
244
// Usage:
245
//
246
//        func TestSimpleChaos(t *testing.T) {
247
//            target := &MyTarget{}
248
//            steps := []chaoskit.StepFunc{
249
//                func(ctx context.Context, target chaoskit.Target) error {
250
//                    return DoSomething()
251
//                },
252
//            }
253
//            injectors := []chaoskit.Injector{
254
//                injectors.RandomDelay(10*time.Millisecond, 50*time.Millisecond),
255
//            }
256
//            validators := []chaoskit.Validator{
257
//                validators.GoroutineLimit(100),
258
//            }
259
//
260
//            chaoskit.RunChaosSimple(t, "name", target, steps, injectors, validators,
261
//                WithRepeat(10),
262
//                WithDefaultThresholds(),
263
//            )
264
//        }
265
func RunChaosSimple(
266
        t TestingT,
267
        name string,
268
        target chaoskit.Target,
269
        steps []func(context.Context, chaoskit.Target) error,
270
        injectors []chaoskit.Injector,
271
        validators []chaoskit.Validator,
272
        opts ...ChaosTestOption,
273
) {
×
274
        RunChaos(t, name, target, func(s *chaoskit.ScenarioBuilder) *chaoskit.ScenarioBuilder {
×
275
                // Add steps
×
276
                for i, stepFn := range steps {
×
277
                        s = s.Step(fmt.Sprintf("step-%d", i+1), stepFn)
×
278
                }
×
279

280
                // Add injectors
281
                for i, inj := range injectors {
×
282
                        s = s.Inject(fmt.Sprintf("injector-%d", i+1), inj)
×
283
                }
×
284

285
                // Add validators
286
                for i, val := range validators {
×
287
                        s = s.Assert(fmt.Sprintf("validator-%d", i+1), val)
×
288
                }
×
289

290
                return s
×
291
        }, opts...)
292
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc