/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package kubectl

import (
	"reflect"
	"testing"

	appsv1beta1 "k8s.io/api/apps/v1beta1"
	batchv1 "k8s.io/api/batch/v1"
	batchv1beta1 "k8s.io/api/batch/v1beta1"
	batchv2alpha1 "k8s.io/api/batch/v2alpha1"
	"k8s.io/api/core/v1"
	extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestGenerate(t *testing.T) {
	one := int32(1)
	tests := []struct {
		params    map[string]interface{}
		expected  *v1.ReplicationController
		expectErr bool
	}{
		{
			params: map[string]interface{}{
				"name":              "foo",
				"image":             "someimage",
				"image-pull-policy": "Always",
				"replicas":          "1",
				"port":              "",
			},
			expected: &v1.ReplicationController{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"run": "foo"},
				},
				Spec: v1.ReplicationControllerSpec{
					Replicas: &one,
					Selector: map[string]string{"run": "foo"},
					Template: &v1.PodTemplateSpec{
						ObjectMeta: metav1.ObjectMeta{
							Labels: map[string]string{"run": "foo"},
						},
						Spec: v1.PodSpec{
							Containers: []v1.Container{
								{
									Name:            "foo",
									Image:           "someimage",
									ImagePullPolicy: v1.PullAlways,
								},
							},
						},
					},
				},
			},
		},

		{
			params: map[string]interface{}{
				"name":     "foo",
				"image":    "someimage",
				"replicas": "1",
				"port":     "",
				"env":      []string{"a=b", "c=d"},
			},
			expected: &v1.ReplicationController{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"run": "foo"},
				},
				Spec: v1.ReplicationControllerSpec{
					Replicas: &one,
					Selector: map[string]string{"run": "foo"},
					Template: &v1.PodTemplateSpec{
						ObjectMeta: metav1.ObjectMeta{
							Labels: map[string]string{"run": "foo"},
						},
						Spec: v1.PodSpec{
							Containers: []v1.Container{
								{
									Name:  "foo",
									Image: "someimage",
									Env: []v1.EnvVar{
										{
											Name:  "a",
											Value: "b",
										},
										{
											Name:  "c",
											Value: "d",
										},
									},
								},
							},
						},
					},
				},
			},
		},

		{
			params: map[string]interface{}{
				"name":              "foo",
				"image":             "someimage",
				"image-pull-policy": "Never",
				"replicas":          "1",
				"port":              "",
				"args":              []string{"bar", "baz", "blah"},
			},
			expected: &v1.ReplicationController{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"run": "foo"},
				},
				Spec: v1.ReplicationControllerSpec{
					Replicas: &one,
					Selector: map[string]string{"run": "foo"},
					Template: &v1.PodTemplateSpec{
						ObjectMeta: metav1.ObjectMeta{
							Labels: map[string]string{"run": "foo"},
						},
						Spec: v1.PodSpec{
							Containers: []v1.Container{
								{
									Name:            "foo",
									Image:           "someimage",
									ImagePullPolicy: v1.PullNever,
									Args:            []string{"bar", "baz", "blah"},
								},
							},
						},
					},
				},
			},
		},
		{
			params: map[string]interface{}{
				"name":     "foo",
				"image":    "someimage",
				"replicas": "1",
				"port":     "",
				"args":     []string{"bar", "baz", "blah"},
				"command":  "true",
			},
			expected: &v1.ReplicationController{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"run": "foo"},
				},
				Spec: v1.ReplicationControllerSpec{
					Replicas: &one,
					Selector: map[string]string{"run": "foo"},
					Template: &v1.PodTemplateSpec{
						ObjectMeta: metav1.ObjectMeta{
							Labels: map[string]string{"run": "foo"},
						},
						Spec: v1.PodSpec{
							Containers: []v1.Container{
								{
									Name:    "foo",
									Image:   "someimage",
									Command: []string{"bar", "baz", "blah"},
								},
							},
						},
					},
				},
			},
		},
		{
			params: map[string]interface{}{
				"name":     "foo",
				"image":    "someimage",
				"replicas": "1",
				"port":     "80",
			},
			expected: &v1.ReplicationController{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"run": "foo"},
				},
				Spec: v1.ReplicationControllerSpec{
					Replicas: &one,
					Selector: map[string]string{"run": "foo"},
					Template: &v1.PodTemplateSpec{
						ObjectMeta: metav1.ObjectMeta{
							Labels: map[string]string{"run": "foo"},
						},
						Spec: v1.PodSpec{
							Containers: []v1.Container{
								{
									Name:  "foo",
									Image: "someimage",
									Ports: []v1.ContainerPort{
										{
											ContainerPort: 80,
										},
									},
								},
							},
						},
					},
				},
			},
		},
		{
			params: map[string]interface{}{
				"name":              "foo",
				"image":             "someimage",
				"image-pull-policy": "IfNotPresent",
				"replicas":          "1",
				"port":              "80",
				"hostport":          "80",
			},
			expected: &v1.ReplicationController{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"run": "foo"},
				},
				Spec: v1.ReplicationControllerSpec{
					Replicas: &one,
					Selector: map[string]string{"run": "foo"},
					Template: &v1.PodTemplateSpec{
						ObjectMeta: metav1.ObjectMeta{
							Labels: map[string]string{"run": "foo"},
						},
						Spec: v1.PodSpec{
							Containers: []v1.Container{
								{
									Name:            "foo",
									Image:           "someimage",
									ImagePullPolicy: v1.PullIfNotPresent,
									Ports: []v1.ContainerPort{
										{
											ContainerPort: 80,
											HostPort:      80,
										},
									},
								},
							},
						},
					},
				},
			},
		},
		{
			params: map[string]interface{}{
				"name":     "foo",
				"image":    "someimage",
				"replicas": "1",
				"hostport": "80",
			},
			expected:  nil,
			expectErr: true,
		},
		{
			params: map[string]interface{}{
				"name":     "foo",
				"image":    "someimage",
				"replicas": "1",
				"labels":   "foo=bar,baz=blah",
			},
			expected: &v1.ReplicationController{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"foo": "bar", "baz": "blah"},
				},
				Spec: v1.ReplicationControllerSpec{
					Replicas: &one,
					Selector: map[string]string{"foo": "bar", "baz": "blah"},
					Template: &v1.PodTemplateSpec{
						ObjectMeta: metav1.ObjectMeta{
							Labels: map[string]string{"foo": "bar", "baz": "blah"},
						},
						Spec: v1.PodSpec{
							Containers: []v1.Container{
								{
									Name:  "foo",
									Image: "someimage",
								},
							},
						},
					},
				},
			},
		},
		{
			params: map[string]interface{}{
				"name":     "foo",
				"image":    "someimage",
				"replicas": "1",
				"hostport": "80",
			},
			expected:  nil,
			expectErr: true,
		},
		{
			params: map[string]interface{}{
				"name":     "foo",
				"image":    "someimage",
				"replicas": "1",
				"labels":   "foo=bar,baz=blah",
				"requests": "cpu100m,memory=100Mi",
			},
			expected:  nil,
			expectErr: true,
		},
		{
			params: map[string]interface{}{
				"name":     "foo",
				"image":    "someimage",
				"replicas": "1",
				"labels":   "foo=bar,baz=blah",
				"requests": "cpu=100m&memory=100Mi",
			},
			expected:  nil,
			expectErr: true,
		},
		{
			params: map[string]interface{}{
				"name":     "foo",
				"image":    "someimage",
				"replicas": "1",
				"labels":   "foo=bar,baz=blah",
				"requests": "cpu=",
			},
			expected:  nil,
			expectErr: true,
		},
		{
			params: map[string]interface{}{
				"name":     "foo",
				"image":    "someimage",
				"replicas": "1",
				"labels":   "foo=bar,baz=blah",
				"requests": "cpu=100m,memory=100Mi",
				"limits":   "cpu=400m,memory=200Mi",
			},
			expected: &v1.ReplicationController{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"foo": "bar", "baz": "blah"},
				},
				Spec: v1.ReplicationControllerSpec{
					Replicas: &one,
					Selector: map[string]string{"foo": "bar", "baz": "blah"},
					Template: &v1.PodTemplateSpec{
						ObjectMeta: metav1.ObjectMeta{
							Labels: map[string]string{"foo": "bar", "baz": "blah"},
						},
						Spec: v1.PodSpec{
							Containers: []v1.Container{
								{
									Name:  "foo",
									Image: "someimage",
									Resources: v1.ResourceRequirements{
										Requests: v1.ResourceList{
											v1.ResourceCPU:    resource.MustParse("100m"),
											v1.ResourceMemory: resource.MustParse("100Mi"),
										},
										Limits: v1.ResourceList{
											v1.ResourceCPU:    resource.MustParse("400m"),
											v1.ResourceMemory: resource.MustParse("200Mi"),
										},
									},
								},
							},
						},
					},
				},
			},
		},
	}
	generator := BasicReplicationController{}
	for i, test := range tests {
		obj, err := generator.Generate(test.params)
		t.Logf("%d: %#v", i, obj)
		if !test.expectErr && err != nil {
			t.Errorf("unexpected error: %v", err)
			continue
		}
		if test.expectErr && err != nil {
			continue
		}
		if !reflect.DeepEqual(obj.(*v1.ReplicationController).Spec.Template, test.expected.Spec.Template) {
			t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected.Spec.Template, obj.(*v1.ReplicationController).Spec.Template)
		}
	}
}

