Skip to content

Commit 464030a

Browse files
committed
ensure no retry for create/apply/delete
We only want to retry kube.get actions, not create, apply or delete. In bringing in [email protected], we now have override ability for an individual Evaluable's Retry and Timeout. When adding this functionality, it became evident that KinD clusters don't immediately add the default service account, which is required for simple tests like the creation of an nginx Pod. So, added a wait loop inside the KindFixture's Start method that waits for up to 15 seconds until it sees the existence of the default service account. Issue #17 Signed-off-by: Jay Pipes <[email protected]>
1 parent 3e24bea commit 464030a

13 files changed

+235
-157
lines changed

action.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import (
1313
"os"
1414
"strings"
1515

16+
"github.com/gdt-dev/gdt/api"
1617
"github.com/gdt-dev/gdt/debug"
17-
gdterrors "github.com/gdt-dev/gdt/errors"
1818
"github.com/gdt-dev/gdt/parse"
1919
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2020
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -226,7 +226,7 @@ func (a *Action) create(
226226
if err != nil {
227227
// This should never happen because we check during parse time
228228
// whether the file can be opened.
229-
rterr := fmt.Errorf("%w: %s", gdterrors.RuntimeError, err)
229+
rterr := fmt.Errorf("%w: %s", api.RuntimeError, err)
230230
return rterr
231231
}
232232
defer f.Close()
@@ -245,7 +245,7 @@ func (a *Action) create(
245245

246246
objs, err := unstructuredFromReader(r)
247247
if err != nil {
248-
rterr := fmt.Errorf("%w: %s", gdterrors.RuntimeError, err)
248+
rterr := fmt.Errorf("%w: %s", api.RuntimeError, err)
249249
return rterr
250250
}
251251
for _, obj := range objs {
@@ -290,7 +290,7 @@ func (a *Action) apply(
290290
if err != nil {
291291
// This should never happen because we check during parse time
292292
// whether the file can be opened.
293-
rterr := fmt.Errorf("%w: %s", gdterrors.RuntimeError, err)
293+
rterr := fmt.Errorf("%w: %s", api.RuntimeError, err)
294294
return rterr
295295
}
296296
defer f.Close()
@@ -309,7 +309,7 @@ func (a *Action) apply(
309309

310310
objs, err := unstructuredFromReader(r)
311311
if err != nil {
312-
rterr := fmt.Errorf("%w: %s", gdterrors.RuntimeError, err)
312+
rterr := fmt.Errorf("%w: %s", api.RuntimeError, err)
313313
return rterr
314314
}
315315
for _, obj := range objs {
@@ -358,13 +358,13 @@ func (a *Action) delete(
358358
if err != nil {
359359
// This should never happen because we check during parse time
360360
// whether the file can be opened.
361-
rterr := fmt.Errorf("%w: %s", gdterrors.RuntimeError, err)
361+
rterr := fmt.Errorf("%w: %s", api.RuntimeError, err)
362362
return rterr
363363
}
364364
defer f.Close()
365365
objs, err := unstructuredFromReader(f)
366366
if err != nil {
367-
rterr := fmt.Errorf("%w: %s", gdterrors.RuntimeError, err)
367+
rterr := fmt.Errorf("%w: %s", api.RuntimeError, err)
368368
return rterr
369369
}
370370
for _, obj := range objs {

assertions.go

+14-15
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ import (
1212
"net/http"
1313
"strings"
1414

15+
"github.com/gdt-dev/gdt/api"
1516
gdtjson "github.com/gdt-dev/gdt/assertion/json"
16-
gdterrors "github.com/gdt-dev/gdt/errors"
17-
gdttypes "github.com/gdt-dev/gdt/types"
1817
"gopkg.in/yaml.v3"
1918
apierrors "k8s.io/apimachinery/pkg/api/errors"
2019
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -166,8 +165,8 @@ type Expect struct {
166165
// conditionMatch is a struct with fields that we will match a resource's
167166
// `Condition` against.
168167
type conditionMatch struct {
169-
Status *gdttypes.FlexStrings `yaml:"status,omitempty"`
170-
Reason string `yaml:"reason,omitempty"`
168+
Status *api.FlexStrings `yaml:"status,omitempty"`
169+
Reason string `yaml:"reason,omitempty"`
171170
}
172171

173172
// ConditionMatch can be a string (the ConditionStatus to match), a slice of
@@ -182,7 +181,7 @@ type ConditionMatch struct {
182181
// ConditionMatch can be either a string, a slice of strings, or an object with .
183182
func (m *ConditionMatch) UnmarshalYAML(node *yaml.Node) error {
184183
if node.Kind == yaml.ScalarNode || node.Kind == yaml.SequenceNode {
185-
var fs gdttypes.FlexStrings
184+
var fs api.FlexStrings
186185
if err := node.Decode(&fs); err != nil {
187186
return ConditionMatchInvalid(node, err)
188187
}
@@ -203,10 +202,10 @@ func (m *ConditionMatch) UnmarshalYAML(node *yaml.Node) error {
203202
type PlacementAssertion struct {
204203
// Spread contains zero or more topology keys that gdt-kube will assert an
205204
// even spread across.
206-
Spread *gdttypes.FlexStrings `yaml:"spread,omitempty"`
205+
Spread *api.FlexStrings `yaml:"spread,omitempty"`
207206
// Pack contains zero or more topology keys that gdt-kube will assert
208207
// bin-packing of resources within.
209-
Pack *gdttypes.FlexStrings `yaml:"pack,omitempty"`
208+
Pack *api.FlexStrings `yaml:"pack,omitempty"`
210209
}
211210

212211
// assertions contains all assertions made for the exec test
@@ -246,7 +245,7 @@ func (a *assertions) OK(ctx context.Context) bool {
246245
exp := a.exp
247246
if exp == nil {
248247
if a.err != nil {
249-
a.Fail(gdterrors.UnexpectedError(a.err))
248+
a.Fail(api.UnexpectedError(a.err))
250249
return false
251250
}
252251
return true
@@ -309,16 +308,16 @@ func (a *assertions) errorOK() bool {
309308
}
310309
if exp.Error != "" && a.r != nil {
311310
if a.err == nil {
312-
a.Fail(gdterrors.UnexpectedError(a.err))
311+
a.Fail(api.UnexpectedError(a.err))
313312
return false
314313
}
315314
if !strings.Contains(a.err.Error(), exp.Error) {
316-
a.Fail(gdterrors.NotIn(a.err.Error(), exp.Error))
315+
a.Fail(api.NotIn(a.err.Error(), exp.Error))
317316
return false
318317
}
319318
}
320319
if a.err != nil {
321-
a.Fail(gdterrors.UnexpectedError(a.err))
320+
a.Fail(api.UnexpectedError(a.err))
322321
return false
323322
}
324323
return true
@@ -368,7 +367,7 @@ func (a *assertions) lenOK() bool {
368367
list, ok := a.r.(*unstructured.UnstructuredList)
369368
if ok && list != nil {
370369
if len(list.Items) != *exp.Len {
371-
a.Fail(gdterrors.NotEqualLength(*exp.Len, len(list.Items)))
370+
a.Fail(api.NotEqualLength(*exp.Len, len(list.Items)))
372371
return false
373372
}
374373
}
@@ -402,7 +401,7 @@ func (a *assertions) matchesOK() bool {
402401
// for _, obj := range list.Items {
403402
// diff := compareResourceToMatchObject(obj, matchObj)
404403
//
405-
// a.Fail(gdterrors.NotEqualLength(*exp.Len, len(list.Items)))
404+
// a.Fail(api.NotEqualLength(*exp.Len, len(list.Items)))
406405
// return false
407406
// }
408407
//}
@@ -435,7 +434,7 @@ func (a *assertions) conditionsOK() bool {
435434
// for _, obj := range list.Items {
436435
// diff := compareResourceToMatchObject(obj, matchObj)
437436
//
438-
// a.Fail(gdterrors.NotEqualLength(*exp.Len, len(list.Items)))
437+
// a.Fail(api.NotEqualLength(*exp.Len, len(list.Items)))
439438
// return false
440439
// }
441440
//}
@@ -511,7 +510,7 @@ func newAssertions(
511510
exp *Expect,
512511
err error,
513512
r interface{},
514-
) gdttypes.Assertions {
513+
) api.Assertions {
515514
return &assertions{
516515
c: c,
517516
failures: []error{},

defaults.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ package kube
77
import (
88
"os"
99

10-
"github.com/gdt-dev/gdt/errors"
11-
gdttypes "github.com/gdt-dev/gdt/types"
10+
"github.com/gdt-dev/gdt/api"
1211
"gopkg.in/yaml.v3"
1312
)
1413

@@ -39,21 +38,21 @@ type Defaults struct {
3938

4039
func (d *Defaults) UnmarshalYAML(node *yaml.Node) error {
4140
if node.Kind != yaml.MappingNode {
42-
return errors.ExpectedMapAt(node)
41+
return api.ExpectedMapAt(node)
4342
}
4443
// maps/structs are stored in a top-level Node.Content field which is a
4544
// concatenated slice of Node pointers in pairs of key/values.
4645
for i := 0; i < len(node.Content); i += 2 {
4746
keyNode := node.Content[i]
4847
if keyNode.Kind != yaml.ScalarNode {
49-
return errors.ExpectedScalarAt(keyNode)
48+
return api.ExpectedScalarAt(keyNode)
5049
}
5150
key := keyNode.Value
5251
valNode := node.Content[i+1]
5352
switch key {
5453
case "kube":
5554
if valNode.Kind != yaml.MappingNode {
56-
return errors.ExpectedMapAt(valNode)
55+
return api.ExpectedMapAt(valNode)
5756
}
5857
hd := kubeDefaults{}
5958
if err := valNode.Decode(&hd); err != nil {
@@ -86,7 +85,7 @@ func (d *Defaults) validate() error {
8685
}
8786

8887
// fromBaseDefaults returns an gdt-kube plugin-specific Defaults from a Spec
89-
func fromBaseDefaults(base *gdttypes.Defaults) *Defaults {
88+
func fromBaseDefaults(base *api.Defaults) *Defaults {
9089
if base == nil {
9190
return nil
9291
}

errors.go

+16-16
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ package kube
77
import (
88
"fmt"
99

10-
gdterrors "github.com/gdt-dev/gdt/errors"
10+
"github.com/gdt-dev/gdt/api"
1111
"gopkg.in/yaml.v3"
1212
"k8s.io/apimachinery/pkg/runtime/schema"
1313
)
@@ -20,103 +20,103 @@ var (
2020
ErrExpectedMapOrYAMLString = fmt.Errorf(
2121
"%w: expected either map[string]interface{} "+
2222
"or a string with embedded YAML",
23-
gdterrors.ErrParse,
23+
api.ErrParse,
2424
)
2525
// ErrEitherShortcutOrKubeSpec is returned when the test author
2626
// included both a shortcut (e.g. `kube.create` or `kube.apply`) AND the
2727
// long-form `kube` object in the same test spec.
2828
ErrEitherShortcutOrKubeSpec = fmt.Errorf(
2929
"%w: either specify a full KubeSpec in the `kube` field or specify "+
3030
"one of the shortcuts (e.g. `kube.create` or `kube.apply`",
31-
gdterrors.ErrParse,
31+
api.ErrParse,
3232
)
3333
// ErrMoreThanOneKubeAction is returned when the test author
3434
// included more than one Kubernetes action (e.g. `create` or `apply`) in
3535
// the same KubeSpec.
3636
ErrMoreThanOneKubeAction = fmt.Errorf(
3737
"%w: you may only specify a single Kubernetes action field "+
3838
"(e.g. `create`, `apply` or `delete`) in the `kube` object. ",
39-
gdterrors.ErrParse,
39+
api.ErrParse,
4040
)
4141
// ErrKubeConfigNotFound is returned when a kubeconfig path points
4242
// to a file that does not exist.
4343
ErrKubeConfigNotFound = fmt.Errorf(
4444
"%w: specified kube config path not found",
45-
gdterrors.ErrParse,
45+
api.ErrParse,
4646
)
4747
// ErrResourceSpecifier is returned when the test author uses a
4848
// resource specifier for the `kube.get` or `kube.delete` fields that is
4949
// not valid.
5050
ErrResourceSpecifierInvalid = fmt.Errorf(
5151
"%w: invalid resource specifier",
52-
gdterrors.ErrParse,
52+
api.ErrParse,
5353
)
5454
// ErrResourceSpecifierOrFilepath is returned when the test author
5555
// uses a resource specifier for the `kube.delete` fields that is not valid
5656
// or is not a filepath.
5757
ErrResourceSpecifierInvalidOrFilepath = fmt.Errorf(
5858
"%w: invalid resource specifier or filepath",
59-
gdterrors.ErrParse,
59+
api.ErrParse,
6060
)
6161
// ErrMatchesInvalid is returned when the `Kube.Assert.Matches` value is
6262
// malformed.
6363
ErrMatchesInvalid = fmt.Errorf(
6464
"%w: `kube.assert.matches` not well-formed",
65-
gdterrors.ErrParse,
65+
api.ErrParse,
6666
)
6767
// ErrConditionMatchInvalid is returned when the `Kube.Assert.Conditions`
6868
// value is malformed.
6969
ErrConditionMatchInvalid = fmt.Errorf(
7070
"%w: `kube.assert.conditions` not well-formed",
71-
gdterrors.ErrParse,
71+
api.ErrParse,
7272
)
7373
// ErrWithLabelsOnlyGetDelete is returned when the test author included
7474
// `kube.with.labels` but did not specify either `kube.get` or
7575
// `kube.delete`.
7676
ErrWithLabelsInvalid = fmt.Errorf(
7777
"%w: with labels invalid",
78-
gdterrors.ErrParse,
78+
api.ErrParse,
7979
)
8080
// ErrWithLabelsOnlyGetDelete is returned when the test author included
8181
// `kube.with.labels` but did not specify either `kube.get` or
8282
// `kube.delete`.
8383
ErrWithLabelsOnlyGetDelete = fmt.Errorf(
8484
"%w: with labels may only be specified for "+
8585
"`kube.get` or `kube.delete`",
86-
gdterrors.ErrParse,
86+
api.ErrParse,
8787
)
8888
// ErrResourceUnknown is returned when an unknown resource kind is
8989
// specified for a create/apply/delete target. This is a runtime error
9090
// because we rely on the discovery client to determine whether a resource
9191
// kind is valid.
9292
ErrResourceUnknown = fmt.Errorf(
9393
"%w: resource unknown",
94-
gdterrors.ErrFailure,
94+
api.ErrFailure,
9595
)
9696
// ErrExpectedNotFound is returned when we expected to get either a
9797
// NotFound response code (get) or an empty set of results (list) but did
9898
// not find that.
9999
ErrExpectedNotFound = fmt.Errorf(
100100
"%w: expected not found",
101-
gdterrors.ErrFailure,
101+
api.ErrFailure,
102102
)
103103
// ErrMatchesNotEqual is returned when we failed to match a resource to an
104104
// object field in a `kube.assert.matches` object.
105105
ErrMatchesNotEqual = fmt.Errorf(
106106
"%w: match field not equal",
107-
gdterrors.ErrFailure,
107+
api.ErrFailure,
108108
)
109109
// ErrConditionDoesNotMatch is returned when we failed to match a resource to an
110110
// Condition match expression in a `kube.assert.matches` object.
111111
ErrConditionDoesNotMatch = fmt.Errorf(
112112
"%w: condition does not match expectation",
113-
gdterrors.ErrFailure,
113+
api.ErrFailure,
114114
)
115115
// ErrConnect is returned when we failed to create a client config to
116116
// connect to the Kubernetes API server.
117117
ErrConnect = fmt.Errorf(
118118
"%w: k8s connect failure",
119-
gdterrors.RuntimeError,
119+
api.RuntimeError,
120120
)
121121
)
122122

eval.go

+7-8
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@ package kube
77
import (
88
"context"
99

10-
gdterrors "github.com/gdt-dev/gdt/errors"
11-
"github.com/gdt-dev/gdt/result"
10+
"github.com/gdt-dev/gdt/api"
1211
)
1312

1413
// Eval performs an action and evaluates the results of that action, returning
1514
// a Result that informs the Scenario about what failed or succeeded. A new
1615
// Kubernetes client request is made during this call.
17-
func (s *Spec) Eval(ctx context.Context) (*result.Result, error) {
16+
func (s *Spec) Eval(ctx context.Context) (*api.Result, error) {
1817
c, err := s.connect(ctx)
1918
if err != nil {
2019
return nil, ConnectError(err)
@@ -25,16 +24,16 @@ func (s *Spec) Eval(ctx context.Context) (*result.Result, error) {
2524
var out interface{}
2625
err = s.Kube.Do(ctx, c, ns, &out)
2726
if err != nil {
28-
if err == gdterrors.ErrTimeoutExceeded {
29-
return result.New(result.WithFailures(gdterrors.ErrTimeoutExceeded)), nil
27+
if err == api.ErrTimeoutExceeded {
28+
return api.NewResult(api.WithFailures(api.ErrTimeoutExceeded)), nil
3029
}
31-
if err == gdterrors.RuntimeError {
30+
if err == api.RuntimeError {
3231
return nil, err
3332
}
3433
}
3534
a := newAssertions(c, s.Assert, err, out)
3635
if a.OK(ctx) {
37-
return result.New(), nil
36+
return api.NewResult(), nil
3837
}
39-
return result.New(result.WithFailures(a.Failures()...)), nil
38+
return api.NewResult(api.WithFailures(a.Failures()...)), nil
4039
}

0 commit comments

Comments
 (0)