-
Notifications
You must be signed in to change notification settings - Fork 1
/
eval.go
91 lines (82 loc) · 2.3 KB
/
eval.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
package kube
import (
"context"
"testing"
"time"
"github.com/cenkalti/backoff/v4"
"github.com/gdt-dev/gdt/debug"
gdterrors "github.com/gdt-dev/gdt/errors"
"github.com/gdt-dev/gdt/result"
gdttypes "github.com/gdt-dev/gdt/types"
)
const (
// defaultGetTimeout is used as a retry max time if the spec's Timeout has
// not been specified.
defaultGetTimeout = time.Second * 5
)
// Eval performs an action and evaluates the results of that action, returning
// a Result that informs the Scenario about what failed or succeeded. A new
// Kubernetes client request is made during this call.
func (s *Spec) Eval(ctx context.Context, t *testing.T) *result.Result {
c, err := s.connect(ctx)
if err != nil {
return result.New(
result.WithRuntimeError(ConnectError(err)),
)
}
var a gdttypes.Assertions
ns := s.Namespace()
// if the Spec has no timeout, default it to a reasonable value
var cancel context.CancelFunc
_, hasDeadline := ctx.Deadline()
if !hasDeadline {
ctx, cancel = context.WithTimeout(ctx, defaultGetTimeout)
defer cancel()
}
// retry the action and test the assertions until they succeed, there is a
// terminal failure, or the timeout expires.
bo := backoff.WithContext(backoff.NewExponentialBackOff(), ctx)
ticker := backoff.NewTicker(bo)
attempts := 0
start := time.Now().UTC()
success := false
for tick := range ticker.C {
attempts++
after := tick.Sub(start)
var out interface{}
err := s.Kube.Do(ctx, t, c, ns, &out)
if err != nil {
if err == gdterrors.ErrTimeoutExceeded {
return result.New(result.WithFailures(gdterrors.ErrTimeoutExceeded))
}
if err == gdterrors.RuntimeError {
return result.New(result.WithRuntimeError(err))
}
}
a = newAssertions(s.Assert, err, out)
success = a.OK()
debug.Println(
ctx, t, "%s (try %d after %s) ok: %v",
s.Title(), attempts, after, success,
)
if success {
ticker.Stop()
break
}
for _, f := range a.Failures() {
debug.Println(
ctx, t, "%s (try %d after %s) failure: %s",
s.Title(), attempts, after, f,
)
}
}
if !success {
for _, fail := range a.Failures() {
t.Error(fail)
}
}
return result.New(result.WithFailures(a.Failures()...))
}