func TestGeneratePod(t *testing.T) {
	tests := []struct {
		params    map[string]interface{}
		expected  *v1.Pod
		expectErr bool
	}{
		{
			params: map[string]interface{}{
				"name":  "foo",
				"image": "someimage",
				"port":  "",
			},
			expected: &v1.Pod{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"run": "foo"},
				},
				Spec: v1.PodSpec{
					Containers: []v1.Container{
						{
							Name:            "foo",
							Image:           "someimage",
							ImagePullPolicy: v1.PullIfNotPresent,
						},
					},
					DNSPolicy:     v1.DNSClusterFirst,
					RestartPolicy: v1.RestartPolicyAlways,
				},
			},
		},
		{
			params: map[string]interface{}{
				"name":  "foo",
				"image": "someimage",
				"env":   []string{"a", "c"},
			},

			expected:  nil,
			expectErr: true,
		},
		{
			params: map[string]interface{}{
				"name":              "foo",
				"image":             "someimage",
				"image-pull-policy": "Always",
				"env":               []string{"a=b", "c=d"},
			},
			expected: &v1.Pod{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"run": "foo"},
				},
				Spec: v1.PodSpec{
					Containers: []v1.Container{
						{
							Name:            "foo",
							Image:           "someimage",
							ImagePullPolicy: v1.PullAlways,
							Env: []v1.EnvVar{
								{
									Name:  "a",
									Value: "b",
								},
								{
									Name:  "c",
									Value: "d",
								},
							},
						},
					},
					DNSPolicy:     v1.DNSClusterFirst,
					RestartPolicy: v1.RestartPolicyAlways,
				},
			},
		},
		{
			params: map[string]interface{}{
				"name":  "foo",
				"image": "someimage",
				"port":  "80",
			},
			expected: &v1.Pod{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"run": "foo"},
				},
				Spec: v1.PodSpec{
					Containers: []v1.Container{
						{
							Name:            "foo",
							Image:           "someimage",
							ImagePullPolicy: v1.PullIfNotPresent,
							Ports: []v1.ContainerPort{
								{
									ContainerPort: 80,
								},
							},
						},
					},
					DNSPolicy:     v1.DNSClusterFirst,
					RestartPolicy: v1.RestartPolicyAlways,
				},
			},
		},
		{
			params: map[string]interface{}{
				"name":     "foo",
				"image":    "someimage",
				"port":     "80",
				"hostport": "80",
			},
			expected: &v1.Pod{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"run": "foo"},
				},
				Spec: v1.PodSpec{
					Containers: []v1.Container{
						{
							Name:            "foo",
							Image:           "someimage",
							ImagePullPolicy: v1.PullIfNotPresent,
							Ports: []v1.ContainerPort{
								{
									ContainerPort: 80,
									HostPort:      80,
								},
							},
						},
					},
					DNSPolicy:     v1.DNSClusterFirst,
					RestartPolicy: v1.RestartPolicyAlways,
				},
			},
		},
		{
			params: map[string]interface{}{
				"name":     "foo",
				"image":    "someimage",
				"hostport": "80",
			},
			expected:  nil,
			expectErr: true,
		},
		{
			params: map[string]interface{}{
				"name":     "foo",
				"image":    "someimage",
				"replicas": "1",
				"labels":   "foo=bar,baz=blah",
			},
			expected: &v1.Pod{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"foo": "bar", "baz": "blah"},
				},
				Spec: v1.PodSpec{
					Containers: []v1.Container{
						{
							Name:            "foo",
							Image:           "someimage",
							ImagePullPolicy: v1.PullIfNotPresent,
						},
					},
					DNSPolicy:     v1.DNSClusterFirst,
					RestartPolicy: v1.RestartPolicyAlways,
				},
			},
		},
		{
			params: map[string]interface{}{
				"name":     "foo",
				"image":    "someimage",
				"replicas": "1",
				"labels":   "foo=bar,baz=blah",
				"stdin":    "true",
			},
			expected: &v1.Pod{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"foo": "bar", "baz": "blah"},
				},
				Spec: v1.PodSpec{
					Containers: []v1.Container{
						{
							Name:            "foo",
							Image:           "someimage",
							ImagePullPolicy: v1.PullIfNotPresent,
							Stdin:           true,
							StdinOnce:       true,
						},
					},
					DNSPolicy:     v1.DNSClusterFirst,
					RestartPolicy: v1.RestartPolicyAlways,
				},
			},
		},
		{
			params: map[string]interface{}{
				"name":             "foo",
				"image":            "someimage",
				"replicas":         "1",
				"labels":           "foo=bar,baz=blah",
				"stdin":            "true",
				"leave-stdin-open": "true",
			},
			expected: &v1.Pod{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"foo": "bar", "baz": "blah"},
				},
				Spec: v1.PodSpec{
					Containers: []v1.Container{
						{
							Name:            "foo",
							Image:           "someimage",
							ImagePullPolicy: v1.PullIfNotPresent,
							Stdin:           true,
							StdinOnce:       false,
						},
					},
					DNSPolicy:     v1.DNSClusterFirst,
					RestartPolicy: v1.RestartPolicyAlways,
				},
			},
		},
	}
	generator := BasicPod{}
	for _, test := range tests {
		obj, err := generator.Generate(test.params)
		if !test.expectErr && err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		if test.expectErr && err != nil {
			continue
		}
		if !reflect.DeepEqual(obj.(*v1.Pod), test.expected) {
			t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*v1.Pod))
		}
	}
}

