Skip to content

Commit fc09da3

Browse files
committedApr 29, 2020
feat: add test for v1 CRDs in registry bundle
1 parent d8d7f6b commit fc09da3

6 files changed

+522
-2
lines changed
 

‎pkg/registry/bundle.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,10 @@ func (b *Bundle) CustomResourceDefinitions() ([]interface{}, error) {
120120
return nil, err
121121
}
122122
var crds []interface{}
123-
for _, crd := range b.v1beta1crds {
123+
for _, crd := range b.v1crds {
124124
crds = append(crds, crd)
125125
}
126-
for _, crd := range b.v1crds {
126+
for _, crd := range b.v1beta1crds {
127127
crds = append(crds, crd)
128128
}
129129
return crds, nil

‎pkg/registry/bundle_test.go

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package registry
2+
3+
import (
4+
"io/ioutil"
5+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
6+
"k8s.io/apimachinery/pkg/runtime/serializer"
7+
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
8+
"path/filepath"
9+
"reflect"
10+
"strings"
11+
"testing"
12+
13+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
14+
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
15+
)
16+
17+
const (
18+
manifestDir = "./testdata/v1crd_bundle/manifests"
19+
)
20+
21+
// TestV1CRDsInBundle tests that adding a v1 and v1beta1 CRD to a bundle is successful.
22+
// The provided APIs and CRD objects in the created bundle are compared to those in a test manifest directory.
23+
func TestV1CRDsInBundle(t *testing.T) {
24+
// create bundle from manifests that include a v1 CRD
25+
bundle := NewBundle("test", "lib-bucket-provisioner", []string{"alpha"})
26+
27+
// Read all files in manifests directory
28+
items, err := ioutil.ReadDir(manifestDir)
29+
if err != nil {
30+
t.Fatalf("reading manifests directory: %s", err)
31+
}
32+
33+
// unmarshal objects into unstructured
34+
unstObjs := []*unstructured.Unstructured{}
35+
for _, item := range items {
36+
fileWithPath := filepath.Join(manifestDir, item.Name())
37+
data, err := ioutil.ReadFile(fileWithPath)
38+
if err != nil {
39+
t.Fatalf("reading manifests directory file %s: %s", fileWithPath, err)
40+
}
41+
42+
dec := k8syaml.NewYAMLOrJSONDecoder(strings.NewReader(string(data)), 30)
43+
k8sFile := &unstructured.Unstructured{}
44+
err = dec.Decode(k8sFile)
45+
if err != nil {
46+
t.Fatalf("marshaling manifest into unstructured %s: %s", k8sFile, err)
47+
}
48+
49+
t.Logf("added %s object", k8sFile.GroupVersionKind().String())
50+
unstObjs = append(unstObjs, k8sFile)
51+
}
52+
53+
// add unstructured objects to test bundle
54+
for _, object := range unstObjs {
55+
bundle.Add(object)
56+
}
57+
58+
// check provided APIs in bundle are what is expected
59+
expectedAPIs := map[APIKey]struct{}{
60+
APIKey{Group: "objectbucket.io", Version: "v1alpha1", Kind: "ObjectBucket", Plural: "objectbuckets"}: {},
61+
APIKey{Group: "objectbucket.io", Version: "v1alpha1", Kind: "ObjectBucketClaim", Plural: "objectbucketclaims"}: {},
62+
}
63+
providedAPIs, err := bundle.ProvidedAPIs()
64+
t.Logf("provided CRDs: \n%#v", providedAPIs)
65+
66+
if !reflect.DeepEqual(expectedAPIs, providedAPIs) {
67+
t.Fatalf("crds in bundle not provided: expected %#v got %#v", expectedAPIs, providedAPIs)
68+
}
69+
70+
// check CRDs in bundle are what is expected
71+
// bundle contains one v1beta1 and one v1 CRD
72+
dec := serializer.NewCodecFactory(Scheme).UniversalDeserializer()
73+
crds, err := bundle.CustomResourceDefinitions()
74+
for _, crd := range crds {
75+
switch crd.(type) {
76+
case *apiextensionsv1.CustomResourceDefinition:
77+
// objectbuckets is the v1 CRD
78+
// confirm it is equal to the manifest
79+
objectbuckets := unstObjs[2]
80+
ob, err := objectbuckets.MarshalJSON()
81+
if err != nil {
82+
t.Fatalf("objectbuckets: %s", err)
83+
}
84+
c := &apiextensionsv1.CustomResourceDefinition{}
85+
if _, _, err = dec.Decode(ob, nil, c); err != nil {
86+
t.Fatalf("error decoding v1 CRD: %s", err)
87+
}
88+
if !reflect.DeepEqual(c, crds[0]) {
89+
t.Fatalf("v1 crd not equal: expected %#v got %#v", crds[0], c)
90+
}
91+
case *apiextensionsv1beta1.CustomResourceDefinition:
92+
// objectbucketclaims is the v1beta1 CRD
93+
// confirm it is equal to the manifest
94+
objectbucketclaims := unstObjs[1]
95+
ob, err := objectbucketclaims.MarshalJSON()
96+
if err != nil {
97+
t.Fatalf("objectbucketclaims: %s", err)
98+
}
99+
c := &apiextensionsv1beta1.CustomResourceDefinition{}
100+
if _, _, err = dec.Decode(ob, nil, c); err != nil {
101+
t.Fatalf("error decoding v1beta1 CRD: %s", err)
102+
}
103+
if !reflect.DeepEqual(c, crds[1]) {
104+
t.Fatalf("v1beta1 crd not equal: expected %#v got %#v", crds[1], c)
105+
}
106+
}
107+
}
108+
}

‎pkg/registry/testdata/v1crd_bundle/manifests/lib-bucket-provisioner.v1.0.0.clusterserviceversion.yaml

+192
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
apiVersion: apiextensions.k8s.io/v1beta1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: objectbucketclaims.objectbucket.io
5+
spec:
6+
version: v1alpha1
7+
versions:
8+
- name: v1alpha1
9+
served: true
10+
storage: true
11+
group: objectbucket.io
12+
names:
13+
kind: ObjectBucketClaim
14+
listKind: ObjectBucketClaimList
15+
plural: objectbucketclaims
16+
singular: objectbucketclaim
17+
shortNames:
18+
- obc
19+
- obcs
20+
scope: Namespaced
21+
subresources:
22+
status: {}
23+
additionalPrinterColumns:
24+
- JSONPath: .spec.storageClassName
25+
description: StorageClass
26+
name: Storage-Class
27+
type: string
28+
- JSONPath: .status.phase
29+
description: Phase
30+
name: Phase
31+
type: string
32+
- JSONPath: .metadata.creationTimestamp
33+
name: Age
34+
type: date
35+
validation:
36+
openAPIV3Schema:
37+
properties:
38+
apiVersion:
39+
description: 'APIVersion defines the versioned schema of this representation
40+
of an object. Servers should convert recognized schemas to the latest
41+
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
42+
type: string
43+
kind:
44+
description: 'Kind is a string value representing the REST resource this
45+
object represents. Servers may infer this from the endpoint the client
46+
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
47+
type: string
48+
metadata:
49+
description: Standard object metadata.
50+
type: object
51+
spec:
52+
description: Specification of the desired behavior of the claim.
53+
properties:
54+
storageClassName:
55+
description: StorageClass names the StorageClass object representing the
56+
desired provisioner and parameters
57+
type: string
58+
bucketName:
59+
description: BucketName (not recommended) the name of the bucket. Caution!
60+
In-store bucket names may collide across namespaces. If you define
61+
the name yourself, try to make it as unique as possible.
62+
type: string
63+
generateBucketName:
64+
description: GenerateBucketName (recommended) a prefix for a bucket name to be
65+
followed by a hyphen and 5 random characters. Protects against
66+
in-store name collisions.
67+
type: string
68+
additionalConfig:
69+
description: AdditionalConfig gives providers a location to set
70+
proprietary config values (tenant, namespace, etc)
71+
additionalProperties:
72+
type: string
73+
type: object
74+
required:
75+
- storageClassName
76+
type: object
77+
status:
78+
description: Most recently observed status of the claim.
79+
properties:
80+
phase:
81+
description: ObjectBucketClaimStatusPhase is set by the controller to save the state of the provisioning process
82+
enum:
83+
- "pending"
84+
- "bound"
85+
- "released"
86+
- "failed"
87+
type: string
88+
type: object
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
apiVersion: apiextensions.k8s.io/v1
2+
kind: CustomResourceDefinition
3+
metadata:
4+
name: objectbuckets.objectbucket.io
5+
spec:
6+
versions:
7+
- name: v1alpha1
8+
served: true
9+
storage: true
10+
group: objectbucket.io
11+
names:
12+
kind: ObjectBucket
13+
listKind: ObjectBucketList
14+
plural: objectbuckets
15+
singular: objectbucket
16+
shortNames:
17+
- ob
18+
- obs
19+
scope: Cluster
20+
subresources:
21+
status: {}
22+
additionalPrinterColumns:
23+
- JSONPath: .spec.storageClassName
24+
description: StorageClass
25+
name: Storage-Class
26+
type: string
27+
- JSONPath: .spec.claimRef.namespace
28+
description: ClaimNamespace
29+
name: Claim-Namespace
30+
type: string
31+
- JSONPath: .spec.claimRef.name
32+
description: ClaimName
33+
name: Claim-Name
34+
type: string
35+
- JSONPath: .spec.reclaimPolicy
36+
description: ReclaimPolicy
37+
name: Reclaim-Policy
38+
type: string
39+
- JSONPath: .status.phase
40+
description: Phase
41+
name: Phase
42+
type: string
43+
- JSONPath: .metadata.creationTimestamp
44+
name: Age
45+
type: date
46+
validation:
47+
openAPIV3Schema:
48+
properties:
49+
apiVersion:
50+
description: 'APIVersion defines the versioned schema of this representation
51+
of an object. Servers should convert recognized schemas to the latest
52+
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
53+
type: string
54+
kind:
55+
description: 'Kind is a string value representing the REST resource this
56+
object represents. Servers may infer this from the endpoint the client
57+
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
58+
type: string
59+
metadata:
60+
description: Standard object metadata.
61+
type: object
62+
spec:
63+
description: Specification of the desired behavior of the bucket.
64+
properties:
65+
storageClassName:
66+
description: StorageClass names the StorageClass object representing the
67+
desired provisioner and parameters
68+
type: string
69+
reclaimPolicy:
70+
description: Describes a policy for end-of-life maintenance of ObjectBucket.
71+
enum:
72+
- "Delete"
73+
- "Retain"
74+
- "Recycle"
75+
type: string
76+
claimRef:
77+
description: ObjectReference to ObjectBucketClaim
78+
type: object
79+
endpoint:
80+
description: Endpoint contains all connection relevant data that an app may
81+
require for accessing the bucket
82+
properties:
83+
bucketHost:
84+
description: Bucket address hostname
85+
type: string
86+
bucketPort:
87+
description: Bucket address port
88+
type: integer
89+
bucketName:
90+
description: Bucket name
91+
type: string
92+
region:
93+
description: Bucket region
94+
type: string
95+
subRegion:
96+
description: Bucket sub-region
97+
type: string
98+
additionalConfig:
99+
description: AdditionalConfig gives providers a location to set
100+
proprietary config values (tenant, namespace, etc)
101+
additionalProperties:
102+
type: string
103+
type: object
104+
type: object
105+
additionalState:
106+
description: additionalState gives providers a location to set
107+
proprietary config values (tenant, namespace, etc)
108+
additionalProperties:
109+
type: string
110+
type: object
111+
required:
112+
- storageClassName
113+
type: object
114+
status:
115+
description: Most recently observed status of the bucket.
116+
properties:
117+
phase:
118+
description: ObjectBucketStatusPhase is set by the controller to save the
119+
state of the provisioning process
120+
enum:
121+
- "bound"
122+
- "released"
123+
- "failed"
124+
type: string
125+
type: object
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
annotations:
2+
operators.operatorframework.io.bundle.channel.default.v1: alpha
3+
operators.operatorframework.io.bundle.channels.v1: alpha
4+
operators.operatorframework.io.bundle.manifests.v1: manifests/
5+
operators.operatorframework.io.bundle.mediatype.v1: registry+v1
6+
operators.operatorframework.io.bundle.metadata.v1: metadata/
7+
operators.operatorframework.io.bundle.package.v1: lib-bucket-provisioner

0 commit comments

Comments
 (0)
Please sign in to comment.