Set up examples gate job for 1.11 (#9345)
There were things changed upstream which have blocked the examples test from running correctly: - PodSecurityPolicy has been MOVED from extensions API group into policy. All samples that are using this resource type needs a change. - The 'GetCodecForObject()' function in testapi/testapi package was removed in 1.11 for unknown reasons. This change has broken our job as well as the test code in the kubernetes/examples project. - Kubernetes is now using 1.10.2+ verion of Go for compilation so we have to change the .travis.yml accordingly. This PR fixes the above problems. Note also, the `TestReadme` function is **removed** for two reasons: - It is only testing the snippets in the `volumes.md` file which is now broken because of the introduction of service account token injection. - It is regarded as too aggressive/restrictive a test. We cannot guarantee that YAML snippets in the markdown files are complete and can be used as is. Instead I believe we should encourage people to use template snippets that contain the **key** information for a topic. When we see a need for a full template that can be used directly, we may want to extract the YAML contents into the `examples` subdirectory.
This commit is contained in:
+2
-2
@@ -1,6 +1,6 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.9.3
|
||||
- 1.10.2
|
||||
|
||||
# Don't want default ./... here:
|
||||
install:
|
||||
@@ -10,7 +10,7 @@ install:
|
||||
# Fetch dependencies for us to run the tests in test/examples_test.go
|
||||
- go get -t -v k8s.io/website/test
|
||||
# Make sure we are testing against the correct branch
|
||||
- pushd $GOPATH/src/k8s.io/kubernetes && git checkout release-1.10 && popd
|
||||
- pushd $GOPATH/src/k8s.io/kubernetes && git checkout release-1.11 && popd
|
||||
|
||||
# Simplified deduplication of dependencies.
|
||||
- cp -L -R $GOPATH/src/k8s.io/kubernetes/vendor/ $GOPATH/src/
|
||||
|
||||
+35
-97
@@ -24,7 +24,6 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -33,6 +32,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/apis/admissionregistration"
|
||||
ar_validation "k8s.io/kubernetes/pkg/apis/admissionregistration/validation"
|
||||
@@ -59,6 +59,33 @@ import (
|
||||
schedulerapilatest "k8s.io/kubernetes/pkg/scheduler/api/latest"
|
||||
)
|
||||
|
||||
func getCodecForObject(obj runtime.Object) (runtime.Codec, error) {
|
||||
kinds, _, err := legacyscheme.Scheme.ObjectKinds(obj)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unexpected encoding error: %v", err)
|
||||
}
|
||||
kind := kinds[0]
|
||||
|
||||
for _, group := range testapi.Groups {
|
||||
if group.GroupVersion().Group != kind.Group {
|
||||
continue
|
||||
}
|
||||
|
||||
if legacyscheme.Scheme.Recognizes(kind) {
|
||||
return group.Codec(), nil
|
||||
}
|
||||
}
|
||||
// Codec used for unversioned types
|
||||
if legacyscheme.Scheme.Recognizes(kind) {
|
||||
serializer, ok := runtime.SerializerInfoForMediaType(legacyscheme.Codecs.SupportedMediaTypes(), runtime.ContentTypeJSON)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no serializer registered for json")
|
||||
}
|
||||
return serializer.Serializer, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected kind: %v", kind)
|
||||
}
|
||||
|
||||
func validateObject(obj runtime.Object) (errors field.ErrorList) {
|
||||
// Enable CustomPodDNS for testing
|
||||
utilfeature.DefaultFeatureGate.Set("CustomPodDNS=true")
|
||||
@@ -173,8 +200,8 @@ func validateObject(obj runtime.Object) (errors field.ErrorList) {
|
||||
t.Namespace = api.NamespaceDefault
|
||||
}
|
||||
errors = ext_validation.ValidateIngress(t)
|
||||
case *extensions.PodSecurityPolicy:
|
||||
errors = ext_validation.ValidatePodSecurityPolicy(t)
|
||||
case *policy.PodSecurityPolicy:
|
||||
errors = policy_validation.ValidatePodSecurityPolicy(t)
|
||||
case *extensions.ReplicaSet:
|
||||
if t.Namespace == "" {
|
||||
t.Namespace = api.NamespaceDefault
|
||||
@@ -289,9 +316,9 @@ func TestExampleObjectSchemas(t *testing.T) {
|
||||
"nginx-deployment": {&extensions.Deployment{}},
|
||||
},
|
||||
"docs/concepts/policy": {
|
||||
"privileged-psp": {&extensions.PodSecurityPolicy{}},
|
||||
"restricted-psp": {&extensions.PodSecurityPolicy{}},
|
||||
"example-psp": {&extensions.PodSecurityPolicy{}},
|
||||
"privileged-psp": {&policy.PodSecurityPolicy{}},
|
||||
"restricted-psp": {&policy.PodSecurityPolicy{}},
|
||||
"example-psp": {&policy.PodSecurityPolicy{}},
|
||||
},
|
||||
"docs/concepts/services-networking": {
|
||||
"curlpod": {&extensions.Deployment{}},
|
||||
@@ -308,8 +335,8 @@ func TestExampleObjectSchemas(t *testing.T) {
|
||||
"frontend": {&extensions.ReplicaSet{}},
|
||||
"hpa-rs": {&autoscaling.HorizontalPodAutoscaler{}},
|
||||
"job": {&batch.Job{}},
|
||||
"my-repset": {&extensions.ReplicaSet{}},
|
||||
"nginx-deployment": {&extensions.Deployment{}},
|
||||
"my-repset": {&extensions.ReplicaSet{}},
|
||||
"replication": {&api.ReplicationController{}},
|
||||
},
|
||||
"docs/tasks/access-application-cluster": {
|
||||
@@ -540,7 +567,7 @@ func TestExampleObjectSchemas(t *testing.T) {
|
||||
// &schedulerapi.Policy, and remove this
|
||||
// special case
|
||||
} else {
|
||||
codec, err := testapi.GetCodecForObject(expectedType)
|
||||
codec, err := getCodecForObject(expectedType)
|
||||
if err != nil {
|
||||
t.Errorf("Could not get codec for %s: %s", expectedType, err)
|
||||
}
|
||||
@@ -562,92 +589,3 @@ func TestExampleObjectSchemas(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This regex is tricky, but it works. For future me, here is the decode:
|
||||
//
|
||||
// Flags: (?ms) = multiline match, allow . to match \n
|
||||
// 1) Look for a line that starts with ``` (a markdown code block)
|
||||
// 2) (?: ... ) = non-capturing group
|
||||
// 3) (P<name>) = capture group as "name"
|
||||
// 4) Look for #1 followed by either:
|
||||
// 4a) "yaml" followed by any word-characters followed by a newline (e.g. ```yamlfoo\n)
|
||||
// 4b) "any word-characters followed by a newline (e.g. ```json\n)
|
||||
// 5) Look for either:
|
||||
// 5a) #4a followed by one or more characters (non-greedy)
|
||||
// 5b) #4b followed by { followed by one or more characters (non-greedy) followed by }
|
||||
// 6) Look for #5 followed by a newline followed by ``` (end of the code block)
|
||||
//
|
||||
// This could probably be simplified, but is already too delicate. Before any
|
||||
// real changes, we should have a test case that just tests this regex.
|
||||
var sampleRegexp = regexp.MustCompile("(?ms)^```(?:(?P<type>yaml)\\w*\\n(?P<content>.+?)|\\w*\\n(?P<content>\\{.+?\\}))\\n^```")
|
||||
var subsetRegexp = regexp.MustCompile("(?ms)\\.{3}")
|
||||
|
||||
// Validates examples embedded in Markdown files.
|
||||
func TestReadme(t *testing.T) {
|
||||
// BlockVolume required for local volume example
|
||||
utilfeature.DefaultFeatureGate.Set("BlockVolume=true")
|
||||
|
||||
paths := []struct {
|
||||
file string
|
||||
expectedType []runtime.Object // List of all valid types for the whole doc
|
||||
}{
|
||||
{"../content/en/docs/concepts/storage/volumes.md", []runtime.Object{
|
||||
&api.Pod{},
|
||||
&api.PersistentVolume{},
|
||||
}},
|
||||
}
|
||||
|
||||
for _, path := range paths {
|
||||
data, err := ioutil.ReadFile(path.file)
|
||||
if err != nil {
|
||||
t.Errorf("Unable to read file %s: %v", path, err)
|
||||
continue
|
||||
}
|
||||
|
||||
matches := sampleRegexp.FindAllStringSubmatch(string(data), -1)
|
||||
if matches == nil {
|
||||
continue
|
||||
}
|
||||
for _, match := range matches {
|
||||
var content, subtype string
|
||||
for i, name := range sampleRegexp.SubexpNames() {
|
||||
if name == "type" {
|
||||
subtype = match[i]
|
||||
}
|
||||
if name == "content" && match[i] != "" {
|
||||
content = match[i]
|
||||
}
|
||||
}
|
||||
if subtype == "yaml" && subsetRegexp.FindString(content) != "" {
|
||||
t.Logf("skipping (%s): \n%s", subtype, content)
|
||||
continue
|
||||
}
|
||||
|
||||
json, err := yaml.ToJSON([]byte(content))
|
||||
if err != nil {
|
||||
t.Errorf("%s could not be converted to JSON: %v\n%s", path, err, string(content))
|
||||
}
|
||||
|
||||
var expectedType runtime.Object
|
||||
for _, expectedType = range path.expectedType {
|
||||
err = runtime.DecodeInto(testapi.Default.Codec(), json, expectedType)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(content))
|
||||
continue
|
||||
}
|
||||
|
||||
if errors := validateObject(expectedType); len(errors) > 0 {
|
||||
t.Errorf("%s did not validate correctly: %v", path, errors)
|
||||
}
|
||||
_, err = runtime.Encode(testapi.Default.Codec(), expectedType)
|
||||
if err != nil {
|
||||
t.Errorf("Could not encode object: %v", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user