func TestGenerateDeployment(t *testing.T) {
	three := int32(3)
	tests := []struct {
		params    map[string]interface{}
		expected  *extensionsv1beta1.Deployment
		expectErr bool
	}{
		{
			params: map[string]interface{}{
				"labels":            "foo=bar,baz=blah",
				"name":              "foo",
				"replicas":          "3",
				"image":             "someimage",
				"image-pull-policy": "Always",
				"port":              "80",
				"hostport":          "80",
				"stdin":             "true",
				"command":           "true",
				"args":              []string{"bar", "baz", "blah"},
				"env":               []string{"a=b", "c=d"},
				"requests":          "cpu=100m,memory=100Mi",
				"limits":            "cpu=400m,memory=200Mi",
			},
			expected: &extensionsv1beta1.Deployment{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"foo": "bar", "baz": "blah"},
				},
				Spec: extensionsv1beta1.DeploymentSpec{
					Replicas: &three,
					Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar", "baz": "blah"}},
					Template: v1.PodTemplateSpec{
						ObjectMeta: metav1.ObjectMeta{
							Labels: map[string]string{"foo": "bar", "baz": "blah"},
						},
						Spec: v1.PodSpec{
							Containers: []v1.Container{
								{
									Name:            "foo",
									Image:           "someimage",
									ImagePullPolicy: v1.PullAlways,
									Stdin:           true,
									Ports: []v1.ContainerPort{
										{
											ContainerPort: 80,
											HostPort:      80,
										},
									},
									Command: []string{"bar", "baz", "blah"},
									Env: []v1.EnvVar{
										{
											Name:  "a",
											Value: "b",
										},
										{
											Name:  "c",
											Value: "d",
										},
									},
									Resources: v1.ResourceRequirements{
										Requests: v1.ResourceList{
											v1.ResourceCPU:    resource.MustParse("100m"),
											v1.ResourceMemory: resource.MustParse("100Mi"),
										},
										Limits: v1.ResourceList{
											v1.ResourceCPU:    resource.MustParse("400m"),
											v1.ResourceMemory: resource.MustParse("200Mi"),
										},
									},
								},
							},
						},
					},
				},
			},
		},
	}

	generator := DeploymentV1Beta1{}
	for _, test := range tests {
		obj, err := generator.Generate(test.params)
		if !test.expectErr && err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		if test.expectErr && err != nil {
			continue
		}
		if !reflect.DeepEqual(obj.(*extensionsv1beta1.Deployment), test.expected) {
			t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*extensionsv1beta1.Deployment))
		}
	}
}

