package examples
import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"testing"
"github.com/golang/glog"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
kvalidation "k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/capabilities"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/yaml"
"github.com/openshift/origin/pkg/api/validation"
buildapi "github.com/openshift/origin/pkg/build/api"
deployapi "github.com/openshift/origin/pkg/deploy/api"
imageapi "github.com/openshift/origin/pkg/image/api"
projectapi "github.com/openshift/origin/pkg/project/api"
routeapi "github.com/openshift/origin/pkg/route/api"
sdnapi "github.com/openshift/origin/pkg/sdn/api"
templateapi "github.com/openshift/origin/pkg/template/api"
// install all APIs
_ "github.com/openshift/origin/pkg/api/install"
_ "k8s.io/kubernetes/pkg/api/install"
_ "k8s.io/kubernetes/pkg/apis/extensions/install"
)
type mockService struct{}
func (mockService) ListServices(kapi.Context) (*kapi.ServiceList, error) {
return &kapi.ServiceList{}, nil
}
func walkJSONFiles(inDir string, fn func(name, path string, data []byte)) error {
err := filepath.Walk(inDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() && path != inDir {
return filepath.SkipDir
}
name := filepath.Base(path)
ext := filepath.Ext(name)
if ext != "" {
name = name[:len(name)-len(ext)]
}
if !(ext == ".json" || ext == ".yaml") {
return nil
}
glog.Infof("testing %s", path)
data, err := ioutil.ReadFile(path)
if err != nil {
return err
}
if ext == ".yaml" {
data, err = yaml.ToJSON(data)
if err != nil {
return err
}
}
fn(name, path, data)
return nil
})
return err
}
func TestExampleObjectSchemas(t *testing.T) {
// Allow privileged containers
// TODO: make this configurable and not the default https://github.com/openshift/origin/issues/662
capabilities.Setup(true, capabilities.PrivilegedSources{}, 0)
cases := map[string]map[string]runtime.Object{
"../examples/wordpress/template": {
"wordpress-mysql": &templateapi.Template{},
},
"../examples/hello-openshift": {
"hello-pod": &kapi.Pod{},
"hello-project": &projectapi.Project{},
},
"../examples/sample-app": {
"github-webhook-example": nil, // Skip.
"application-template-stibuild": &templateapi.Template{},
"application-template-dockerbuild": &templateapi.Template{},
"application-template-custombuild": &templateapi.Template{},
"application-template-pullspecbuild": &templateapi.Template{},
},
"../examples/jenkins": {
"jenkins-ephemeral-template": &templateapi.Template{},
"jenkins-persistent-template": &templateapi.Template{},
"application-template": &templateapi.Template{},
},
"../examples/image-streams": {
"image-streams-centos7": &imageapi.ImageStreamList{},
"image-streams-rhel7": &imageapi.ImageStreamList{},
},
"../examples/db-templates": {
"mysql-persistent-template": &templateapi.Template{},
"postgresql-persistent-template": &templateapi.Template{},
"mongodb-persistent-template": &templateapi.Template{},
"mariadb-persistent-template": &templateapi.Template{},
"redis-persistent-template": &templateapi.Template{},
"mysql-ephemeral-template": &templateapi.Template{},
"postgresql-ephemeral-template": &templateapi.Template{},
"mongodb-ephemeral-template": &templateapi.Template{},
"mariadb-ephemeral-template": &templateapi.Template{},
"redis-ephemeral-template": &templateapi.Template{},
},
"../test/extended/testdata/ldap": {
"ldapserver-buildconfig": &buildapi.BuildConfig{},
"ldapserver-deploymentconfig": &deployapi.DeploymentConfig{},
"ldapserver-imagestream": &imageapi.ImageStream{},
"ldapserver-imagestream-testenv": &imageapi.ImageStream{},
"ldapserver-service": &kapi.Service{},
},
"../test/integration/testdata": {
// TODO fix this test to handle json and yaml
"project-request-template-with-quota": nil, // skip a yaml file
"test-deployment-config": &deployapi.DeploymentConfig{},
"test-image": &imageapi.Image{},
"test-image-stream": &imageapi.ImageStream{},
"test-image-stream-mapping": nil, // skip &imageapi.ImageStreamMapping{},
"test-route": &routeapi.Route{},
"test-service": &kapi.Service{},
"test-service-with-finalizer": &kapi.Service{},
"test-buildcli": &kapi.List{},
"test-buildcli-beta2": &kapi.List{},
"test-egress-network-policy": &sdnapi.EgressNetworkPolicy{},
},
"../test/templates/testdata": {
"crunchydata-pod": nil, // Explicitly fails validation, but should pass transformation
"guestbook_list": &templateapi.Template{},
"guestbook": &templateapi.Template{},
},
}
for path, expected := range cases {
tested := 0
err := walkJSONFiles(path, func(name, path string, data []byte) {
expectedType, found := expected[name]
if !found {
t.Errorf("%s does not have a test case defined", path)
return
}
tested += 1
if expectedType == nil {
t.Logf("%q is skipped", path)
return
}
if err := runtime.DecodeInto(kapi.Codecs.UniversalDecoder(), data, expectedType); err != nil {
t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(data))
return
}
validateObject(path, expectedType, t)
})
if err != nil {
t.Errorf("Expected no error, Got %v", err)
}
if tested != len(expected) {
t.Errorf("Expected %d examples, Got %d", len(expected), tested)
}
}
}
func validateObject(path string, obj runtime.Object, t *testing.T) {
// if an object requires a namespace server side, be sure that it is filled in for validation
if validation.HasObjectMeta(obj) {
namespaceRequired, err := validation.GetRequiresNamespace(obj)
if err != nil {
t.Errorf("Expected no error, Got %v", err)
return
}
if namespaceRequired {
objectMeta, objectMetaErr := kapi.ObjectMetaFor(obj)
if objectMetaErr != nil {
t.Errorf("Expected no error, Got %v", objectMetaErr)
return
}
objectMeta.Namespace = kapi.NamespaceDefault
}
}
switch typedObj := obj.(type) {
case *kapi.Pod:
if errors := kvalidation.ValidatePod(typedObj); len(errors) > 0 {
t.Errorf("%s did not validate correctly: %v", path, errors)
}
case *kapi.Service:
if errors := kvalidation.ValidateService(typedObj); len(errors) > 0 {
t.Errorf("%s did not validate correctly: %v", path, errors)
}
case *kapi.List, *imageapi.ImageStreamList:
if list, err := meta.ExtractList(typedObj); err == nil {
runtime.DecodeList(list, kapi.Codecs.UniversalDecoder())
for i := range list {
validateObject(path, list[i], t)
}
} else {
t.Errorf("Expected no error, Got %v", err)
}
default:
if errors := validation.Validator.Validate(obj); len(errors) > 0 {
t.Errorf("%s with %v did not validate correctly: %v", path, reflect.TypeOf(obj), errors)
}
}
}
func TestReadme(t *testing.T) {
path := "../README.md"
_, err := ioutil.ReadFile(path)
if err != nil {
t.Fatalf("Unable to read file: %v", err)
}
}