package validation import ( "testing" kapi "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/util/validation/field" "github.com/openshift/origin/pkg/project/api" ) func TestValidateProject(t *testing.T) { testCases := []struct { name string project api.Project numErrs int }{ { name: "missing id", project: api.Project{ ObjectMeta: kapi.ObjectMeta{ Annotations: map[string]string{ api.ProjectDescription: "This is a description", api.ProjectDisplayName: "hi", }, }, }, // Should fail because the ID is missing. numErrs: 1, }, { name: "invalid id", project: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "141-.124.$", Annotations: map[string]string{ api.ProjectDescription: "This is a description", api.ProjectDisplayName: "hi", }, }, }, // Should fail because the ID is invalid. numErrs: 1, }, { name: "invalid id uppercase", project: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "AA", }, }, numErrs: 1, }, { name: "valid id leading number", project: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "11", }, }, numErrs: 0, }, { name: "invalid id for create (< 2 characters)", project: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "h", }, }, numErrs: 1, }, { name: "valid id for create (2+ characters)", project: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "hi", }, }, numErrs: 0, }, { name: "invalid id internal dots", project: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "1.a.1", }, }, numErrs: 1, }, { name: "has namespace", project: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "foo", Namespace: "foo", Annotations: map[string]string{ api.ProjectDescription: "This is a description", api.ProjectDisplayName: "hi", }, }, }, // Should fail because the namespace is supplied. numErrs: 1, }, { name: "invalid display name", project: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "foo", Namespace: "", Annotations: map[string]string{ api.ProjectDescription: "This is a description", api.ProjectDisplayName: "h\t\ni", }, }, }, // Should fail because the display name has \t \n numErrs: 1, }, { name: "valid node selector", project: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "foo", Namespace: "", Annotations: map[string]string{ api.ProjectNodeSelector: "infra=true, env = test", }, }, }, numErrs: 0, }, { name: "invalid node selector", project: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "foo", Namespace: "", Annotations: map[string]string{ api.ProjectNodeSelector: "infra, env = $test", }, }, }, // Should fail because infra and $test doesn't satisfy the format numErrs: 1, }, } for _, tc := range testCases { errs := ValidateProject(&tc.project) if len(errs) != tc.numErrs { t.Errorf("Unexpected error list for case %q: %+v", tc.name, errs) } } project := api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "foo", Annotations: map[string]string{ api.ProjectDescription: "This is a description", api.ProjectDisplayName: "hi", }, }, } errs := ValidateProject(&project) if len(errs) != 0 { t.Errorf("Unexpected non-zero error list: %#v", errs) } } func TestValidateProjectUpdate(t *testing.T) { // Ensure we can update projects with short names, to make sure we can // proxy updates to namespaces created outside project validation project := &api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "project-name", ResourceVersion: "1", Annotations: map[string]string{ api.ProjectDescription: "This is a description", api.ProjectDisplayName: "display name", api.ProjectNodeSelector: "infra=true, env = test", }, Labels: map[string]string{"label-name": "value"}, }, } updateDisplayname := &api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "project-name", ResourceVersion: "1", Annotations: map[string]string{ api.ProjectDescription: "This is a description", api.ProjectDisplayName: "display name change", api.ProjectNodeSelector: "infra=true, env = test", }, Labels: map[string]string{"label-name": "value"}, }, } errs := ValidateProjectUpdate(updateDisplayname, project) if len(errs) > 0 { t.Fatalf("Expected no errors, got %v", errs) } errorCases := map[string]struct { A api.Project T field.ErrorType F string }{ "change name": { A: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "different", ResourceVersion: "1", Annotations: project.Annotations, Labels: project.Labels, }, }, T: field.ErrorTypeInvalid, F: "metadata.name", }, "invalid displayname": { A: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "project-name", ResourceVersion: "1", Annotations: map[string]string{ api.ProjectDescription: "This is a description", api.ProjectDisplayName: "display name\n", api.ProjectNodeSelector: "infra=true, env = test", }, Labels: project.Labels, }, }, T: field.ErrorTypeInvalid, F: "metadata.annotations[" + api.ProjectDisplayName + "]", }, "updating disallowed annotation": { A: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "project-name", ResourceVersion: "1", Annotations: map[string]string{ api.ProjectDescription: "This is a description", api.ProjectDisplayName: "display name", api.ProjectNodeSelector: "infra=true, env = test2", }, Labels: project.Labels, }, }, T: field.ErrorTypeInvalid, F: "metadata.annotations[openshift.io/node-selector]", }, "delete annotation": { A: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "project-name", ResourceVersion: "1", Annotations: map[string]string{ api.ProjectDescription: "This is a description", api.ProjectDisplayName: "display name", }, Labels: project.Labels, }, }, T: field.ErrorTypeInvalid, F: "metadata.annotations[openshift.io/node-selector]", }, "updating label": { A: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "project-name", ResourceVersion: "1", Annotations: project.Annotations, Labels: map[string]string{"label-name": "diff"}, }, }, T: field.ErrorTypeInvalid, F: "metadata.labels[label-name]", }, "deleting label": { A: api.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "project-name", ResourceVersion: "1", Annotations: project.Annotations, }, }, T: field.ErrorTypeInvalid, F: "metadata.labels[label-name]", }, } for k, v := range errorCases { errs := ValidateProjectUpdate(&v.A, project) if len(errs) == 0 { t.Errorf("expected failure %s for %v", k, v.A) continue } for i := range errs { if errs[i].Type != v.T { t.Errorf("%s: expected errors to have type %s: %v", k, v.T, errs[i]) } if errs[i].Field != v.F { t.Errorf("%s: expected errors to have field %s: %v", k, v.F, errs[i]) } } } }