func TestGenerateAppsDeployment(t *testing.T) {
	three := int32(3)
	tests := []struct {
		params    map[string]interface{}
		expected  *appsv1beta1.Deployment
		expectErr bool
	}{
		{
			params: map[string]interface{}{
				"labels":            "foo=bar,baz=blah",
				"name":              "foo",
				"replicas":          "3",
				"image":             "someimage",
				"image-pull-policy": "Always",
				"port":              "80",
				"hostport":          "80",
				"stdin":             "true",
				"command":           "true",
				"args":              []string{"bar", "baz", "blah"},
				"env":               []string{"a=b", "c=d"},
				"requests":          "cpu=100m,memory=100Mi",
				"limits":            "cpu=400m,memory=200Mi",
			},
			expected: &appsv1beta1.Deployment{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"foo": "bar", "baz": "blah"},
				},
				Spec: appsv1beta1.DeploymentSpec{
					Replicas: &three,
					Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"foo": "bar", "baz": "blah"}},
					Template: v1.PodTemplateSpec{
						ObjectMeta: metav1.ObjectMeta{
							Labels: map[string]string{"foo": "bar", "baz": "blah"},
						},
						Spec: v1.PodSpec{
							Containers: []v1.Container{
								{
									Name:            "foo",
									Image:           "someimage",
									ImagePullPolicy: v1.PullAlways,
									Stdin:           true,
									Ports: []v1.ContainerPort{
										{
											ContainerPort: 80,
											HostPort:      80,
										},
									},
									Command: []string{"bar", "baz", "blah"},
									Env: []v1.EnvVar{
										{
											Name:  "a",
											Value: "b",
										},
										{
											Name:  "c",
											Value: "d",
										},
									},
									Resources: v1.ResourceRequirements{
										Requests: v1.ResourceList{
											v1.ResourceCPU:    resource.MustParse("100m"),
											v1.ResourceMemory: resource.MustParse("100Mi"),
										},
										Limits: v1.ResourceList{
											v1.ResourceCPU:    resource.MustParse("400m"),
											v1.ResourceMemory: resource.MustParse("200Mi"),
										},
									},
								},
							},
						},
					},
				},
			},
		},
	}

	generator := DeploymentAppsV1Beta1{}
	for _, test := range tests {
		obj, err := generator.Generate(test.params)
		if !test.expectErr && err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		if test.expectErr && err != nil {
			continue
		}
		if !reflect.DeepEqual(obj.(*appsv1beta1.Deployment), test.expected) {
			t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*appsv1beta1.Deployment))
		}
	}
}

