Updating api/validation/schema_test to test testapi.Version rather than just v1beta1

pull/6/head
nikhiljindal 2015-04-14 11:31:12 -07:00
parent 86d3072492
commit 40842e4471
14 changed files with 303 additions and 2238 deletions

View File

@ -78,7 +78,14 @@ func main() {
if err != nil {
log.Fatalf("Couldn't read from input: %q", err)
}
isYAML := isYAML(data)
if isYAML {
data, err = yaml.YAMLToJSON(data)
if err != nil {
log.Fatalf("Failed to convert YAML to JSON: %q", err)
}
}
obj, err := api.Scheme.Decode(data)
if err != nil {
log.Fatalf("Couldn't decode input: %q", err)
@ -89,7 +96,7 @@ func main() {
log.Fatalf("Failed to encode to version %q: %q", *outputVersion, err)
}
if isYAML(data) {
if isYAML {
outData, err = yaml.JSONToYAML(outData)
if err != nil {
log.Fatalf("Failed to convert to YAML: %q", err)

View File

@ -73,7 +73,10 @@ func (s *SwaggerSchema) ValidateBytes(data []byte) error {
if err := json.Unmarshal(data, &obj); err != nil {
return err
}
fields := obj.(map[string]interface{})
fields, ok := obj.(map[string]interface{})
if !ok {
return fmt.Errorf("error in unmarshaling data %s", string(data))
}
apiVersion := fields["apiVersion"].(string)
kind := fields["kind"].(string)
return s.ValidateObject(obj, apiVersion, "", apiVersion+"."+kind)
@ -84,25 +87,37 @@ func (s *SwaggerSchema) ValidateObject(obj interface{}, apiVersion, fieldName, t
// TODO: handle required fields here too.
model, ok := models[typeName]
if !ok {
glog.V(2).Infof("couldn't find type: %s, skipping validation", typeName)
return nil
return fmt.Errorf("couldn't find type: %s", typeName)
}
properties := model.Properties
fields := obj.(map[string]interface{})
if len(properties) == 0 {
// The object does not have any sub-fields.
return nil
}
fields, ok := obj.(map[string]interface{})
if !ok {
return fmt.Errorf("expected object of type map[string]interface{} as value of %s field", fieldName)
}
if len(fieldName) > 0 {
fieldName = fieldName + "."
}
for key, value := range fields {
details, ok := properties[key]
if !ok {
glog.V(2).Infof("couldn't find properties for %s, skipping", key)
// Some properties can be missing because of
// https://github.com/GoogleCloudPlatform/kubernetes/issues/6842.
glog.V(2).Infof("couldn't find properties for %s", key)
continue
}
if details.Type == nil {
glog.V(2).Infof("nil details for %s, skipping", key)
continue
if details.Type == nil && details.Ref == nil {
return fmt.Errorf("could not find the type of %s from object: %v", key, details)
}
var fieldType string
if details.Type != nil {
fieldType = *details.Type
} else {
fieldType = *details.Ref
}
fieldType := *details.Type
if value == nil {
glog.V(2).Infof("Skipping nil field: %s", key)
continue
@ -134,7 +149,15 @@ func (s *SwaggerSchema) validateField(value interface{}, apiVersion, fieldName,
if !ok {
return NewInvalidTypeError(reflect.Array, reflect.TypeOf(value).Kind(), fieldName)
}
arrType := *fieldDetails.Items.Ref
var arrType string
if fieldDetails.Items.Ref == nil && fieldDetails.Items.Type == nil {
return NewInvalidTypeError(reflect.Array, reflect.TypeOf(value).Kind(), fieldName)
}
if fieldDetails.Items.Ref != nil {
arrType = *fieldDetails.Items.Ref
} else {
arrType = *fieldDetails.Items.Type
}
for ix := range arr {
err := s.validateField(arr[ix], apiVersion, fmt.Sprintf("%s[%d]", fieldName, ix), arrType, nil)
if err != nil {
@ -156,6 +179,7 @@ func (s *SwaggerSchema) validateField(value interface{}, apiVersion, fieldName,
if _, ok := value.(bool); !ok {
return NewInvalidTypeError(reflect.Bool, reflect.TypeOf(value).Kind(), fieldName)
}
case "any":
default:
return fmt.Errorf("unexpected type: %v", fieldType)
}

View File

@ -22,13 +22,22 @@ import (
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi"
apitesting "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
func LoadSchemaForTest(file string) (Schema, error) {
data, err := ioutil.ReadFile(file)
func readPod(filename string) (string, error) {
data, err := ioutil.ReadFile("testdata/" + testapi.Version() + "/" + filename)
if err != nil {
return "", err
}
return string(data), nil
}
func loadSchemaForTest() (Schema, error) {
pathToSwaggerSpec := "../../../api/swagger-spec/" + testapi.Version() + ".json"
data, err := ioutil.ReadFile(pathToSwaggerSpec)
if err != nil {
return nil, err
}
@ -36,14 +45,14 @@ func LoadSchemaForTest(file string) (Schema, error) {
}
func TestLoad(t *testing.T) {
_, err := LoadSchemaForTest("v1beta1-swagger.json")
_, err := loadSchemaForTest()
if err != nil {
t.Errorf("Failed to load: %v", err)
}
}
func TestValidateOk(t *testing.T) {
schema, err := LoadSchemaForTest("v1beta1-swagger.json")
schema, err := loadSchemaForTest()
if err != nil {
t.Errorf("Failed to load: %v", err)
}
@ -62,7 +71,7 @@ func TestValidateOk(t *testing.T) {
for _, test := range tests {
testObj := test.obj
apiObjectFuzzer.Fuzz(testObj)
data, err := v1beta1.Codec.Encode(testObj)
data, err := testapi.Codec().Encode(testObj)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
@ -74,150 +83,45 @@ func TestValidateOk(t *testing.T) {
}
}
var invalidPod = `{
"id": "name",
"kind": "Pod",
"apiVersion": "v1beta1",
"desiredState": {
"manifest": {
"version": "v1beta1",
"id": "redis-master",
"containers": [{
"name": "master",
"image": "dockerfile/redis",
"command": "this is a bad command",
}]
}
},
"labels": {
"name": "redis-master"
}
}
`
var invalidPod2 = `{
"apiVersion": "v1beta1",
"kind": "Pod",
"id": "apache-php",
"desiredState": {
"manifest": {
"version": "v1beta1",
"id": "apache-php",
"containers": [{
"name": "apache-php",
"image": "php:5.6.2-apache",
"ports": [{ "name": "apache", "containerPort": 80, "hostPort":"13380", "protocol":"TCP" }],
"volumeMounts": [{"name": "shared-disk","mountPath": "/var/www/html", "readOnly": false}]
}]
}
},
"labels": { "name": "apache-php" },
"restartPolicy": {"always": {}},
"dnsPolicy": "ClusterFirst",
"volumes": [
"name": "shared-disk",
"source": {
"GCEPersistentDisk": {
"path": "shared-disk"
}
}
]
}
`
var invalidPod3 = `{
"apiVersion": "v1beta1",
"kind": "Pod",
"id": "apache-php",
"desiredState": {
"manifest": {
"version": "v1beta1",
"id": "apache-php",
"containers": [{
"name": "apache-php",
"image": "php:5.6.2-apache",
"ports": [{ "name": "apache", "containerPort": 80, "hostPort":"13380", "protocol":"TCP" }],
"volumeMounts": [{"name": "shared-disk","mountPath": "/var/www/html", "readOnly": false}]
}]
}
},
"labels": { "name": "apache-php" },
"restartPolicy": {"always": {}},
"dnsPolicy": "ClusterFirst",
"volumes": [
{
"name": "shared-disk",
"source": {
"GCEPersistentDisk": {
"path": "shared-disk"
}
}
}
]
}
`
var invalidYaml = `
id: name
kind: Pod
apiVersion: v1beta1
desiredState:
manifest:
version: v1beta1
id: redis-master
containers:
- name: "master"
image: "dockerfile/redis"
command: "this is a bad command"
labels:
name: "redis-master"
`
func TestInvalid(t *testing.T) {
schema, err := LoadSchemaForTest("v1beta1-swagger.json")
schema, err := loadSchemaForTest()
if err != nil {
t.Errorf("Failed to load: %v", err)
}
tests := []string{invalidPod, invalidPod2, invalidPod3, invalidYaml}
tests := []string{
"invalidPod1.json", // command is a string, instead of []string.
"invalidPod2.json", // hostPort if of type string, instead of int.
"invalidPod3.json", // volumes is not an array of objects.
"invalidPod.yaml", // command is a string, instead of []string.
}
for _, test := range tests {
err = schema.ValidateBytes([]byte(test))
pod, err := readPod(test)
if err != nil {
t.Errorf("could not read file: %s", pod)
}
err = schema.ValidateBytes([]byte(pod))
if err == nil {
t.Errorf("unexpected non-error\n%s", test)
t.Errorf("unexpected non-error, err: %s for pod: %s", err, pod)
}
}
}
var validYaml = `
id: name
kind: Pod
apiVersion: v1beta1
desiredState:
manifest:
version: v1beta1
id: redis-master
containers:
- name: "master"
image: "dockerfile/redis"
command:
- this
- is
- an
- ok
- command
labels:
name: "redis-master"
`
func TestValid(t *testing.T) {
schema, err := LoadSchemaForTest("v1beta1-swagger.json")
schema, err := loadSchemaForTest()
if err != nil {
t.Errorf("Failed to load: %v", err)
}
tests := []string{validYaml}
tests := []string{
"validPod.yaml",
}
for _, test := range tests {
err = schema.ValidateBytes([]byte(test))
if err == nil {
t.Errorf("unexpected non-error\n%s", test)
pod, err := readPod(test)
if err != nil {
t.Errorf("could not read file: %s", test)
}
err = schema.ValidateBytes([]byte(pod))
if err != nil {
t.Errorf("unexpected error %s, for pod %s", err, pod)
}
}
}

View File

@ -0,0 +1,13 @@
kind: Pod
apiVersion: v1beta1
id: name
desiredState:
manifest:
version: v1beta1
id: redis-master
containers:
- name: "master"
image: "dockerfile/redis"
command: "this is a bad command"
labels:
name: "redis-master"

View File

@ -0,0 +1,19 @@
{
"id": "name",
"kind": "Pod",
"apiVersion": "v1beta1",
"desiredState": {
"manifest": {
"version": "v1beta1",
"id": "redis-master",
"containers": [{
"name": "master",
"image": "dockerfile/redis",
"command": "this is a bad command"
}]
}
},
"labels": {
"name": "redis-master"
}
}

View File

@ -0,0 +1,28 @@
{
"apiVersion": "v1beta1",
"kind": "Pod",
"id": "apache-php",
"desiredState": {
"manifest": {
"version": "v1beta1",
"id": "apache-php",
"containers": [{
"name": "apache-php",
"image": "php:5.6.2-apache",
"ports": [{ "name": "apache", "containerPort": 80, "hostPort":"13380", "protocol":"TCP" }],
"volumeMounts": [{"name": "shared-disk","mountPath": "/var/www/html", "readOnly": false}]
}],
"restartPolicy": {"always": {}},
"dnsPolicy": "ClusterFirst",
"volumes": [{
"name": "shared-disk",
"source": {
"GCEPersistentDisk": {
"path": "shared-disk"
}
}
}]
}
},
"labels": { "name": "apache-php" }
}

View File

@ -0,0 +1,28 @@
{
"apiVersion": "v1beta1",
"kind": "Pod",
"id": "apache-php",
"desiredState": {
"manifest": {
"version": "v1beta1",
"id": "apache-php",
"containers": [{
"name": "apache-php",
"image": "php:5.6.2-apache",
"ports": [{ "name": "apache", "containerPort": 80, "hostPort":13380, "protocol":"TCP" }],
"volumeMounts": [{"name": "shared-disk","mountPath": "/var/www/html", "readOnly": false}]
}],
"restartPolicy": {"always": {}},
"dnsPolicy": "ClusterFirst",
"volumes": [
"name": "shared-disk",
"source": {
"GCEPersistentDisk": {
"path": "shared-disk"
}
}
]
}
},
"labels": { "name": "apache-php" }
}

View File

@ -0,0 +1,18 @@
id: name
kind: Pod
apiVersion: v1beta1
desiredState:
manifest:
version: v1beta1
id: redis-master
containers:
- name: "master"
image: "dockerfile/redis"
command:
- this
- is
- an
- ok
- command
labels:
name: "redis-master"

View File

@ -0,0 +1,11 @@
apiVersion: v1beta3
kind: Pod
metadata:
labels:
name: redis-master
name: name
spec:
containers:
- args: "this is a bad command"
image: dockerfile/redis
name: master

View File

@ -0,0 +1,19 @@
{
"kind": "Pod",
"apiVersion": "v1beta3",
"metadata": {
"name": "name",
"labels": {
"name": "redis-master"
}
},
"spec": {
"containers": [
{
"name": "master",
"image": "dockerfile/redis",
"args": "this is a bad command"
}
]
}
}

View File

@ -0,0 +1,35 @@
{
"kind": "Pod",
"apiVersion": "v1beta3",
"metadata": {
"name": "apache-php",
"labels": {
"name": "apache-php"
}
},
"spec": {
"volumes": [{
"name": "shared-disk"
}],
"containers": [
{
"name": "apache-php",
"image": "php:5.6.2-apache",
"ports": [
{
"name": "apache",
"hostPort": "13380",
"containerPort": 80,
"protocol": "TCP"
}
],
"volumeMounts": [
{
"name": "shared-disk",
"mountPath": "/var/www/html"
}
]
}
]
}
}

View File

@ -0,0 +1,35 @@
{
"kind": "Pod",
"apiVersion": "v1beta3",
"metadata": {
"name": "apache-php",
"labels": {
"name": "apache-php"
}
},
"spec": {
"volumes": [
"name": "shared-disk"
],
"containers": [
{
"name": "apache-php",
"image": "php:5.6.2-apache",
"ports": [
{
"name": "apache",
"hostPort": 13380,
"containerPort": 80,
"protocol": "TCP"
}
],
"volumeMounts": [
{
"name": "shared-disk",
"mountPath": "/var/www/html"
}
]
}
]
}
}

View File

@ -0,0 +1,16 @@
apiVersion: v1beta3
kind: Pod
metadata:
labels:
name: redis-master
name: name
spec:
containers:
- args:
- this
- is
- an
- ok
- command
image: dockerfile/redis
name: master

File diff suppressed because it is too large Load Diff