package validation
import (
"reflect"
"strings"
"testing"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/util/validation/field"
buildapi "github.com/openshift/origin/pkg/build/api"
_ "github.com/openshift/origin/pkg/build/api/install"
)
func TestBuildValidationSuccess(t *testing.T) {
build := &buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Name: "buildid", Namespace: "default"},
Spec: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
Status: buildapi.BuildStatus{
Phase: buildapi.BuildPhaseNew,
},
}
if result := ValidateBuild(build); len(result) > 0 {
t.Errorf("Unexpected validation error returned %v", result)
}
}
func checkDockerStrategyEmptySourceError(result field.ErrorList) bool {
for _, err := range result {
if err.Type == field.ErrorTypeInvalid && strings.Contains(err.Field, "spec.source") && strings.Contains(err.Detail, "must provide a value for at least one source input(git, binary, dockerfile, images).") {
return true
}
}
return false
}
func TestBuildEmptySource(t *testing.T) {
builds := []buildapi.Build{
{
ObjectMeta: kapi.ObjectMeta{Name: "buildid", Namespace: "default"},
Spec: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{},
Strategy: buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{
From: kapi.ObjectReference{
Kind: "DockerImage",
Name: "myimage:tag",
},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
Status: buildapi.BuildStatus{
Phase: buildapi.BuildPhaseNew,
},
},
{
ObjectMeta: kapi.ObjectMeta{Name: "buildid", Namespace: "default"},
Spec: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{},
Strategy: buildapi.BuildStrategy{
CustomStrategy: &buildapi.CustomBuildStrategy{
From: kapi.ObjectReference{
Kind: "DockerImage",
Name: "myimage:tag",
},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
Status: buildapi.BuildStatus{
Phase: buildapi.BuildPhaseNew,
},
},
}
for _, build := range builds {
if result := ValidateBuild(&build); len(result) > 0 {
t.Errorf("Unexpected validation error returned %v", result)
}
}
badBuild := &buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Name: "buildid", Namespace: "default"},
Spec: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
Status: buildapi.BuildStatus{
Phase: buildapi.BuildPhaseNew,
},
}
if result := ValidateBuild(badBuild); len(result) == 0 {
t.Error("An error should have occurred with a DockerStrategy / no source combo")
} else {
if !checkDockerStrategyEmptySourceError(result) {
t.Errorf("The correct error was not found: %v", result)
}
}
}
func TestBuildConfigEmptySource(t *testing.T) {
buildConfigs := []buildapi.BuildConfig{
{
ObjectMeta: kapi.ObjectMeta{Name: "config-id", Namespace: "namespace"},
Spec: buildapi.BuildConfigSpec{
RunPolicy: buildapi.BuildRunPolicySerial,
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{},
Strategy: buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{
From: kapi.ObjectReference{
Kind: "DockerImage",
Name: "myimage:tag",
},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
},
{
ObjectMeta: kapi.ObjectMeta{Name: "config-id", Namespace: "namespace"},
Spec: buildapi.BuildConfigSpec{
RunPolicy: buildapi.BuildRunPolicySerial,
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{},
Strategy: buildapi.BuildStrategy{
CustomStrategy: &buildapi.CustomBuildStrategy{
From: kapi.ObjectReference{
Kind: "DockerImage",
Name: "myimage:tag",
},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
},
}
for _, buildConfig := range buildConfigs {
if result := ValidateBuildConfig(&buildConfig); len(result) > 0 {
t.Errorf("Unexpected validation error returned %v", result)
}
}
badBuildConfig := buildapi.BuildConfig{
ObjectMeta: kapi.ObjectMeta{Name: "config-id", Namespace: "namespace"},
Spec: buildapi.BuildConfigSpec{
RunPolicy: buildapi.BuildRunPolicySerial,
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
}
if result := ValidateBuildConfig(&badBuildConfig); len(result) == 0 {
t.Error("An error should have occurred with a DockerStrategy / no source combo")
} else {
if !checkDockerStrategyEmptySourceError(result) {
t.Errorf("The correct error was not found: %v", result)
}
}
}
func TestBuildValidationFailure(t *testing.T) {
build := &buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Name: "", Namespace: ""},
Spec: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
Status: buildapi.BuildStatus{
Phase: buildapi.BuildPhaseNew,
},
}
if result := ValidateBuild(build); len(result) != 2 {
t.Errorf("Unexpected validation result: %v", result)
}
}
func newDefaultParameters() buildapi.BuildSpec {
return buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
}
}
func newNonDefaultParameters() buildapi.BuildSpec {
o := newDefaultParameters()
o.Source.Git.URI = "changed"
return o
}
func TestValidateBuildUpdate(t *testing.T) {
old := &buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "my-build", ResourceVersion: "1"},
Spec: newDefaultParameters(),
Status: buildapi.BuildStatus{Phase: buildapi.BuildPhaseRunning},
}
errs := ValidateBuildUpdate(
&buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "my-build", ResourceVersion: "1"},
Spec: newDefaultParameters(),
Status: buildapi.BuildStatus{Phase: buildapi.BuildPhaseComplete},
},
old,
)
if len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
errorCases := map[string]struct {
Old *buildapi.Build
Update *buildapi.Build
T field.ErrorType
F string
}{
"changed spec": {
Old: &buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "my-build", ResourceVersion: "1"},
Spec: newDefaultParameters(),
},
Update: &buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "my-build", ResourceVersion: "1"},
Spec: newNonDefaultParameters(),
},
T: field.ErrorTypeInvalid,
F: "spec",
},
"update from terminal1": {
Old: &buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "my-build", ResourceVersion: "1"},
Spec: newDefaultParameters(),
Status: buildapi.BuildStatus{Phase: buildapi.BuildPhaseComplete},
},
Update: &buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "my-build", ResourceVersion: "1"},
Spec: newDefaultParameters(),
Status: buildapi.BuildStatus{Phase: buildapi.BuildPhaseRunning},
},
T: field.ErrorTypeInvalid,
F: "status.phase",
},
"update from terminal2": {
Old: &buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "my-build", ResourceVersion: "1"},
Spec: newDefaultParameters(),
Status: buildapi.BuildStatus{Phase: buildapi.BuildPhaseCancelled},
},
Update: &buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "my-build", ResourceVersion: "1"},
Spec: newDefaultParameters(),
Status: buildapi.BuildStatus{Phase: buildapi.BuildPhaseRunning},
},
T: field.ErrorTypeInvalid,
F: "status.phase",
},
"update from terminal3": {
Old: &buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "my-build", ResourceVersion: "1"},
Spec: newDefaultParameters(),
Status: buildapi.BuildStatus{Phase: buildapi.BuildPhaseError},
},
Update: &buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "my-build", ResourceVersion: "1"},
Spec: newDefaultParameters(),
Status: buildapi.BuildStatus{Phase: buildapi.BuildPhaseRunning},
},
T: field.ErrorTypeInvalid,
F: "status.phase",
},
"update from terminal4": {
Old: &buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "my-build", ResourceVersion: "1"},
Spec: newDefaultParameters(),
Status: buildapi.BuildStatus{Phase: buildapi.BuildPhaseFailed},
},
Update: &buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "my-build", ResourceVersion: "1"},
Spec: newDefaultParameters(),
Status: buildapi.BuildStatus{Phase: buildapi.BuildPhaseRunning},
},
T: field.ErrorTypeInvalid,
F: "status.phase",
},
}
for k, v := range errorCases {
errs := ValidateBuildUpdate(v.Update, v.Old)
if len(errs) == 0 {
t.Errorf("expected failure %s for %v", k, v.Update)
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])
}
}
}
}
func TestBuildConfigGitSourceWithProxyFailure(t *testing.T) {
proxyAddress := "127.0.0.1:3128"
buildConfig := &buildapi.BuildConfig{
ObjectMeta: kapi.ObjectMeta{Name: "config-id", Namespace: "namespace"},
Spec: buildapi.BuildConfigSpec{
RunPolicy: buildapi.BuildRunPolicySerial,
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "git://github.com/my/repository",
ProxyConfig: buildapi.ProxyConfig{
HTTPProxy: &proxyAddress,
HTTPSProxy: &proxyAddress,
},
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
}
errors := ValidateBuildConfig(buildConfig)
if len(errors) != 1 {
t.Errorf("Expected one error, got %d", len(errors))
}
err := errors[0]
if err.Type != field.ErrorTypeInvalid {
t.Errorf("Expected invalid value validation error, got %q", err.Type)
}
if err.Detail != "only http:// and https:// GIT protocols are allowed with HTTP or HTTPS proxy set" {
t.Errorf("Exptected git:// protocol with proxy validation error, got: %q", err.Detail)
}
}
// TestBuildConfigDockerStrategyImageChangeTrigger ensures that it is invalid to
// have a BuildConfig with Docker strategy and an ImageChangeTrigger where
// neither DockerStrategy.From nor ImageChange.From are defined.
func TestBuildConfigDockerStrategyImageChangeTrigger(t *testing.T) {
buildConfig := &buildapi.BuildConfig{
ObjectMeta: kapi.ObjectMeta{Name: "config-id", Namespace: "namespace"},
Spec: buildapi.BuildConfigSpec{
RunPolicy: buildapi.BuildRunPolicySerial,
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
Triggers: []buildapi.BuildTriggerPolicy{
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{},
},
},
},
}
errors := ValidateBuildConfig(buildConfig)
switch len(errors) {
case 0:
t.Errorf("Expected validation error, got nothing")
case 1:
err := errors[0]
if err.Type != field.ErrorTypeInvalid {
t.Errorf("Expected error to be '%v', got '%v'", field.ErrorTypeInvalid, err.Type)
}
default:
t.Errorf("Expected a single validation error, got %v", errors)
}
}
func TestBuildConfigValidationFailureRequiredName(t *testing.T) {
buildConfig := &buildapi.BuildConfig{
ObjectMeta: kapi.ObjectMeta{Name: "", Namespace: "foo"},
Spec: buildapi.BuildConfigSpec{
RunPolicy: buildapi.BuildRunPolicySerial,
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
}
errors := ValidateBuildConfig(buildConfig)
if len(errors) != 1 {
t.Fatalf("Unexpected validation errors %v", errors)
}
err := errors[0]
if err.Type != field.ErrorTypeRequired {
t.Errorf("Unexpected error type, expected %s, got %s", field.ErrorTypeRequired, err.Type)
}
if err.Field != "metadata.name" {
t.Errorf("Unexpected field name expected metadata.name, got %s", err.Field)
}
}
func TestBuildConfigImageChangeTriggers(t *testing.T) {
tests := []struct {
name string
triggers []buildapi.BuildTriggerPolicy
fromKind string
expectError bool
errorType field.ErrorType
}{
{
name: "valid default trigger with imagestreamtag",
triggers: []buildapi.BuildTriggerPolicy{
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{},
},
},
fromKind: "ImageStreamTag",
expectError: false,
},
{
name: "invalid default trigger (imagestreamimage)",
triggers: []buildapi.BuildTriggerPolicy{
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{},
},
},
fromKind: "ImageStreamImage",
expectError: true,
errorType: field.ErrorTypeInvalid,
},
{
name: "invalid default trigger (dockerimage)",
triggers: []buildapi.BuildTriggerPolicy{
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{},
},
},
fromKind: "DockerImage",
expectError: true,
errorType: field.ErrorTypeInvalid,
},
{
name: "more than one default trigger",
triggers: []buildapi.BuildTriggerPolicy{
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{},
},
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{},
},
},
fromKind: "ImageStreamTag",
expectError: true,
errorType: field.ErrorTypeInvalid,
},
{
name: "missing image change struct",
triggers: []buildapi.BuildTriggerPolicy{
{
Type: buildapi.ImageChangeBuildTriggerType,
},
},
fromKind: "ImageStreamTag",
expectError: true,
errorType: field.ErrorTypeRequired,
},
{
name: "only one default image change trigger",
triggers: []buildapi.BuildTriggerPolicy{
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{},
},
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{
From: &kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "myimage:tag",
},
},
},
},
fromKind: "ImageStreamTag",
expectError: false,
},
{
name: "invalid reference kind for trigger",
triggers: []buildapi.BuildTriggerPolicy{
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{},
},
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{
From: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "myimage:tag",
},
},
},
},
fromKind: "ImageStreamTag",
expectError: true,
errorType: field.ErrorTypeInvalid,
},
{
name: "empty reference kind for trigger",
triggers: []buildapi.BuildTriggerPolicy{
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{},
},
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{
From: &kapi.ObjectReference{
Name: "myimage:tag",
},
},
},
},
fromKind: "ImageStreamTag",
expectError: true,
errorType: field.ErrorTypeInvalid,
},
{
name: "duplicate imagestreamtag references",
triggers: []buildapi.BuildTriggerPolicy{
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{
From: &kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "myimage:tag",
},
},
},
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{
From: &kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "myimage:tag",
},
},
},
},
fromKind: "ImageStreamTag",
expectError: true,
errorType: field.ErrorTypeInvalid,
},
{
name: "duplicate imagestreamtag - same as strategy ref",
triggers: []buildapi.BuildTriggerPolicy{
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{},
},
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{
From: &kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "builderimage:latest",
},
},
},
},
fromKind: "ImageStreamTag",
expectError: true,
errorType: field.ErrorTypeInvalid,
},
{
name: "imagestreamtag references with same name, different ns",
triggers: []buildapi.BuildTriggerPolicy{
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{
From: &kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "myimage:tag",
Namespace: "ns1",
},
},
},
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{
From: &kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "myimage:tag",
Namespace: "ns2",
},
},
},
},
fromKind: "ImageStreamTag",
expectError: false,
},
{
name: "imagestreamtag references with same name, same ns",
triggers: []buildapi.BuildTriggerPolicy{
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{
From: &kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "myimage:tag",
Namespace: "ns",
},
},
},
{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{
From: &kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "myimage:tag",
Namespace: "ns",
},
},
},
},
fromKind: "ImageStreamTag",
expectError: true,
errorType: field.ErrorTypeInvalid,
},
}
for _, tc := range tests {
buildConfig := &buildapi.BuildConfig{
ObjectMeta: kapi.ObjectMeta{Name: "bar", Namespace: "foo"},
Spec: buildapi.BuildConfigSpec{
RunPolicy: buildapi.BuildRunPolicySerial,
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{
From: kapi.ObjectReference{
Kind: tc.fromKind,
Name: "builderimage:latest",
},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
Triggers: tc.triggers,
},
}
errors := ValidateBuildConfig(buildConfig)
// Check whether an error was returned
if hasError := len(errors) > 0; hasError != tc.expectError {
t.Errorf("%s: did not get expected result: %#v", tc.name, errors)
}
// Check whether it's the expected error type
if len(errors) > 0 && tc.expectError && tc.errorType != "" {
verr := errors[0]
if verr.Type != tc.errorType {
t.Errorf("%s: unexpected error type. Expected: %s. Got: %s", tc.name, tc.errorType, verr.Type)
}
}
}
}
func TestBuildConfigValidationOutputFailure(t *testing.T) {
buildConfig := &buildapi.BuildConfig{
ObjectMeta: kapi.ObjectMeta{Name: ""},
Spec: buildapi.BuildConfigSpec{
RunPolicy: buildapi.BuildRunPolicySerial,
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Name: "other",
},
},
},
},
}
if result := ValidateBuildConfig(buildConfig); len(result) != 3 {
for _, e := range result {
t.Errorf("Unexpected validation result %v", e)
}
}
}
func TestValidateBuildRequest(t *testing.T) {
testCases := map[string]*buildapi.BuildRequest{
string(field.ErrorTypeRequired) + "metadata.namespace": {ObjectMeta: kapi.ObjectMeta{Name: "requestName"}},
string(field.ErrorTypeRequired) + "metadata.name": {ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault}},
}
for desc, tc := range testCases {
errors := ValidateBuildRequest(tc)
if len(desc) == 0 && len(errors) > 0 {
t.Errorf("%s: Unexpected validation result: %v", desc, errors)
}
if len(desc) > 0 && len(errors) != 1 {
t.Errorf("%s: Unexpected validation result: %v", desc, errors)
}
if len(desc) > 0 {
err := errors[0]
errDesc := string(err.Type) + err.Field
if desc != errDesc {
t.Errorf("Unexpected validation result for %s: expected %s, got %s", err.Field, desc, errDesc)
}
}
}
}
func TestValidateSource(t *testing.T) {
dockerfile := "FROM something"
invalidProxyAddress := "some!@#$%^&*()url"
errorCases := []struct {
t field.ErrorType
path string
source *buildapi.BuildSource
ok bool
multiple bool
}{
// 0
{
t: field.ErrorTypeRequired,
path: "git.uri",
source: &buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "",
},
},
},
// 1
{
t: field.ErrorTypeInvalid,
path: "git.uri",
source: &buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "::",
},
},
},
// 2
{
t: field.ErrorTypeInvalid,
path: "contextDir",
source: &buildapi.BuildSource{
Dockerfile: &dockerfile,
ContextDir: "../file",
},
},
// 3
{
t: field.ErrorTypeInvalid,
path: "git",
source: &buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "https://example.com/repo.git",
},
Binary: &buildapi.BinaryBuildSource{},
},
multiple: true,
},
// 4
{
t: field.ErrorTypeInvalid,
path: "binary.asFile",
source: &buildapi.BuildSource{
Binary: &buildapi.BinaryBuildSource{AsFile: "/a/path"},
},
},
// 5
{
t: field.ErrorTypeInvalid,
path: "binary.asFile",
source: &buildapi.BuildSource{
Binary: &buildapi.BinaryBuildSource{AsFile: "/"},
},
},
// 6
{
t: field.ErrorTypeInvalid,
path: "binary.asFile",
source: &buildapi.BuildSource{
Binary: &buildapi.BinaryBuildSource{AsFile: "a\\b"},
},
},
// 7
{
source: &buildapi.BuildSource{
Binary: &buildapi.BinaryBuildSource{AsFile: "/././file"},
},
ok: true,
},
// 8
{
source: &buildapi.BuildSource{
Binary: &buildapi.BinaryBuildSource{AsFile: "/././file"},
Dockerfile: &dockerfile,
},
ok: true,
},
// 9
{
source: &buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "https://example.com/repo.git",
},
Dockerfile: &dockerfile,
},
ok: true,
},
// 10
{
source: &buildapi.BuildSource{
Dockerfile: &dockerfile,
},
ok: true,
},
// 11
{
source: &buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "https://example.com/repo.git",
},
ContextDir: "contextDir",
},
ok: true,
},
// 12
{
t: field.ErrorTypeRequired,
path: "sourceSecret.name",
source: &buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://example.com/repo.git",
},
SourceSecret: &kapi.LocalObjectReference{},
ContextDir: "contextDir/../somedir",
},
},
// 13
{
t: field.ErrorTypeInvalid,
path: "git.httpproxy",
source: &buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "https://example.com/repo.git",
ProxyConfig: buildapi.ProxyConfig{
HTTPProxy: &invalidProxyAddress,
},
},
ContextDir: "contextDir",
},
},
// 14
{
t: field.ErrorTypeInvalid,
path: "git.httpsproxy",
source: &buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "https://example.com/repo.git",
ProxyConfig: buildapi.ProxyConfig{
HTTPSProxy: &invalidProxyAddress,
},
},
ContextDir: "contextDir",
},
},
// 15
{
ok: true,
source: &buildapi.BuildSource{
Images: []buildapi.ImageSource{
{
From: kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "my-image:latest",
},
Paths: []buildapi.ImageSourcePath{
{
SourcePath: "/some/path",
DestinationDir: "test/dir",
},
},
},
{
From: kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "my-image:latest",
},
Paths: []buildapi.ImageSourcePath{
{
SourcePath: "/some/path",
DestinationDir: "test/dir",
},
},
},
},
},
},
// 16
{
t: field.ErrorTypeRequired,
path: "images[0].paths",
source: &buildapi.BuildSource{
Images: []buildapi.ImageSource{
{
From: kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "my-image:latest",
},
},
},
},
},
// 17 - destinationdir is not relative.
{
t: field.ErrorTypeInvalid,
path: "images[0].paths[0].destinationDir",
source: &buildapi.BuildSource{
Images: []buildapi.ImageSource{
{
From: kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "my-image:latest",
},
Paths: []buildapi.ImageSourcePath{
{
SourcePath: "/some/path",
DestinationDir: "/test/dir",
},
},
},
},
},
},
// 18 - sourcepath is not absolute.
{
t: field.ErrorTypeInvalid,
path: "images[0].paths[0].sourcePath",
source: &buildapi.BuildSource{
Images: []buildapi.ImageSource{
{
From: kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "my-image:latest",
},
Paths: []buildapi.ImageSourcePath{
{
SourcePath: "some/path",
DestinationDir: "test/dir",
},
},
},
},
},
},
// 19 - destinationdir backsteps above basedir
{
t: field.ErrorTypeInvalid,
path: "images[0].paths[0].destinationDir",
source: &buildapi.BuildSource{
Images: []buildapi.ImageSource{
{
From: kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "my-image:latest",
},
Paths: []buildapi.ImageSourcePath{
{
SourcePath: "/some/path",
DestinationDir: "test/../../dir",
},
},
},
},
},
},
// 20
{
t: field.ErrorTypeInvalid,
path: "images[0].from.kind",
source: &buildapi.BuildSource{
Images: []buildapi.ImageSource{
{
From: kapi.ObjectReference{
Kind: "InvalidKind",
Name: "my-image:latest",
},
Paths: []buildapi.ImageSourcePath{
{
SourcePath: "/some/path",
DestinationDir: "test/dir",
},
},
},
},
},
},
// 21
{
t: field.ErrorTypeRequired,
path: "images[0].pullSecret.name",
source: &buildapi.BuildSource{
Images: []buildapi.ImageSource{
{
From: kapi.ObjectReference{
Kind: "DockerImage",
Name: "my-image:latest",
},
PullSecret: &kapi.LocalObjectReference{
Name: "",
},
Paths: []buildapi.ImageSourcePath{
{
SourcePath: "/some/path",
DestinationDir: "test/dir",
},
},
},
},
},
},
}
for i, tc := range errorCases {
errors := validateSource(tc.source, false, false, false, nil)
switch len(errors) {
case 0:
if !tc.ok {
t.Errorf("%d: Unexpected validation result: %v", i, errors)
}
continue
case 1:
if tc.ok || tc.multiple {
t.Errorf("%d: Unexpected validation result: %v", i, errors)
continue
}
default:
if tc.ok || !tc.multiple {
t.Errorf("%d: Unexpected validation result: %v", i, errors)
continue
}
}
err := errors[0]
if err.Type != tc.t {
t.Errorf("%d: Expected error type %s, got %s", i, tc.t, err.Type)
}
if err.Field != tc.path {
t.Errorf("%d: Expected error path %s, got %s", i, tc.path, err.Field)
}
}
errorCases[11].source.ContextDir = "."
validateSource(errorCases[11].source, false, false, false, nil)
if len(errorCases[11].source.ContextDir) != 0 {
t.Errorf("ContextDir was not cleaned: %s", errorCases[11].source.ContextDir)
}
}
func TestValidateStrategy(t *testing.T) {
errorCases := []struct {
t field.ErrorType
path string
strategy *buildapi.BuildStrategy
ok bool
multiple bool
}{
// 0
{
t: field.ErrorTypeInvalid,
path: "",
strategy: &buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{},
DockerStrategy: &buildapi.DockerBuildStrategy{},
CustomStrategy: &buildapi.CustomBuildStrategy{},
JenkinsPipelineStrategy: &buildapi.JenkinsPipelineBuildStrategy{},
},
},
}
for i, tc := range errorCases {
errors := validateStrategy(tc.strategy, nil)
switch len(errors) {
case 0:
if !tc.ok {
t.Errorf("%d: Unexpected validation result: %v", i, errors)
}
continue
case 1:
if tc.ok || tc.multiple {
t.Errorf("%d: Unexpected validation result: %v", i, errors)
continue
}
default:
if tc.ok || !tc.multiple {
t.Errorf("%d: Unexpected validation result: %v", i, errors)
continue
}
}
err := errors[0]
if err.Type != tc.t {
t.Errorf("%d: Unexpected error type: %s", i, err.Type)
}
if err.Field != tc.path {
t.Errorf("%d: Unexpected error path: %s", i, err.Field)
}
}
}
func TestValidateCommonSpec(t *testing.T) {
zero := int64(0)
longString := strings.Repeat("1234567890", 100*61)
errorCases := []struct {
err string
buildapi.CommonSpec
}{
// 0
{
string(field.ErrorTypeInvalid) + "output.to.name",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "///some/long/value/with/no/meaning",
},
},
},
},
// 1
{
string(field.ErrorTypeInvalid) + "output.to.kind",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "ImageStream",
Name: "///some/long/value/with/no/meaning",
},
},
},
},
// 2
{
string(field.ErrorTypeInvalid) + "output.to.name",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "///some/long/value/with/no/meaning",
},
},
},
},
// 3
{
string(field.ErrorTypeInvalid) + "output.to.name",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "///some/long/value/with/no/meaning:latest",
},
},
},
},
// 4
{
string(field.ErrorTypeInvalid) + "output.to.kind",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "Foo",
Name: "test",
},
},
},
},
// 5
{
string(field.ErrorTypeRequired) + "output.to.kind",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{},
},
},
},
// 6
{
string(field.ErrorTypeRequired) + "output.to.name",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "ImageStreamTag",
},
},
},
},
// 7
{
string(field.ErrorTypeInvalid) + "output.to.name",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "missingtag",
Namespace: "subdomain",
},
},
},
},
// 8
{
string(field.ErrorTypeInvalid) + "output.to.namespace",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "test:tag",
Namespace: "not_a_valid_subdomain",
},
},
},
},
// 9
// invalid because from is not specified in the
// sti strategy definition
{
string(field.ErrorTypeRequired) + "strategy.sourceStrategy.from.kind",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 10
// Invalid because from.name is not specified
{
string(field.ErrorTypeRequired) + "strategy.sourceStrategy.from.name",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{
From: kapi.ObjectReference{
Kind: "DockerImage",
},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 11
// invalid because from name is a bad format
{
string(field.ErrorTypeInvalid) + "strategy.sourceStrategy.from.name",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{
From: kapi.ObjectReference{Kind: "ImageStreamTag", Name: "bad format"},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 12
// invalid because from name is a bad format
{
string(field.ErrorTypeInvalid) + "strategy.sourceStrategy.from.name",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{
From: kapi.ObjectReference{Kind: "ImageStreamTag", Name: "badformat"},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 13
// invalid because from name is a bad format
{
string(field.ErrorTypeInvalid) + "strategy.sourceStrategy.from.name",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{
From: kapi.ObjectReference{Kind: "ImageStreamTag", Name: "bad/format:latest"},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 14
// invalid because from is not specified in the
// custom strategy definition
{
string(field.ErrorTypeRequired) + "strategy.customStrategy.from.kind",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
CustomStrategy: &buildapi.CustomBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 15
// invalid because from.name is not specified in the
// custom strategy definition
{
string(field.ErrorTypeInvalid) + "strategy.customStrategy.from.name",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
CustomStrategy: &buildapi.CustomBuildStrategy{
From: kapi.ObjectReference{Kind: "ImageStreamTag", Name: "bad format"},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 16
{
string(field.ErrorTypeInvalid) + "source.dockerfile",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Dockerfile: &longString,
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
},
},
// 17
{
string(field.ErrorTypeInvalid) + "source.dockerfile",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Dockerfile: &longString,
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
},
},
// 18
// invalid because CompletionDeadlineSeconds <= 0
{
string(field.ErrorTypeInvalid) + "completionDeadlineSeconds",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
CompletionDeadlineSeconds: &zero,
},
},
// 19
// must provide some source input
{
string(field.ErrorTypeInvalid) + "source",
buildapi.CommonSpec{
Source: buildapi.BuildSource{},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 20
// dockerfilePath can't be an absolute path
{
string(field.ErrorTypeInvalid) + "strategy.dockerStrategy.dockerfilePath",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{
DockerfilePath: "/myDockerfile",
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 21
// dockerfilePath can't start with ../
{
string(field.ErrorTypeInvalid) + "strategy.dockerStrategy.dockerfilePath",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{
DockerfilePath: "../someDockerfile",
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 22
// dockerfilePath can't reference a path outside of the dir
{
string(field.ErrorTypeInvalid) + "strategy.dockerStrategy.dockerfilePath",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{
DockerfilePath: "someDockerfile/../../..",
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 23
// dockerfilePath can't equal ..
{
string(field.ErrorTypeInvalid) + "strategy.dockerStrategy.dockerfilePath",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
ContextDir: "context",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{
DockerfilePath: "..",
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 24
{
string(field.ErrorTypeInvalid) + "postCommit",
buildapi.CommonSpec{
PostCommit: buildapi.BuildPostCommitSpec{
Command: []string{"rake", "test"},
Script: "rake test",
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
},
},
// 25
{
string(field.ErrorTypeInvalid) + "source.git",
buildapi.CommonSpec{
Strategy: buildapi.BuildStrategy{
JenkinsPipelineStrategy: &buildapi.JenkinsPipelineBuildStrategy{},
},
},
},
// 26
{
string(field.ErrorTypeInvalid) + "source.git",
buildapi.CommonSpec{
Strategy: buildapi.BuildStrategy{
JenkinsPipelineStrategy: &buildapi.JenkinsPipelineBuildStrategy{
JenkinsfilePath: "b",
},
},
},
},
// 27
// jenkinsfilePath can't be an absolute path
{
string(field.ErrorTypeInvalid) + "strategy.jenkinsPipelineStrategy.jenkinsfilePath",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
JenkinsPipelineStrategy: &buildapi.JenkinsPipelineBuildStrategy{
JenkinsfilePath: "/myJenkinsfile",
},
},
},
},
// 28
// jenkinsfilePath can't start with ../
{
string(field.ErrorTypeInvalid) + "strategy.jenkinsPipelineStrategy.jenkinsfilePath",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
JenkinsPipelineStrategy: &buildapi.JenkinsPipelineBuildStrategy{
JenkinsfilePath: "../someJenkinsfile",
},
},
},
},
// 29
// jenkinsfilePath can't be a reference a path outside of the dir
{
string(field.ErrorTypeInvalid) + "strategy.jenkinsPipelineStrategy.jenkinsfilePath",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
JenkinsPipelineStrategy: &buildapi.JenkinsPipelineBuildStrategy{
JenkinsfilePath: "someJenkinsfile/../../../",
},
},
},
},
// 30
// jenkinsfilePath can't be equal to ..
{
string(field.ErrorTypeInvalid) + "strategy.jenkinsPipelineStrategy.jenkinsfilePath",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
JenkinsPipelineStrategy: &buildapi.JenkinsPipelineBuildStrategy{
JenkinsfilePath: "..",
},
},
},
},
// 31
// path must be shorter than 100k
{
string(field.ErrorTypeInvalid) + "strategy.jenkinsPipelineStrategy.jenkinsfile",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
JenkinsPipelineStrategy: &buildapi.JenkinsPipelineBuildStrategy{
Jenkinsfile: longString + longString,
},
},
},
},
// 32
{
string(field.ErrorTypeRequired) + "output.imageLabels[0].name",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
ImageLabels: []buildapi.ImageLabel{
{
Name: "",
Value: "",
},
},
},
},
},
// 33
{
string(field.ErrorTypeInvalid) + "output.imageLabels[0].name",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
ImageLabels: []buildapi.ImageLabel{
{
Name: "%$#@!",
Value: "",
},
},
},
},
},
// 34
// duplicate labels
{
string(field.ErrorTypeInvalid) + "output.imageLabels[1].name",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
ImageLabels: []buildapi.ImageLabel{
{
Name: "really",
Value: "yes",
},
{
Name: "really",
Value: "no",
},
},
},
},
},
// 35
// nonconsecutive duplicate labels
{
string(field.ErrorTypeInvalid) + "output.imageLabels[3].name",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
ImageLabels: []buildapi.ImageLabel{
{
Name: "a",
Value: "1",
},
{
Name: "really",
Value: "yes",
},
{
Name: "b",
Value: "2",
},
{
Name: "really",
Value: "no",
},
{
Name: "c",
Value: "3",
},
},
},
},
},
// 36
// invalid nodeselector
{
string(field.ErrorTypeInvalid) + "nodeSelector[A@B!]",
buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
NodeSelector: map[string]string{"A@B!": "C"},
},
},
}
for count, config := range errorCases {
errors := validateCommonSpec(&config.CommonSpec, nil)
if len(errors) != 1 {
t.Errorf("Test[%d] %s: Unexpected validation result: %v", count, config.err, errors)
continue
}
err := errors[0]
errDesc := string(err.Type) + err.Field
if config.err != errDesc {
t.Errorf("Test[%d] Unexpected validation result for %s: expected %s, got %s", count, err.Field, config.err, errDesc)
}
}
}
func TestValidateCommonSpecSuccess(t *testing.T) {
shortString := "FROM foo"
testCases := []struct {
buildapi.CommonSpec
}{
// 0
{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{
From: kapi.ObjectReference{
Kind: "DockerImage",
Name: "reponame",
},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 1
{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
CustomStrategy: &buildapi.CustomBuildStrategy{
From: kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "imagestreamname:tag",
},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 2
{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 3
{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{
From: &kapi.ObjectReference{
Kind: "ImageStreamImage",
Name: "imagestreamimage",
},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 4
{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Dockerfile: &shortString,
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{
From: &kapi.ObjectReference{
Kind: "ImageStreamImage",
Name: "imagestreamimage",
},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 5
{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{
From: &kapi.ObjectReference{
Kind: "ImageStreamImage",
Name: "imagestreamimage",
},
DockerfilePath: "dockerfiles/firstDockerfile",
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 6
{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{
From: kapi.ObjectReference{
Kind: "DockerImage",
Name: "reponame",
},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "registry/project/repository/data",
},
},
},
},
// 7
{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{
From: kapi.ObjectReference{
Kind: "DockerImage",
Name: "registry/project/repository/data",
},
},
},
Output: buildapi.BuildOutput{
To: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "repository/data",
},
},
},
},
// 6
{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
ImageLabels: nil,
},
},
},
// 7
{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
ImageLabels: []buildapi.ImageLabel{},
},
},
},
// 8
{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
ImageLabels: []buildapi.ImageLabel{
{
Name: "key",
},
},
},
},
},
// 9
{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
Output: buildapi.BuildOutput{
ImageLabels: []buildapi.ImageLabel{
{
Name: "key",
Value: "value )(*&",
},
},
},
},
},
// 10
{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
URI: "http://github.com/my/repository",
},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{},
},
NodeSelector: map[string]string{"A": "B", "C": "D"},
},
},
}
for count, config := range testCases {
errors := validateCommonSpec(&config.CommonSpec, nil)
if len(errors) != 0 {
t.Errorf("Test[%d] Unexpected validation error: %v", count, errors)
}
}
}
func TestValidateDockerfilePath(t *testing.T) {
tests := []struct {
strategy *buildapi.DockerBuildStrategy
expectedDockerfilePath string
}{
{
strategy: &buildapi.DockerBuildStrategy{
DockerfilePath: ".",
},
expectedDockerfilePath: "",
},
{
strategy: &buildapi.DockerBuildStrategy{
DockerfilePath: "somedir/..",
},
expectedDockerfilePath: "",
},
{
strategy: &buildapi.DockerBuildStrategy{
DockerfilePath: "somedir/../somedockerfile",
},
expectedDockerfilePath: "somedockerfile",
},
{
strategy: &buildapi.DockerBuildStrategy{
DockerfilePath: "somedir/somedockerfile",
},
expectedDockerfilePath: "somedir/somedockerfile",
},
}
for count, test := range tests {
errors := validateDockerStrategy(test.strategy, nil)
if len(errors) != 0 {
t.Errorf("Test[%d] Unexpected validation error: %v", count, errors)
}
if test.strategy.DockerfilePath != test.expectedDockerfilePath {
t.Errorf("Test[%d] Unexpected DockerfilePath: %v (expected: %s)", count, test.strategy.DockerfilePath, test.expectedDockerfilePath)
}
}
}
func TestValidateJenkinsfilePath(t *testing.T) {
tests := []struct {
strategy *buildapi.JenkinsPipelineBuildStrategy
expectedJenkinsfilePath string
}{
{
strategy: &buildapi.JenkinsPipelineBuildStrategy{
JenkinsfilePath: ".",
},
expectedJenkinsfilePath: "",
},
{
strategy: &buildapi.JenkinsPipelineBuildStrategy{
JenkinsfilePath: "somedir/..",
},
expectedJenkinsfilePath: "",
},
{
strategy: &buildapi.JenkinsPipelineBuildStrategy{
JenkinsfilePath: "somedir/../somedockerfile",
},
expectedJenkinsfilePath: "somedockerfile",
},
{
strategy: &buildapi.JenkinsPipelineBuildStrategy{
JenkinsfilePath: "somedir/somedockerfile",
},
expectedJenkinsfilePath: "somedir/somedockerfile",
},
}
for count, test := range tests {
errors := validateJenkinsPipelineStrategy(test.strategy, nil)
if len(errors) != 0 {
t.Errorf("Test[%d] Unexpected validation error: %v", count, errors)
}
if test.strategy.JenkinsfilePath != test.expectedJenkinsfilePath {
t.Errorf("Test[%d] Unexpected JenkinsfilePath: %v (expected: %s)", count, test.strategy.JenkinsfilePath, test.expectedJenkinsfilePath)
}
}
}
func TestValidateTrigger(t *testing.T) {
tests := map[string]struct {
trigger buildapi.BuildTriggerPolicy
expected []*field.Error
}{
"trigger without type": {
trigger: buildapi.BuildTriggerPolicy{},
expected: []*field.Error{field.Required(field.NewPath("type"), "")},
},
"trigger with unknown type": {
trigger: buildapi.BuildTriggerPolicy{
Type: "UnknownTriggerType",
},
expected: []*field.Error{field.Invalid(field.NewPath("type"), "", "")},
},
"GitHub type with no github webhook": {
trigger: buildapi.BuildTriggerPolicy{Type: buildapi.GitHubWebHookBuildTriggerType},
expected: []*field.Error{field.Required(field.NewPath("github"), "")},
},
"GitHub trigger with no secret": {
trigger: buildapi.BuildTriggerPolicy{
Type: buildapi.GitHubWebHookBuildTriggerType,
GitHubWebHook: &buildapi.WebHookTrigger{},
},
expected: []*field.Error{field.Required(field.NewPath("github", "secret"), "")},
},
"GitHub trigger with generic webhook": {
trigger: buildapi.BuildTriggerPolicy{
Type: buildapi.GitHubWebHookBuildTriggerType,
GenericWebHook: &buildapi.WebHookTrigger{
Secret: "secret101",
},
},
expected: []*field.Error{field.Required(field.NewPath("github"), "")},
},
"GitHub trigger with allow env": {
trigger: buildapi.BuildTriggerPolicy{
Type: buildapi.GitHubWebHookBuildTriggerType,
GitHubWebHook: &buildapi.WebHookTrigger{
Secret: "secret101",
AllowEnv: true,
},
},
expected: []*field.Error{field.Invalid(field.NewPath("github", "allowEnv"), "", "")},
},
"Generic trigger with no generic webhook": {
trigger: buildapi.BuildTriggerPolicy{Type: buildapi.GenericWebHookBuildTriggerType},
expected: []*field.Error{field.Required(field.NewPath("generic"), "")},
},
"Generic trigger with no secret": {
trigger: buildapi.BuildTriggerPolicy{
Type: buildapi.GenericWebHookBuildTriggerType,
GenericWebHook: &buildapi.WebHookTrigger{},
},
expected: []*field.Error{field.Required(field.NewPath("generic", "secret"), "")},
},
"Generic trigger with github webhook": {
trigger: buildapi.BuildTriggerPolicy{
Type: buildapi.GenericWebHookBuildTriggerType,
GitHubWebHook: &buildapi.WebHookTrigger{
Secret: "secret101",
},
},
expected: []*field.Error{field.Required(field.NewPath("generic"), "")},
},
"ImageChange trigger without params": {
trigger: buildapi.BuildTriggerPolicy{
Type: buildapi.ImageChangeBuildTriggerType,
},
expected: []*field.Error{field.Required(field.NewPath("imageChange"), "")},
},
"valid GitHub trigger": {
trigger: buildapi.BuildTriggerPolicy{
Type: buildapi.GitHubWebHookBuildTriggerType,
GitHubWebHook: &buildapi.WebHookTrigger{
Secret: "secret101",
},
},
},
"valid Generic trigger": {
trigger: buildapi.BuildTriggerPolicy{
Type: buildapi.GenericWebHookBuildTriggerType,
GenericWebHook: &buildapi.WebHookTrigger{
Secret: "secret101",
},
},
},
"valid ImageChange trigger": {
trigger: buildapi.BuildTriggerPolicy{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{
LastTriggeredImageID: "asdf1234",
},
},
},
"valid ImageChange trigger with empty fields": {
trigger: buildapi.BuildTriggerPolicy{
Type: buildapi.ImageChangeBuildTriggerType,
ImageChange: &buildapi.ImageChangeTrigger{},
},
},
}
for desc, test := range tests {
errors := validateTrigger(&test.trigger, &kapi.ObjectReference{Kind: "ImageStreamTag"}, nil)
if len(test.expected) == 0 {
if len(errors) != 0 {
t.Errorf("%s: Got unexpected validation errors: %#v", desc, errors)
}
continue
}
if len(errors) != 1 {
t.Errorf("%s: Expected one validation error, got %d", desc, len(errors))
for i, err := range errors {
validationError := err
t.Errorf(" %d. %v", i+1, validationError)
}
continue
}
err := errors[0]
validationError := err
if validationError.Type != test.expected[0].Type {
t.Errorf("%s: Expected error type %s, got %s", desc, test.expected[0].Type, validationError.Type)
}
if validationError.Field != test.expected[0].Field {
t.Errorf("%s: Expected error field %s, got %s", desc, test.expected[0].Field, validationError.Field)
}
}
}
func TestValidateToImageReference(t *testing.T) {
o := &kapi.ObjectReference{
Name: "somename",
Namespace: "somenamespace",
Kind: "DockerImage",
}
errs := validateToImageReference(o, nil)
if len(errs) != 1 {
t.Errorf("Wrong number of errors: %v", errs)
}
err := errs[0]
if err.Type != field.ErrorTypeInvalid {
t.Errorf("Wrong error type, expected %v, got %v", field.ErrorTypeInvalid, err.Type)
}
if err.Field != "namespace" {
t.Errorf("Error on wrong field, expected %s, got %s", "namespace", err.Field)
}
}
func TestValidateStrategyEnvVars(t *testing.T) {
tests := []struct {
env []kapi.EnvVar
errExpected bool
errField string
errType field.ErrorType
}{
// 0: missing Env variable name
{
env: []kapi.EnvVar{
{
Name: "",
Value: "test",
},
},
errExpected: true,
errField: "env[0].name",
errType: field.ErrorTypeRequired,
},
// 1: invalid Env variable name
{
env: []kapi.EnvVar{
{
Name: " invalid,name",
Value: "test",
},
},
errExpected: true,
errField: "env[0].name",
errType: field.ErrorTypeInvalid,
},
// 2: valueFrom present in env var
{
env: []kapi.EnvVar{
{
Name: "name",
Value: "test",
ValueFrom: &kapi.EnvVarSource{},
},
},
errExpected: true,
errField: "env[0].valueFrom",
errType: field.ErrorTypeInvalid,
},
// 3: valid env
{
env: []kapi.EnvVar{
{
Name: "VAR1",
Value: "value1",
},
{
Name: "VAR2",
Value: "value2",
},
},
},
}
for i, tc := range tests {
errs := ValidateStrategyEnv(tc.env, field.NewPath("env"))
if !tc.errExpected {
if len(errs) > 0 {
t.Errorf("%d: unexpected error: %v", i, errs.ToAggregate())
}
continue
}
if tc.errExpected && len(errs) == 0 {
t.Errorf("%d: expected error. Got none.", i)
continue
}
err := errs[0]
if err.Field != tc.errField {
t.Errorf("%d: unexpected error field: %s", i, err.Field)
}
if err.Type != tc.errType {
t.Errorf("%d: unexpected error type: %s", i, err.Type)
}
}
}
func TestValidatePostCommit(t *testing.T) {
path := field.NewPath("postCommit")
invalidSpec := buildapi.BuildPostCommitSpec{
Command: []string{"rake", "test"},
Script: "rake test",
}
tests := []struct {
spec buildapi.BuildPostCommitSpec
want field.ErrorList
}{
{
spec: buildapi.BuildPostCommitSpec{},
want: field.ErrorList{},
},
{
spec: buildapi.BuildPostCommitSpec{
Script: "rake test",
},
want: field.ErrorList{},
},
{
spec: buildapi.BuildPostCommitSpec{
Command: []string{"rake", "test"},
},
want: field.ErrorList{},
},
{
spec: buildapi.BuildPostCommitSpec{
Args: []string{"rake", "test"},
},
want: field.ErrorList{},
},
{
spec: buildapi.BuildPostCommitSpec{
Script: "rake test $1",
Args: []string{"--verbose"},
},
want: field.ErrorList{},
},
{
spec: buildapi.BuildPostCommitSpec{
Command: []string{"/bin/bash", "-c"},
Args: []string{"rake test"},
},
want: field.ErrorList{},
},
{
spec: invalidSpec,
want: field.ErrorList{
field.Invalid(path, invalidSpec, "cannot use command and script together"),
},
},
}
for _, tt := range tests {
if got := validatePostCommit(tt.spec, path); !reflect.DeepEqual(got, tt.want) {
t.Errorf("validatePostCommitSpec(%+v) = %v, want %v", tt.spec, got, tt.want)
}
}
}
func TestDiffBuildSpec(t *testing.T) {
tests := []struct {
name string
older, newer buildapi.BuildSpec
expected string
}{
{
name: "context dir",
older: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{},
},
},
newer: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
ContextDir: "context-dir",
},
},
},
expected: `{"spec":{"source":{"contextDir":"context-dir"}}}`,
},
{
name: "same git build source",
older: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
Ref: "https://github.com/openshift/origin.git",
},
},
},
},
newer: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
Ref: "https://github.com/openshift/origin.git",
},
},
},
},
expected: "{}",
},
{
name: "different git build source",
older: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
Ref: "https://github.com/openshift/origin.git",
},
},
},
},
newer: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Git: &buildapi.GitBuildSource{
Ref: "https://github.com/ose/origin.git",
},
},
},
},
expected: `{"spec":{"source":{"git":{"ref":"https://github.com/ose/origin.git"}}}}`,
},
}
for _, test := range tests {
diff, err := diffBuildSpec(test.newer, test.older)
if err != nil {
t.Errorf("%s: unexpected: %v", test.name, err)
continue
}
if diff != test.expected {
t.Errorf("%s: expected: %s, got: %s", test.name, test.expected, diff)
}
}
}
func TestValidateBuildImageRefs(t *testing.T) {
tests := []struct {
name string
build buildapi.Build
expectedError string
}{
{
name: "valid docker build",
build: buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Name: "build", Namespace: "default"},
Spec: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Binary: &buildapi.BinaryBuildSource{},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{
From: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "myimage:tag",
},
},
},
},
},
},
expectedError: "",
},
{
name: "valid s2i build w/ runtimeImage",
build: buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Name: "build", Namespace: "default"},
Spec: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Binary: &buildapi.BinaryBuildSource{},
},
Strategy: buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{
From: kapi.ObjectReference{
Kind: "DockerImage",
Name: "myimage:tag",
},
RuntimeImage: &kapi.ObjectReference{
Kind: "DockerImage",
Name: "runtimestream:tag",
},
},
},
},
},
},
expectedError: "",
},
{
name: "docker build with ImageStreamTag in from",
build: buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Name: "build", Namespace: "default"},
Spec: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Binary: &buildapi.BinaryBuildSource{},
},
Strategy: buildapi.BuildStrategy{
DockerStrategy: &buildapi.DockerBuildStrategy{
From: &kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "myimagestream:tag",
},
},
},
},
},
},
expectedError: "only DockerImage references",
},
{
name: "s2i build with valid source image references",
build: buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Name: "build", Namespace: "default"},
Spec: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Binary: &buildapi.BinaryBuildSource{},
Images: []buildapi.ImageSource{
{
From: kapi.ObjectReference{
Kind: "DockerImage",
Name: "myimage:tag",
},
Paths: []buildapi.ImageSourcePath{
{
SourcePath: "/some/path",
DestinationDir: "test/dir",
},
},
},
},
},
Strategy: buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{
From: kapi.ObjectReference{
Kind: "DockerImage",
Name: "myimagestream:tag",
},
},
},
},
},
},
expectedError: "",
},
{
name: "image with sources uses ImageStreamTag",
build: buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Name: "build", Namespace: "default"},
Spec: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Binary: &buildapi.BinaryBuildSource{},
Images: []buildapi.ImageSource{
{
From: kapi.ObjectReference{
Kind: "DockerImage",
Name: "myimage:tag",
},
Paths: []buildapi.ImageSourcePath{
{
SourcePath: "/some/path",
DestinationDir: "test/dir",
},
},
},
{
From: kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "myimagestream:tag",
},
Paths: []buildapi.ImageSourcePath{
{
SourcePath: "/some/path",
DestinationDir: "test/dir",
},
},
},
},
},
Strategy: buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{
From: kapi.ObjectReference{
Kind: "DockerImage",
Name: "myimagestream:tag",
},
},
},
},
},
},
expectedError: "only DockerImage references",
},
{
name: "s2i build with ImageStreamTag runtimeImage",
build: buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Name: "build", Namespace: "default"},
Spec: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Binary: &buildapi.BinaryBuildSource{},
},
Strategy: buildapi.BuildStrategy{
SourceStrategy: &buildapi.SourceBuildStrategy{
From: kapi.ObjectReference{
Kind: "DockerImage",
Name: "myimage:tag",
},
RuntimeImage: &kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "runtimestream:tag",
},
},
},
},
},
},
expectedError: "only DockerImage references",
},
{
name: "custom build with ImageStreamTag in from",
build: buildapi.Build{
ObjectMeta: kapi.ObjectMeta{Name: "build", Namespace: "default"},
Spec: buildapi.BuildSpec{
CommonSpec: buildapi.CommonSpec{
Source: buildapi.BuildSource{
Binary: &buildapi.BinaryBuildSource{},
},
Strategy: buildapi.BuildStrategy{
CustomStrategy: &buildapi.CustomBuildStrategy{
From: kapi.ObjectReference{
Kind: "ImageStreamTag",
Name: "myimagestream:tag",
},
},
},
},
},
},
expectedError: "only DockerImage references",
},
}
for _, tc := range tests {
errs := ValidateBuild(&tc.build)
if tc.expectedError == "" && len(errs) > 0 {
t.Errorf("%s: Unexpected validation result: %v", tc.name, errs)
}
if tc.expectedError != "" {
found := false
for _, err := range errs {
if strings.Contains(err.Error(), tc.expectedError) {
found = true
}
}
if !found {
t.Errorf("%s: Expected to fail with %q, result: %v", tc.name, tc.expectedError, errs)
}
}
}
}