diff --git a/docs/user-guide/petset.yaml b/docs/user-guide/petset.yaml index 5c29237c48..add3530077 100644 --- a/docs/user-guide/petset.yaml +++ b/docs/user-guide/petset.yaml @@ -14,8 +14,8 @@ spec: selector: app: nginx --- -apiVersion: apps/v1alpha1 -kind: PetSet +apiVersion: apps/v1beta1 +kind: StatefulSet metadata: name: web spec: diff --git a/test/examples_test.go b/test/examples_test.go index 6aba7203df..e41d97467c 100644 --- a/test/examples_test.go +++ b/test/examples_test.go @@ -17,7 +17,10 @@ limitations under the License. package examples_test import ( + "bufio" + "bytes" "fmt" + "io" "io/ioutil" "os" "path/filepath" @@ -153,7 +156,7 @@ func validateObject(obj runtime.Object) (errors field.ErrorList) { // Walks inDir for any json/yaml files. Converts yaml to json, and calls fn for // each file found with the contents in data. -func walkConfigFiles(inDir string, fn func(name, path string, data []byte)) error { +func walkConfigFiles(inDir string, fn func(name, path string, data [][]byte)) error { return filepath.Walk(inDir, func(path string, info os.FileInfo, err error) error { if err != nil { return err @@ -172,137 +175,151 @@ func walkConfigFiles(inDir string, fn func(name, path string, data []byte)) erro } name := strings.TrimSuffix(file, ext) + var docs [][]byte if ext == ".yaml" { - out, err := yaml.ToJSON(data) - if err != nil { - return fmt.Errorf("%s: %v", path, err) + // YAML can contain multiple documents. + splitter := yaml.NewYAMLReader(bufio.NewReader(bytes.NewBuffer(data))) + for { + doc, err := splitter.Read() + if err == io.EOF { + break + } + if err != nil { + return fmt.Errorf("%s: %v", path, err) + } + out, err := yaml.ToJSON(doc) + if err != nil { + return fmt.Errorf("%s: %v", path, err) + } + docs = append(docs, out) } - data = out + } else { + docs = append(docs, data) } - fn(name, path, data) + fn(name, path, docs) } return nil }) } func TestExampleObjectSchemas(t *testing.T) { - cases := map[string]map[string]runtime.Object{ + cases := map[string]map[string][]runtime.Object{ "../docs/user-guide/walkthrough": { - "deployment": &extensions.Deployment{}, - "deployment-update": &extensions.Deployment{}, - "pod-nginx": &api.Pod{}, - "pod-nginx-with-label": &api.Pod{}, - "pod-redis": &api.Pod{}, - "pod-with-http-healthcheck": &api.Pod{}, - "podtemplate": &api.PodTemplate{}, - "service": &api.Service{}, + "deployment": {&extensions.Deployment{}}, + "deployment-update": {&extensions.Deployment{}}, + "pod-nginx": {&api.Pod{}}, + "pod-nginx-with-label": {&api.Pod{}}, + "pod-redis": {&api.Pod{}}, + "pod-with-http-healthcheck": {&api.Pod{}}, + "podtemplate": {&api.PodTemplate{}}, + "service": {&api.Service{}}, }, "../docs/user-guide/update-demo": { - "kitten-rc": &api.ReplicationController{}, - "nautilus-rc": &api.ReplicationController{}, + "kitten-rc": {&api.ReplicationController{}}, + "nautilus-rc": {&api.ReplicationController{}}, }, "../docs/user-guide/persistent-volumes/volumes": { - "local-01": &api.PersistentVolume{}, - "local-02": &api.PersistentVolume{}, - "gce": &api.PersistentVolume{}, - "nfs": &api.PersistentVolume{}, + "local-01": {&api.PersistentVolume{}}, + "local-02": {&api.PersistentVolume{}}, + "gce": {&api.PersistentVolume{}}, + "nfs": {&api.PersistentVolume{}}, }, "../docs/user-guide/persistent-volumes/claims": { - "claim-01": &api.PersistentVolumeClaim{}, - "claim-02": &api.PersistentVolumeClaim{}, - "claim-03": &api.PersistentVolumeClaim{}, + "claim-01": {&api.PersistentVolumeClaim{}}, + "claim-02": {&api.PersistentVolumeClaim{}}, + "claim-03": {&api.PersistentVolumeClaim{}}, }, "../docs/user-guide/persistent-volumes/simpletest": { - "namespace": &api.Namespace{}, - "pod": &api.Pod{}, - "service": &api.Service{}, + "namespace": {&api.Namespace{}}, + "pod": {&api.Pod{}}, + "service": {&api.Service{}}, }, "../docs/user-guide/liveness": { - "exec-liveness": &api.Pod{}, - "http-liveness": &api.Pod{}, - "http-liveness-named-port": &api.Pod{}, + "exec-liveness": {&api.Pod{}}, + "http-liveness": {&api.Pod{}}, + "http-liveness-named-port": {&api.Pod{}}, }, "../docs/user-guide/jobs/work-queue-1": { - "job": &batch.Job{}, + "job": {&batch.Job{}}, }, "../docs/user-guide/jobs/work-queue-2": { - "job": &batch.Job{}, - "redis-pod": &api.Pod{}, - "redis-service": &api.Service{}, + "job": {&batch.Job{}}, + "redis-pod": {&api.Pod{}}, + "redis-service": {&api.Service{}}, }, "../docs/user-guide": { - "bad-nginx-deployment": &extensions.Deployment{}, - "counter-pod": &api.Pod{}, - "curlpod": &extensions.Deployment{}, - "deployment": &extensions.Deployment{}, - "ingress": &extensions.Ingress{}, - "job": &batch.Job{}, - "multi-pod": &api.Pod{}, - "new-nginx-deployment": &extensions.Deployment{}, - "nginx-app": &api.Service{}, - "nginx-deployment": &extensions.Deployment{}, - "nginx-init-containers": &api.Pod{}, - "nginx-lifecycle-deployment": &extensions.Deployment{}, - "nginx-probe-deployment": &extensions.Deployment{}, - "nginx-secure-app": &api.Service{}, - "nginx-svc": &api.Service{}, - "petset": &api.Service{}, - "pod": &api.Pod{}, - "pod-w-message": &api.Pod{}, - "redis-deployment": &extensions.Deployment{}, - "redis-resource-deployment": &extensions.Deployment{}, - "redis-secret-deployment": &extensions.Deployment{}, - "run-my-nginx": &extensions.Deployment{}, - "cronjob": &batch.CronJob{}, + "bad-nginx-deployment": {&extensions.Deployment{}}, + "counter-pod": {&api.Pod{}}, + "curlpod": {&extensions.Deployment{}}, + "deployment": {&extensions.Deployment{}}, + "ingress": {&extensions.Ingress{}}, + "job": {&batch.Job{}}, + "multi-pod": {&api.Pod{}, &api.Pod{}}, + "new-nginx-deployment": {&extensions.Deployment{}}, + "nginx-app": {&api.Service{}, &extensions.Deployment{}}, + "nginx-deployment": {&extensions.Deployment{}}, + "nginx-init-containers": {&api.Pod{}}, + "nginx-lifecycle-deployment": {&extensions.Deployment{}}, + "nginx-probe-deployment": {&extensions.Deployment{}}, + "nginx-secure-app": {&api.Service{}, &extensions.Deployment{}}, + "nginx-svc": {&api.Service{}}, + "petset": {&api.Service{}, &apps.StatefulSet{}}, + "pod": {&api.Pod{}}, + "pod-w-message": {&api.Pod{}}, + "redis-deployment": {&extensions.Deployment{}}, + "redis-resource-deployment": {&extensions.Deployment{}}, + "redis-secret-deployment": {&extensions.Deployment{}}, + "run-my-nginx": {&extensions.Deployment{}}, + "cronjob": {&batch.CronJob{}}, }, "../docs/admin": { - "daemon": &extensions.DaemonSet{}, + "daemon": {&extensions.DaemonSet{}}, }, "../docs/user-guide/downward-api": { - "dapi-pod": &api.Pod{}, - "dapi-container-resources": &api.Pod{}, + "dapi-pod": {&api.Pod{}}, + "dapi-container-resources": {&api.Pod{}}, }, "../docs/user-guide/downward-api/volume/": { - "dapi-volume": &api.Pod{}, - "dapi-volume-resources": &api.Pod{}, + "dapi-volume": {&api.Pod{}}, + "dapi-volume-resources": {&api.Pod{}}, }, "../docs/admin/namespaces": { - "namespace-dev": &api.Namespace{}, - "namespace-prod": &api.Namespace{}, + "namespace-dev": {&api.Namespace{}}, + "namespace-prod": {&api.Namespace{}}, }, "../docs/admin/limitrange": { - "invalid-pod": &api.Pod{}, - "limits": &api.LimitRange{}, - "namespace": &api.Namespace{}, - "valid-pod": &api.Pod{}, + "invalid-pod": {&api.Pod{}}, + "limits": {&api.LimitRange{}}, + "namespace": {&api.Namespace{}}, + "valid-pod": {&api.Pod{}}, }, "../docs/user-guide/logging-demo": { - "synthetic_0_25lps": &api.Pod{}, - "synthetic_10lps": &api.Pod{}, + "synthetic_0_25lps": {&api.Pod{}}, + "synthetic_10lps": {&api.Pod{}}, }, "../docs/user-guide/node-selection": { - "pod": &api.Pod{}, - "pod-with-node-affinity": &api.Pod{}, - "pod-with-pod-affinity": &api.Pod{}, + "pod": {&api.Pod{}}, + "pod-with-node-affinity": {&api.Pod{}}, + "pod-with-pod-affinity": {&api.Pod{}}, }, "../docs/admin/resourcequota": { - "best-effort": &api.ResourceQuota{}, - "compute-resources": &api.ResourceQuota{}, - "limits": &api.LimitRange{}, - "namespace": &api.Namespace{}, - "not-best-effort": &api.ResourceQuota{}, - "object-counts": &api.ResourceQuota{}, + "best-effort": {&api.ResourceQuota{}}, + "compute-resources": {&api.ResourceQuota{}}, + "limits": {&api.LimitRange{}}, + "namespace": {&api.Namespace{}}, + "not-best-effort": {&api.ResourceQuota{}}, + "object-counts": {&api.ResourceQuota{}}, }, "../docs/user-guide/secrets": { - "secret-pod": &api.Pod{}, - "secret": &api.Secret{}, - "secret-env-pod": &api.Pod{}, + "secret-pod": {&api.Pod{}}, + "secret": {&api.Secret{}}, + "secret-env-pod": {&api.Pod{}}, }, "../docs/tutorials/replicated-stateful-application": { - "mysql-services": &api.Service{}, - "mysql-configmap": &api.ConfigMap{}, - "mysql-statefulset": &apps.StatefulSet{}, + "mysql-services": {&api.Service{}, &api.Service{}}, + "mysql-configmap": {&api.ConfigMap{}}, + "mysql-statefulset": {&apps.StatefulSet{}}, }, } @@ -312,43 +329,52 @@ func TestExampleObjectSchemas(t *testing.T) { for path, expected := range cases { tested := 0 - err := walkConfigFiles(path, func(name, path string, data []byte) { - expectedType, found := expected[name] + numExpected := 0 + err := walkConfigFiles(path, func(name, path string, docs [][]byte) { + expectedTypes, found := expected[name] if !found { t.Errorf("%s: %s does not have a test case defined", path, name) return } - tested++ - if expectedType == nil { - t.Logf("skipping : %s/%s\n", path, name) + numExpected += len(expectedTypes) + if len(expectedTypes) != len(docs) { + t.Errorf("%s: number of expected types (%v) doesn't match number of docs in YAML (%v)", path, len(expectedTypes), len(docs)) return } - if strings.Contains(name, "scheduler-policy-config") { - if err := runtime.DecodeInto(schedulerapilatest.Codec, data, expectedType); err != nil { - t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(data)) + for i, data := range docs { + expectedType := expectedTypes[i] + tested++ + if expectedType == nil { + t.Logf("skipping : %s/%s\n", path, name) return } - // TODO: Add validate method for - // &schedulerapi.Policy, and remove this - // special case - } else { - codec, err := testapi.GetCodecForObject(expectedType) - if err != nil { - t.Errorf("Could not get codec for %s: %s", expectedType, err) - } - if err := runtime.DecodeInto(codec, data, expectedType); err != nil { - t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(data)) - return - } - if errors := validateObject(expectedType); len(errors) > 0 { - t.Errorf("%s did not validate correctly: %v", path, errors) + if strings.Contains(name, "scheduler-policy-config") { + if err := runtime.DecodeInto(schedulerapilatest.Codec, data, expectedType); err != nil { + t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(data)) + return + } + // TODO: Add validate method for + // &schedulerapi.Policy, and remove this + // special case + } else { + codec, err := testapi.GetCodecForObject(expectedType) + if err != nil { + t.Errorf("Could not get codec for %s: %s", expectedType, err) + } + if err := runtime.DecodeInto(codec, data, expectedType); err != nil { + t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(data)) + return + } + if errors := validateObject(expectedType); len(errors) > 0 { + t.Errorf("%s did not validate correctly: %v", path, errors) + } } } }) if err != nil { t.Errorf("Expected no error, Got %v on Path %v", err, path) } - if tested != len(expected) { + if tested != numExpected { t.Errorf("Directory %v: Expected %d examples, Got %d", path, len(expected), tested) } }