func TestGenerateJob(t *testing.T) {
	tests := []struct {
		params    map[string]interface{}
		expected  *batchv1.Job
		expectErr bool
	}{
		{
			params: map[string]interface{}{
				"labels":           "foo=bar,baz=blah",
				"name":             "foo",
				"image":            "someimage",
				"port":             "80",
				"hostport":         "80",
				"stdin":            "true",
				"leave-stdin-open": "true",
				"command":          "true",
				"args":             []string{"bar", "baz", "blah"},
				"env":              []string{"a=b", "c=d"},
				"requests":         "cpu=100m,memory=100Mi",
				"limits":           "cpu=400m,memory=200Mi",
				"restart":          "OnFailure",
			},
			expected: &batchv1.Job{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"foo": "bar", "baz": "blah"},
				},
				Spec: batchv1.JobSpec{
					Template: v1.PodTemplateSpec{
						ObjectMeta: metav1.ObjectMeta{
							Labels: map[string]string{"foo": "bar", "baz": "blah"},
						},
						Spec: v1.PodSpec{
							RestartPolicy: v1.RestartPolicyOnFailure,
							Containers: []v1.Container{
								{
									Name:      "foo",
									Image:     "someimage",
									Stdin:     true,
									StdinOnce: false,
									Ports: []v1.ContainerPort{
										{
											ContainerPort: 80,
											HostPort:      80,
										},
									},
									Command: []string{"bar", "baz", "blah"},
									Env: []v1.EnvVar{
										{
											Name:  "a",
											Value: "b",
										},
										{
											Name:  "c",
											Value: "d",
										},
									},
									Resources: v1.ResourceRequirements{
										Requests: v1.ResourceList{
											v1.ResourceCPU:    resource.MustParse("100m"),
											v1.ResourceMemory: resource.MustParse("100Mi"),
										},
										Limits: v1.ResourceList{
											v1.ResourceCPU:    resource.MustParse("400m"),
											v1.ResourceMemory: resource.MustParse("200Mi"),
										},
									},
								},
							},
						},
					},
				},
			},
		},
	}

	generator := JobV1{}
	for _, test := range tests {
		obj, err := generator.Generate(test.params)
		if !test.expectErr && err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		if test.expectErr && err != nil {
			continue
		}
		if !reflect.DeepEqual(obj.(*batchv1.Job), test.expected) {
			t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*batchv1.Job))
		}
	}
}

