func TestValidateSelectorMatchesPodTemplateLabels(t *testing.T) {
	tests := map[string]struct {
		spec        api.DeploymentConfigSpec
		expectedErr bool
		errorType   field.ErrorType
		field       string
	}{
		"valid template labels": {
			spec: api.DeploymentConfigSpec{
				Selector: test.OkSelector(),
				Strategy: test.OkStrategy(),
				Template: test.OkPodTemplate(),
			},
		},
		"invalid template labels": {
			spec: api.DeploymentConfigSpec{
				Selector: test.OkSelector(),
				Strategy: test.OkStrategy(),
				Template: test.OkPodTemplate(),
			},
			expectedErr: true,
			errorType:   field.ErrorTypeInvalid,
			field:       "spec.template.metadata.labels",
		},
	}

	for name, test := range tests {
		if test.expectedErr {
			test.spec.Template.Labels["a"] = "c"
		}
		errs := ValidateDeploymentConfigSpec(test.spec)
		if len(errs) == 0 && test.expectedErr {
			t.Errorf("%s: expected failure", name)
			continue
		}
		if !test.expectedErr {
			continue
		}
		if len(errs) != 1 {
			t.Errorf("%s: expected one error, got %d", name, len(errs))
			continue
		}
		err := errs[0]
		if err.Type != test.errorType {
			t.Errorf("%s: expected error to have type %q, got %q", name, test.errorType, err.Type)
		}
		if err.Field != test.field {
			t.Errorf("%s: expected error to have field %q, got %q", name, test.field, err.Field)
		}
	}
}
Example #2
0
func TestValidateDeploymentConfigDefaultImageStreamKind(t *testing.T) {
	config := &api.DeploymentConfig{
		ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
		Spec: api.DeploymentConfigSpec{
			Replicas: 1,
			Triggers: []api.DeploymentTriggerPolicy{
				{
					Type: api.DeploymentTriggerOnImageChange,
					ImageChangeParams: &api.DeploymentTriggerImageChangeParams{
						From: kapi.ObjectReference{
							Kind: "ImageStreamTag",
							Name: "name:v1",
						},
						ContainerNames: []string{"foo"},
					},
				},
			},
			Selector: test.OkSelector(),
			Template: test.OkPodTemplate(),
			Strategy: test.OkStrategy(),
		},
	}

	if errs := ValidateDeploymentConfig(config); len(errs) > 0 {
		t.Errorf("Unxpected non-empty error list: %v", errs)
	}
}
Example #3
0
func podTemplateA() *kapi.PodTemplateSpec {
	t := deploytest.OkPodTemplate()
	t.Spec.Containers = append(t.Spec.Containers, kapi.Container{
		Name:  "container1",
		Image: "registry:8080/repo1:ref1",
	})
	return t
}
Example #4
0
func TestDCPodTemplateSpecNode(t *testing.T) {
	g := osgraph.New()

	dc := &deployapi.DeploymentConfig{}
	dc.Namespace = "ns"
	dc.Name = "foo"
	dc.Spec.Template = test.OkPodTemplate()

	_ = EnsureDeploymentConfigNode(g, dc)

	edges := g.Edges()
	if len(edges) != 2 {
		t.Errorf("expected 2 edges, got %d", len(edges))
		return
	}
	for i := range edges {
		if !g.EdgeKinds(edges[i]).Has(osgraph.ContainsEdgeKind) {
			t.Errorf("expected %v, got %v", osgraph.ContainsEdgeKind, g.EdgeKinds(edges[i]))
			return
		}
	}

	nodes := g.Nodes()
	if len(nodes) != 3 {
		t.Errorf("expected 3 nodes, got %d", len(nodes))
		return
	}
	sorted, err := topo.Sort(g)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
		return
	}
	// Just to be sure
	if len(sorted) != 3 {
		t.Errorf("expected 3 nodes, got %d", len(sorted))
		return
	}
	if _, ok := sorted[0].(*DeploymentConfigNode); !ok {
		t.Errorf("expected first node to be a DeploymentConfigNode")
		return
	}
	if _, ok := sorted[1].(*kubetypes.PodTemplateSpecNode); !ok {
		t.Errorf("expected second node to be a PodTemplateSpecNode")
		return
	}
	if _, ok := sorted[2].(*kubetypes.PodSpecNode); !ok {
		t.Errorf("expected third node to be a PodSpecNode")
	}
}
Example #5
0
func TestValidateDeploymentConfigOK(t *testing.T) {
	errs := ValidateDeploymentConfig(&api.DeploymentConfig{
		ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
		Spec: api.DeploymentConfigSpec{
			Replicas: 1,
			Triggers: manualTrigger(),
			Selector: test.OkSelector(),
			Strategy: test.OkStrategy(),
			Template: test.OkPodTemplate(),
		},
	})

	if len(errs) > 0 {
		t.Errorf("Unxpected non-empty error list: %#v", errs)
	}
}
Example #6
0
func rollingConfig(interval, updatePeriod, timeout int) api.DeploymentConfig {
	return api.DeploymentConfig{
		ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
		Spec: api.DeploymentConfigSpec{
			Triggers: manualTrigger(),
			Strategy: api.DeploymentStrategy{
				Type: api.DeploymentStrategyTypeRolling,
				RollingParams: &api.RollingDeploymentStrategyParams{
					IntervalSeconds:     mkint64p(interval),
					UpdatePeriodSeconds: mkint64p(updatePeriod),
					TimeoutSeconds:      mkint64p(timeout),
					MaxSurge:            intstr.FromInt(1),
				},
			},
			Template: test.OkPodTemplate(),
			Selector: test.OkSelector(),
		},
	}
}
Example #7
0
func rollingConfigMax(maxSurge, maxUnavailable intstr.IntOrString) api.DeploymentConfig {
	return api.DeploymentConfig{
		ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
		Spec: api.DeploymentConfigSpec{
			Triggers: manualTrigger(),
			Strategy: api.DeploymentStrategy{
				Type: api.DeploymentStrategyTypeRolling,
				RollingParams: &api.RollingDeploymentStrategyParams{
					IntervalSeconds:     mkint64p(1),
					UpdatePeriodSeconds: mkint64p(1),
					TimeoutSeconds:      mkint64p(1),
					MaxSurge:            maxSurge,
					MaxUnavailable:      maxUnavailable,
				},
			},
			Template: test.OkPodTemplate(),
			Selector: test.OkSelector(),
		},
	}
}
Example #8
0
func TestCanTrigger(t *testing.T) {
	tests := []struct {
		name string

		config  *deployapi.DeploymentConfig
		decoded *deployapi.DeploymentConfig
		force   bool

		expected       bool
		expectedCauses []deployapi.DeploymentCause
		expectedErr    bool
	}{
		{
			name: "no trigger [w/ podtemplate change]",

			config: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Triggers: []deployapi.DeploymentTriggerPolicy{},
					Template: deploytest.OkPodTemplateChanged(),
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			decoded: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Triggers: []deployapi.DeploymentTriggerPolicy{},
					Template: deploytest.OkPodTemplate(),
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			force: false,

			expected:       false,
			expectedCauses: nil,
		},
		{
			name: "forced updated",

			config: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplateChanged(),
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			decoded: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplate(),
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			force: true,

			expected:       true,
			expectedCauses: []deployapi.DeploymentCause{{Type: deployapi.DeploymentTriggerManual}},
		},
		{
			name: "config change trigger only [w/ podtemplate change]",

			config: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplateChanged(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkConfigChangeTrigger(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			decoded: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkConfigChangeTrigger(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			force: false,

			expected:       true,
			expectedCauses: deploytest.OkConfigChangeDetails().Causes,
		},
		{
			name: "config change trigger only [no change][initial]",

			config: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkConfigChangeTrigger(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(0),
			},
			decoded: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkConfigChangeTrigger(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(0),
			},
			force: false,

			expected:       true,
			expectedCauses: deploytest.OkConfigChangeDetails().Causes,
		},
		{
			name: "config change trigger only [no change]",

			config: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkConfigChangeTrigger(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			decoded: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkConfigChangeTrigger(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			force: false,

			expected:       false,
			expectedCauses: nil,
		},
		{
			name: "image change trigger only [automatic=false][w/ podtemplate change]",

			config: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplateChanged(), // Irrelevant change
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkNonAutomaticICT(), // Image still to be resolved but it's false anyway
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			decoded: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkNonAutomaticICT(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			force: false,

			expected:       false,
			expectedCauses: nil,
			expectedErr:    true,
		},
		{
			name: "image change trigger only [automatic=false][w/ image change]",

			config: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplateChanged(), // Image has been updated in the template but automatic=false
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkTriggeredNonAutomatic(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			decoded: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkNonAutomaticICT(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			force: false,

			expected:       false,
			expectedCauses: nil,
		},
		{
			name: "image change trigger only [automatic=true][w/ image change]",

			config: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplateChanged(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkTriggeredImageChange(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			decoded: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkImageChangeTrigger(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			force: false,

			expected:       true,
			expectedCauses: deploytest.OkImageChangeDetails().Causes,
		},
		{
			name: "image change trigger only [automatic=true][no change]",

			config: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplateChanged(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkTriggeredImageChange(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			decoded: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplateChanged(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkTriggeredImageChange(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			force: false,

			expected:       false,
			expectedCauses: nil,
		},
		{
			name: "config change and image change trigger [automatic=false][initial][w/ image change]",

			config: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplateChanged(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkConfigChangeTrigger(),
						deploytest.OkTriggeredNonAutomatic(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(0),
			},
			decoded: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkConfigChangeTrigger(),
						deploytest.OkNonAutomaticICT(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(0),
			},
			force: false,

			expected:       true,
			expectedCauses: deploytest.OkConfigChangeDetails().Causes,
		},
		{
			name: "config change and image change trigger [automatic=false][initial][no change]",

			config: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkConfigChangeTrigger(),
						deploytest.OkNonAutomaticICT(), // Image is not resolved yet
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(0),
			},
			decoded: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkConfigChangeTrigger(),
						deploytest.OkNonAutomaticICT(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(0),
			},
			force: false,

			expected:       false,
			expectedCauses: nil,
			expectedErr:    true,
		},
		{
			name: "config change and image change trigger [automatic=true][initial][w/ podtemplate change]",

			config: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplateChanged(), // Pod template has changed but the image in the template is yet to be updated
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkConfigChangeTrigger(),
						deploytest.OkImageChangeTrigger(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(0),
			},
			decoded: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkConfigChangeTrigger(),
						deploytest.OkImageChangeTrigger(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(0),
			},
			force: false,

			expected:       false,
			expectedCauses: nil,
			expectedErr:    true,
		},
		{
			name: "config change and image change trigger [automatic=true][initial][w/ image change]",

			config: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplateChanged(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkConfigChangeTrigger(),
						deploytest.OkTriggeredImageChange(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(0),
			},
			decoded: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkConfigChangeTrigger(),
						deploytest.OkImageChangeTrigger(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(0),
			},
			force: false,

			expected:       true,
			expectedCauses: deploytest.OkImageChangeDetails().Causes,
		},
		{
			name: "config change and image change trigger [automatic=true][no change]",

			config: &deployapi.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "config"},
				Spec: deployapi.DeploymentConfigSpec{
					Template: deploytest.OkPodTemplateChanged(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						deploytest.OkConfigChangeTrigger(),
						deploytest.OkTriggeredImageChange(),
					},
				},
				Status: deploytest.OkDeploymentConfigStatus(1),
			},
			force: false,

			expected:       false,
			expectedCauses: nil,
		},
	}

	for _, test := range tests {
		t.Logf("running scenario %q", test.name)

		fake := &ktestclient.Fake{}
		fake.AddReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
			config := test.decoded
			if config == nil {
				config = test.config
			}
			config = deploytest.RoundTripConfig(t, config)
			deployment, _ := deployutil.MakeDeployment(config, codec)
			return true, deployment, nil
		})

		test.config = deploytest.RoundTripConfig(t, test.config)

		got, gotCauses, err := canTrigger(test.config, fake, codec, test.force)
		if err != nil && !test.expectedErr {
			t.Errorf("unexpected error: %v", err)
			continue
		}
		if err == nil && test.expectedErr {
			t.Errorf("expected an error")
			continue
		}
		if test.expected != got {
			t.Errorf("expected to trigger: %t, got: %t", test.expected, got)
		}
		if !kapi.Semantic.DeepEqual(test.expectedCauses, gotCauses) {
			t.Errorf("expected causes:\n%#v\ngot:\n%#v", test.expectedCauses, gotCauses)
		}
	}
}
Example #9
0
func TestCanTrigger(t *testing.T) {
	tests := []struct {
		name string

		config  *deployapi.DeploymentConfig
		decoded *deployapi.DeploymentConfig

		expected       bool
		expectedCauses []deployapi.DeploymentCause
	}{
		{
			name: "nil decoded config",

			config:  testapi.OkDeploymentConfig(1),
			decoded: nil,

			expected:       false,
			expectedCauses: nil,
		},
		{
			name: "no trigger",

			config: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplateChanged(),
				},
				Status: testapi.OkDeploymentConfigStatus(1),
			},
			decoded: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
				},
				Status: testapi.OkDeploymentConfigStatus(1),
			},

			expected:       false,
			expectedCauses: nil,
		},
		{
			name: "config change trigger only",

			config: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplateChanged(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
					},
				},
				Status: testapi.OkDeploymentConfigStatus(1),
			},
			decoded: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
					},
				},
				Status: testapi.OkDeploymentConfigStatus(1),
			},

			expected:       true,
			expectedCauses: testapi.OkConfigChangeDetails().Causes,
		},
		{
			name: "config change trigger only [no change][initial]",

			config: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
					},
				},
				Status: testapi.OkDeploymentConfigStatus(0),
			},
			decoded: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
					},
				},
				Status: testapi.OkDeploymentConfigStatus(0),
			},

			expected:       true,
			expectedCauses: testapi.OkConfigChangeDetails().Causes,
		},
		{
			name: "config change trigger only [no change]",

			config: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
					},
				},
				Status: testapi.OkDeploymentConfigStatus(1),
			},
			decoded: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
					},
				},
				Status: testapi.OkDeploymentConfigStatus(1),
			},

			expected:       false,
			expectedCauses: nil,
		},
		{
			name: "image change trigger only [automatic=false]",

			config: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplateChanged(), // Irrelevant change
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkNonAutomaticICT(), // Image still to be resolved but it's false anyway
					},
				},
			},
			decoded: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkNonAutomaticICT(),
					},
				},
			},

			expected:       false,
			expectedCauses: nil,
		},
		{
			name: "image change trigger only [automatic=false][image triggered]",

			config: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplateChanged(), // Image has been updated in the template but automatic=false
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkTriggeredNonAutomatic(),
					},
				},
			},
			decoded: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkNonAutomaticICT(),
					},
				},
			},

			expected:       false,
			expectedCauses: nil,
		},
		{
			name: "image change trigger only [automatic=true]",

			config: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplateChanged(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkTriggeredImageChange(),
					},
				},
			},
			decoded: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkImageChangeTrigger(),
					},
				},
			},

			expected:       true,
			expectedCauses: testapi.OkImageChangeDetails().Causes,
		},
		{
			name: "image change trigger only [automatic=true][no change]",

			config: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkImageChangeTrigger(),
					},
				},
			},
			decoded: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkImageChangeTrigger(),
					},
				},
			},

			expected:       false,
			expectedCauses: nil,
		},
		{
			name: "config change and image change trigger [automatic=false][initial][image resolved]",

			config: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplateChanged(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
						testapi.OkTriggeredNonAutomatic(),
					},
				},
				Status: testapi.OkDeploymentConfigStatus(0),
			},
			decoded: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
						testapi.OkNonAutomaticICT(),
					},
				},
				Status: testapi.OkDeploymentConfigStatus(0),
			},

			expected:       true,
			expectedCauses: testapi.OkConfigChangeDetails().Causes,
		},
		{
			name: "config change and image change trigger [automatic=false][initial]",

			config: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
						testapi.OkNonAutomaticICT(), // Image is not resolved yet
					},
				},
				Status: testapi.OkDeploymentConfigStatus(0),
			},
			decoded: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
						testapi.OkNonAutomaticICT(),
					},
				},
				Status: testapi.OkDeploymentConfigStatus(0),
			},

			expected:       false,
			expectedCauses: nil,
		},
		{
			name: "config change and image change trigger [automatic=true][initial]",

			config: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplateChanged(), // Pod template has changed but the image in the template is yet to be updated
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
						testapi.OkImageChangeTrigger(),
					},
				},
				Status: testapi.OkDeploymentConfigStatus(0),
			},
			decoded: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
						testapi.OkImageChangeTrigger(),
					},
				},
				Status: testapi.OkDeploymentConfigStatus(0),
			},

			expected:       false,
			expectedCauses: nil,
		},
		{
			name: "config change and image change trigger [automatic=true][initial][image triggered]",

			config: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplateChanged(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
						testapi.OkTriggeredImageChange(),
					},
				},
				Status: testapi.OkDeploymentConfigStatus(0),
			},
			decoded: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
						testapi.OkImageChangeTrigger(),
					},
				},
				Status: testapi.OkDeploymentConfigStatus(0),
			},

			expected:       true,
			expectedCauses: testapi.OkImageChangeDetails().Causes,
		},
		{
			name: "config change and image change trigger [automatic=true][no change]",

			config: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
						testapi.OkImageChangeTrigger(),
					},
				},
				Status: testapi.OkDeploymentConfigStatus(1),
			},
			decoded: &deployapi.DeploymentConfig{
				Spec: deployapi.DeploymentConfigSpec{
					Template: testapi.OkPodTemplate(),
					Triggers: []deployapi.DeploymentTriggerPolicy{
						testapi.OkConfigChangeTrigger(),
						testapi.OkImageChangeTrigger(),
					},
				},
				Status: testapi.OkDeploymentConfigStatus(1),
			},

			expected:       false,
			expectedCauses: nil,
		},
	}

	for _, test := range tests {
		got, gotCauses := canTrigger(test.config, test.decoded)
		if test.expected != got {
			t.Errorf("%s: expected to trigger: %t, got: %t", test.name, test.expected, got)
			continue
		}
		if !kapi.Semantic.DeepEqual(test.expectedCauses, gotCauses) {
			t.Errorf("%s: expected causes:\n%#v\ngot:\n%#v", test.name, test.expectedCauses, gotCauses)
		}
	}
}
Example #10
0
func TestValidateDeploymentConfigMissingFields(t *testing.T) {
	errorCases := map[string]struct {
		DeploymentConfig api.DeploymentConfig
		ErrorType        field.ErrorType
		Field            string
	}{
		"missing name": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "", Namespace: "bar"},
				Spec:       test.OkDeploymentConfigSpec(),
			},
			field.ErrorTypeRequired,
			"metadata.name",
		},
		"missing namespace": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: ""},
				Spec:       test.OkDeploymentConfigSpec(),
			},
			field.ErrorTypeRequired,
			"metadata.namespace",
		},
		"invalid name": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "-foo", Namespace: "bar"},
				Spec:       test.OkDeploymentConfigSpec(),
			},
			field.ErrorTypeInvalid,
			"metadata.name",
		},
		"invalid namespace": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "-bar"},
				Spec:       test.OkDeploymentConfigSpec(),
			},
			field.ErrorTypeInvalid,
			"metadata.namespace",
		},

		"missing trigger.type": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
				Spec: api.DeploymentConfigSpec{
					Replicas: 1,
					Triggers: []api.DeploymentTriggerPolicy{
						{
							ImageChangeParams: &api.DeploymentTriggerImageChangeParams{
								ContainerNames: []string{"foo"},
							},
						},
					},
					Selector: test.OkSelector(),
					Strategy: test.OkStrategy(),
					Template: test.OkPodTemplate(),
				},
			},
			field.ErrorTypeRequired,
			"spec.triggers[0].type",
		},
		"missing Trigger imageChangeParams.from": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
				Spec: api.DeploymentConfigSpec{
					Replicas: 1,
					Triggers: []api.DeploymentTriggerPolicy{
						{
							Type: api.DeploymentTriggerOnImageChange,
							ImageChangeParams: &api.DeploymentTriggerImageChangeParams{
								ContainerNames: []string{"foo"},
							},
						},
					},
					Selector: test.OkSelector(),
					Strategy: test.OkStrategy(),
					Template: test.OkPodTemplate(),
				},
			},
			field.ErrorTypeRequired,
			"spec.triggers[0].imageChangeParams.from",
		},
		"invalid Trigger imageChangeParams.from.kind": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
				Spec: api.DeploymentConfigSpec{
					Replicas: 1,
					Triggers: []api.DeploymentTriggerPolicy{
						{
							Type: api.DeploymentTriggerOnImageChange,
							ImageChangeParams: &api.DeploymentTriggerImageChangeParams{
								From: kapi.ObjectReference{
									Kind: "Invalid",
									Name: "name:tag",
								},
								ContainerNames: []string{"foo"},
							},
						},
					},
					Selector: test.OkSelector(),
					Strategy: test.OkStrategy(),
					Template: test.OkPodTemplate(),
				},
			},
			field.ErrorTypeInvalid,
			"spec.triggers[0].imageChangeParams.from.kind",
		},
		"missing Trigger imageChangeParams.containerNames": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
				Spec: api.DeploymentConfigSpec{
					Replicas: 1,
					Triggers: []api.DeploymentTriggerPolicy{
						{
							Type: api.DeploymentTriggerOnImageChange,
							ImageChangeParams: &api.DeploymentTriggerImageChangeParams{
								From: kapi.ObjectReference{
									Kind: "ImageStreamTag",
									Name: "foo:v1",
								},
							},
						},
					},
					Selector: test.OkSelector(),
					Strategy: test.OkStrategy(),
					Template: test.OkPodTemplate(),
				},
			},
			field.ErrorTypeRequired,
			"spec.triggers[0].imageChangeParams.containerNames",
		},
		"missing strategy.type": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
				Spec: api.DeploymentConfigSpec{
					Replicas: 1,
					Triggers: manualTrigger(),
					Selector: test.OkSelector(),
					Strategy: api.DeploymentStrategy{
						CustomParams: test.OkCustomParams(),
					},
					Template: test.OkPodTemplate(),
				},
			},
			field.ErrorTypeRequired,
			"spec.strategy.type",
		},
		"missing strategy.customParams": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
				Spec: api.DeploymentConfigSpec{
					Replicas: 1,
					Triggers: manualTrigger(),
					Selector: test.OkSelector(),
					Strategy: api.DeploymentStrategy{
						Type: api.DeploymentStrategyTypeCustom,
					},
					Template: test.OkPodTemplate(),
				},
			},
			field.ErrorTypeRequired,
			"spec.strategy.customParams",
		},
		"missing spec.strategy.customParams.image": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
				Spec: api.DeploymentConfigSpec{
					Replicas: 1,
					Triggers: manualTrigger(),
					Selector: test.OkSelector(),
					Strategy: api.DeploymentStrategy{
						Type:         api.DeploymentStrategyTypeCustom,
						CustomParams: &api.CustomDeploymentStrategyParams{},
					},
					Template: test.OkPodTemplate(),
				},
			},
			field.ErrorTypeRequired,
			"spec.strategy.customParams.image",
		},
		"missing spec.strategy.recreateParams.pre.failurePolicy": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
				Spec: api.DeploymentConfigSpec{
					Replicas: 1,
					Strategy: api.DeploymentStrategy{
						Type: api.DeploymentStrategyTypeRecreate,
						RecreateParams: &api.RecreateDeploymentStrategyParams{
							Pre: &api.LifecycleHook{
								ExecNewPod: &api.ExecNewPodHook{
									Command:       []string{"cmd"},
									ContainerName: "container",
								},
							},
						},
					},
					Template: test.OkPodTemplate(),
					Selector: test.OkSelector(),
				},
			},
			field.ErrorTypeRequired,
			"spec.strategy.recreateParams.pre.failurePolicy",
		},
		"missing spec.strategy.recreateParams.pre.execNewPod": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
				Spec: api.DeploymentConfigSpec{
					Replicas: 1,
					Strategy: api.DeploymentStrategy{
						Type: api.DeploymentStrategyTypeRecreate,
						RecreateParams: &api.RecreateDeploymentStrategyParams{
							Pre: &api.LifecycleHook{
								FailurePolicy: api.LifecycleHookFailurePolicyRetry,
							},
						},
					},
					Template: test.OkPodTemplate(),
					Selector: test.OkSelector(),
				},
			},
			field.ErrorTypeRequired,
			"spec.strategy.recreateParams.pre.execNewPod",
		},
		"missing spec.strategy.recreateParams.pre.execNewPod.command": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
				Spec: api.DeploymentConfigSpec{
					Replicas: 1,
					Strategy: api.DeploymentStrategy{
						Type: api.DeploymentStrategyTypeRecreate,
						RecreateParams: &api.RecreateDeploymentStrategyParams{
							Pre: &api.LifecycleHook{
								FailurePolicy: api.LifecycleHookFailurePolicyRetry,
								ExecNewPod: &api.ExecNewPodHook{
									ContainerName: "container",
								},
							},
						},
					},
					Template: test.OkPodTemplate(),
					Selector: test.OkSelector(),
				},
			},
			field.ErrorTypeRequired,
			"spec.strategy.recreateParams.pre.execNewPod.command",
		},
		"missing spec.strategy.recreateParams.pre.execNewPod.containerName": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
				Spec: api.DeploymentConfigSpec{
					Replicas: 1,
					Strategy: api.DeploymentStrategy{
						Type: api.DeploymentStrategyTypeRecreate,
						RecreateParams: &api.RecreateDeploymentStrategyParams{
							Pre: &api.LifecycleHook{
								FailurePolicy: api.LifecycleHookFailurePolicyRetry,
								ExecNewPod: &api.ExecNewPodHook{
									Command: []string{"cmd"},
								},
							},
						},
					},
					Template: test.OkPodTemplate(),
					Selector: test.OkSelector(),
				},
			},
			field.ErrorTypeRequired,
			"spec.strategy.recreateParams.pre.execNewPod.containerName",
		},
		"invalid spec.strategy.recreateParams.pre.execNewPod.volumes": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
				Spec: api.DeploymentConfigSpec{
					Replicas: 1,
					Strategy: api.DeploymentStrategy{
						Type: api.DeploymentStrategyTypeRecreate,
						RecreateParams: &api.RecreateDeploymentStrategyParams{
							Pre: &api.LifecycleHook{
								FailurePolicy: api.LifecycleHookFailurePolicyRetry,
								ExecNewPod: &api.ExecNewPodHook{
									ContainerName: "container",
									Command:       []string{"cmd"},
									Volumes:       []string{"good", ""},
								},
							},
						},
					},
					Template: test.OkPodTemplate(),
					Selector: test.OkSelector(),
				},
			},
			field.ErrorTypeInvalid,
			"spec.strategy.recreateParams.pre.execNewPod.volumes[1]",
		},
		"invalid spec.strategy.rollingParams.intervalSeconds": {
			rollingConfig(-20, 1, 1),
			field.ErrorTypeInvalid,
			"spec.strategy.rollingParams.intervalSeconds",
		},
		"invalid spec.strategy.rollingParams.updatePeriodSeconds": {
			rollingConfig(1, -20, 1),
			field.ErrorTypeInvalid,
			"spec.strategy.rollingParams.updatePeriodSeconds",
		},
		"invalid spec.strategy.rollingParams.timeoutSeconds": {
			rollingConfig(1, 1, -20),
			field.ErrorTypeInvalid,
			"spec.strategy.rollingParams.timeoutSeconds",
		},
		"missing spec.strategy.rollingParams.pre.failurePolicy": {
			api.DeploymentConfig{
				ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar"},
				Spec: api.DeploymentConfigSpec{
					Replicas: 1,
					Strategy: api.DeploymentStrategy{
						Type: api.DeploymentStrategyTypeRolling,
						RollingParams: &api.RollingDeploymentStrategyParams{
							IntervalSeconds:     mkint64p(1),
							UpdatePeriodSeconds: mkint64p(1),
							TimeoutSeconds:      mkint64p(20),
							MaxSurge:            intstr.FromInt(1),
							Pre: &api.LifecycleHook{
								ExecNewPod: &api.ExecNewPodHook{
									Command:       []string{"cmd"},
									ContainerName: "container",
								},
							},
						},
					},
					Template: test.OkPodTemplate(),
					Selector: test.OkSelector(),
				},
			},
			field.ErrorTypeRequired,
			"spec.strategy.rollingParams.pre.failurePolicy",
		},
		"both maxSurge and maxUnavailable 0 spec.strategy.rollingParams.maxUnavailable": {
			rollingConfigMax(intstr.FromInt(0), intstr.FromInt(0)),
			field.ErrorTypeInvalid,
			"spec.strategy.rollingParams.maxUnavailable",
		},
		"invalid lower bound spec.strategy.rollingParams.maxUnavailable": {
			rollingConfigMax(intstr.FromInt(0), intstr.FromInt(-100)),
			field.ErrorTypeInvalid,
			"spec.strategy.rollingParams.maxUnavailable",
		},
		"invalid lower bound spec.strategy.rollingParams.maxSurge": {
			rollingConfigMax(intstr.FromInt(-1), intstr.FromInt(0)),
			field.ErrorTypeInvalid,
			"spec.strategy.rollingParams.maxSurge",
		},
		"both maxSurge and maxUnavailable 0 percent spec.strategy.rollingParams.maxUnavailable": {
			rollingConfigMax(intstr.FromString("0%"), intstr.FromString("0%")),
			field.ErrorTypeInvalid,
			"spec.strategy.rollingParams.maxUnavailable",
		},
		"invalid lower bound percent spec.strategy.rollingParams.maxUnavailable": {
			rollingConfigMax(intstr.FromInt(0), intstr.FromString("-1%")),
			field.ErrorTypeInvalid,
			"spec.strategy.rollingParams.maxUnavailable",
		},
		"invalid upper bound percent spec.strategy.rollingParams.maxUnavailable": {
			rollingConfigMax(intstr.FromInt(0), intstr.FromString("101%")),
			field.ErrorTypeInvalid,
			"spec.strategy.rollingParams.maxUnavailable",
		},
		"invalid percent spec.strategy.rollingParams.maxUnavailable": {
			rollingConfigMax(intstr.FromInt(0), intstr.FromString("foo")),
			field.ErrorTypeInvalid,
			"spec.strategy.rollingParams.maxUnavailable",
		},
		"invalid percent spec.strategy.rollingParams.maxSurge": {
			rollingConfigMax(intstr.FromString("foo"), intstr.FromString("100%")),
			field.ErrorTypeInvalid,
			"spec.strategy.rollingParams.maxSurge",
		},
	}

	for testName, v := range errorCases {
		errs := ValidateDeploymentConfig(&v.DeploymentConfig)
		if len(v.ErrorType) == 0 {
			if len(errs) > 0 {
				for _, e := range errs {
					t.Errorf("%s: unexpected error: %s", testName, e)
				}
			}
			continue
		}
		if len(errs) == 0 {
			t.Errorf("%s: expected test failure, got success", testName)
		}
		for i := range errs {
			if got, exp := errs[i].Type, v.ErrorType; got != exp {
				t.Errorf("%s: expected error \"%v\" to have type %q, but got %q", testName, errs[i], exp, got)
			}
			if got, exp := errs[i].Field, v.Field; got != exp {
				t.Errorf("%s: expected error \"%v\" to have field %q, but got %q", testName, errs[i], exp, got)
			}
		}
	}
}
Example #11
0
func TestValidateDeploymentConfigUpdate(t *testing.T) {
	oldConfig := &api.DeploymentConfig{
		ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar", ResourceVersion: "1"},
		Spec: api.DeploymentConfigSpec{
			Replicas: 1,
			Triggers: manualTrigger(),
			Selector: test.OkSelector(),
			Strategy: test.OkStrategy(),
			Template: test.OkPodTemplate(),
		},
		Status: api.DeploymentConfigStatus{
			LatestVersion: 5,
		},
	}
	newConfig := &api.DeploymentConfig{
		ObjectMeta: kapi.ObjectMeta{Name: "foo", Namespace: "bar", ResourceVersion: "1"},
		Spec: api.DeploymentConfigSpec{
			Replicas: 1,
			Triggers: manualTrigger(),
			Selector: test.OkSelector(),
			Strategy: test.OkStrategy(),
			Template: test.OkPodTemplate(),
		},
		Status: api.DeploymentConfigStatus{
			LatestVersion: 3,
		},
	}

	scenarios := []struct {
		oldLatestVersion int
		newLatestVersion int
	}{
		{5, 3},
		{5, 7},
		{0, -1},
	}

	for _, values := range scenarios {
		oldConfig.Status.LatestVersion = values.oldLatestVersion
		newConfig.Status.LatestVersion = values.newLatestVersion
		errs := ValidateDeploymentConfigUpdate(newConfig, oldConfig)
		if len(errs) == 0 {
			t.Errorf("Expected update failure")
		}
		for i := range errs {
			if errs[i].Type != field.ErrorTypeInvalid {
				t.Errorf("expected update error to have type %s: %v", field.ErrorTypeInvalid, errs[i])
			}
			if errs[i].Field != "status.latestVersion" {
				t.Errorf("expected update error to have field %s: %v", "latestVersion", errs[i])
			}
		}
	}

	// testing for a successful update
	oldConfig.Status.LatestVersion = 5
	newConfig.Status.LatestVersion = 6
	errs := ValidateDeploymentConfigUpdate(newConfig, oldConfig)
	if len(errs) > 0 {
		t.Errorf("Unexpected update failure")
	}
}