func TestGenerateCronJobAlpha(t *testing.T) {
	tests := []struct {
		params    map[string]interface{}
		expected  *batchv2alpha1.CronJob
		expectErr bool
	}{
		{
			params: map[string]interface{}{
				"labels":           "foo=bar,baz=blah",
				"name":             "foo",
				"image":            "someimage",
				"port":             "80",
				"hostport":         "80",
				"stdin":            "true",
				"leave-stdin-open": "true",
				"command":          "true",
				"args":             []string{"bar", "baz", "blah"},
				"env":              []string{"a=b", "c=d"},
				"requests":         "cpu=100m,memory=100Mi",
				"limits":           "cpu=400m,memory=200Mi",
				"restart":          "OnFailure",
				"schedule":         "0/5 * * * ?",
			},
			expected: &batchv2alpha1.CronJob{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"foo": "bar", "baz": "blah"},
				},
				Spec: batchv2alpha1.CronJobSpec{
					Schedule:          "0/5 * * * ?",
					ConcurrencyPolicy: batchv2alpha1.AllowConcurrent,
					JobTemplate: batchv2alpha1.JobTemplateSpec{
						Spec: batchv1.JobSpec{
							Template: v1.PodTemplateSpec{
								ObjectMeta: metav1.ObjectMeta{
									Labels: map[string]string{"foo": "bar", "baz": "blah"},
								},
								Spec: v1.PodSpec{
									RestartPolicy: v1.RestartPolicyOnFailure,
									Containers: []v1.Container{
										{
											Name:      "foo",
											Image:     "someimage",
											Stdin:     true,
											StdinOnce: false,
											Ports: []v1.ContainerPort{
												{
													ContainerPort: 80,
													HostPort:      80,
												},
											},
											Command: []string{"bar", "baz", "blah"},
											Env: []v1.EnvVar{
												{
													Name:  "a",
													Value: "b",
												},
												{
													Name:  "c",
													Value: "d",
												},
											},
											Resources: v1.ResourceRequirements{
												Requests: v1.ResourceList{
													v1.ResourceCPU:    resource.MustParse("100m"),
													v1.ResourceMemory: resource.MustParse("100Mi"),
												},
												Limits: v1.ResourceList{
													v1.ResourceCPU:    resource.MustParse("400m"),
													v1.ResourceMemory: resource.MustParse("200Mi"),
												},
											},
										},
									},
								},
							},
						},
					},
				},
			},
		},
	}

	generator := CronJobV2Alpha1{}
	for _, test := range tests {
		obj, err := generator.Generate(test.params)
		if !test.expectErr && err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		if test.expectErr && err != nil {
			continue
		}
		if !reflect.DeepEqual(obj.(*batchv2alpha1.CronJob), test.expected) {
			t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*batchv2alpha1.CronJob))
		}
	}
}

func TestGenerateCronJobBeta(t *testing.T) {
	tests := []struct {
		params    map[string]interface{}
		expected  *batchv1beta1.CronJob
		expectErr bool
	}{
		{
			params: map[string]interface{}{
				"labels":           "foo=bar,baz=blah",
				"name":             "foo",
				"image":            "someimage",
				"port":             "80",
				"hostport":         "80",
				"stdin":            "true",
				"leave-stdin-open": "true",
				"command":          "true",
				"args":             []string{"bar", "baz", "blah"},
				"env":              []string{"a=b", "c=d"},
				"requests":         "cpu=100m,memory=100Mi",
				"limits":           "cpu=400m,memory=200Mi",
				"restart":          "OnFailure",
				"schedule":         "0/5 * * * ?",
			},
			expected: &batchv1beta1.CronJob{
				ObjectMeta: metav1.ObjectMeta{
					Name:   "foo",
					Labels: map[string]string{"foo": "bar", "baz": "blah"},
				},
				Spec: batchv1beta1.CronJobSpec{
					Schedule:          "0/5 * * * ?",
					ConcurrencyPolicy: batchv1beta1.AllowConcurrent,
					JobTemplate: batchv1beta1.JobTemplateSpec{
						Spec: batchv1.JobSpec{
							Template: v1.PodTemplateSpec{
								ObjectMeta: metav1.ObjectMeta{
									Labels: map[string]string{"foo": "bar", "baz": "blah"},
								},
								Spec: v1.PodSpec{
									RestartPolicy: v1.RestartPolicyOnFailure,
									Containers: []v1.Container{
										{
											Name:      "foo",
											Image:     "someimage",
											Stdin:     true,
											StdinOnce: false,
											Ports: []v1.ContainerPort{
												{
													ContainerPort: 80,
													HostPort:      80,
												},
											},
											Command: []string{"bar", "baz", "blah"},
											Env: []v1.EnvVar{
												{
													Name:  "a",
													Value: "b",
												},
												{
													Name:  "c",
													Value: "d",
												},
											},
											Resources: v1.ResourceRequirements{
												Requests: v1.ResourceList{
													v1.ResourceCPU:    resource.MustParse("100m"),
													v1.ResourceMemory: resource.MustParse("100Mi"),
												},
												Limits: v1.ResourceList{
													v1.ResourceCPU:    resource.MustParse("400m"),
													v1.ResourceMemory: resource.MustParse("200Mi"),
												},
											},
										},
									},
								},
							},
						},
					},
				},
			},
		},
	}

	generator := CronJobV1Beta1{}
	for _, test := range tests {
		obj, err := generator.Generate(test.params)
		if !test.expectErr && err != nil {
			t.Errorf("unexpected error: %v", err)
		}
		if test.expectErr && err != nil {
			continue
		}
		if !reflect.DeepEqual(obj.(*batchv1beta1.CronJob), test.expected) {
			t.Errorf("\nexpected:\n%#v\nsaw:\n%#v", test.expected, obj.(*batchv1beta1.CronJob))
		}
	}
}

func TestParseEnv(t *testing.T) {
	tests := []struct {
		envArray  []string
		expected  []v1.EnvVar
		expectErr bool
		test      string
	}{
		{
			envArray: []string{
				"THIS_ENV=isOK",
				"this.dotted.env=isOKToo",
				"HAS_COMMAS=foo,bar",
				"HAS_EQUALS=jJnro54iUu75xNy==",
			},
			expected: []v1.EnvVar{
				{
					Name:  "THIS_ENV",
					Value: "isOK",
				},
				{
					Name:  "this.dotted.env",
					Value: "isOKToo",
				},
				{
					Name:  "HAS_COMMAS",
					Value: "foo,bar",
				},
				{
					Name:  "HAS_EQUALS",
					Value: "jJnro54iUu75xNy==",
				},
			},
			expectErr: false,
			test:      "test case 1",
		},
		{
			envArray: []string{
				"WITH_OUT_EQUALS",
			},
			expected:  []v1.EnvVar{},
			expectErr: true,
			test:      "test case 2",
		},
		{
			envArray: []string{
				"WITH_OUT_VALUES=",
			},
			expected: []v1.EnvVar{
				{
					Name:  "WITH_OUT_VALUES",
					Value: "",
				},
			},
			expectErr: false,
			test:      "test case 3",
		},
		{
			envArray: []string{
				"=WITH_OUT_NAME",
			},
			expected:  []v1.EnvVar{},
			expectErr: true,
			test:      "test case 4",
		},
	}

	for _, test := range tests {
		envs, err := parseEnvs(test.envArray)
		if !test.expectErr && err != nil {
			t.Errorf("unexpected error: %v (%s)", err, test.test)
		}
		if test.expectErr && err != nil {
			continue
		}
		if !reflect.DeepEqual(envs, test.expected) {
			t.Errorf("\nexpected:\n%#v\nsaw:\n%#v (%s)", test.expected, envs, test.test)
		}
	}
}