1
0
Fork 0
mirror of https://github.com/kastenhq/kubestr.git synced 2024-12-15 17:50:57 +00:00
kastenhq-kubestr/pkg/fio/fio_test.go

1043 lines
26 KiB
Go
Raw Normal View History

package fio
import (
"context"
"fmt"
"os"
"testing"
"github.com/pkg/errors"
. "gopkg.in/check.v1"
v1 "k8s.io/api/core/v1"
scv1 "k8s.io/api/storage/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/fake"
k8stesting "k8s.io/client-go/testing"
)
func Test(t *testing.T) { TestingT(t) }
type FIOTestSuite struct{}
var _ = Suite(&FIOTestSuite{})
func (s *FIOTestSuite) TestRunner(c *C) {
ctx := context.Background()
runner := &FIOrunner{
Cli: nil,
}
_, err := runner.RunFio(ctx, nil)
c.Check(err, NotNil)
}
func (s *FIOTestSuite) TestRunFioHelper(c *C) {
ctx := context.Background()
for i, tc := range []struct {
cli kubernetes.Interface
stepper *fakeFioStepper
args *RunFIOArgs
expectedSteps []string
checker Checker
expectedCM string
expectedSC string
expectedSize string
expectedTFN string
expectedPVC string
}{
{ // storageclass not found
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmConfigMap: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
},
},
cPVC: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "PVC",
},
},
cPod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "Pod",
},
},
},
args: &RunFIOArgs{
StorageClass: "sc",
ConfigMapName: "CM1",
JobName: "job",
},
checker: NotNil,
expectedSteps: []string{"LCM", "DCM"},
expectedSC: "sc",
expectedSize: DefaultPVCSize,
expectedTFN: "testfile.fio",
expectedCM: "CM1",
expectedPVC: "PVC",
},
{ // storage class provided by config map
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmConfigMap: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
ConfigMapSCKey: "sc",
},
},
cPVC: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "PVC",
},
},
cPod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "Pod",
},
},
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
},
checker: IsNil,
expectedSteps: []string{"LCM", "SCE", "CPVC", "CPOD", "RFIOC", "DPOD", "DPVC", "DCM"},
expectedSC: "sc",
expectedSize: DefaultPVCSize,
expectedTFN: "testfile.fio",
expectedCM: "CM1",
expectedPVC: "PVC",
},
{ // use size provided by Configmap
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmConfigMap: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
ConfigMapSCKey: "SC2",
ConfigMapSizeKey: "10Gi",
},
},
cPVC: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "PVC",
},
},
cPod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "Pod",
},
},
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
},
checker: IsNil,
expectedSteps: []string{"LCM", "SCE", "CPVC", "CPOD", "RFIOC", "DPOD", "DPVC", "DCM"},
expectedSC: "SC2",
expectedSize: "10Gi",
expectedTFN: "testfile.fio",
expectedCM: "CM1",
expectedPVC: "PVC",
},
{ // fio test error
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmConfigMap: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
ConfigMapSCKey: "SC2",
ConfigMapSizeKey: "10Gi",
},
},
cPVC: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "PVC",
},
},
cPod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "Pod",
},
},
rFIOErr: fmt.Errorf("run fio error"),
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
},
checker: NotNil,
expectedSteps: []string{"LCM", "SCE", "CPVC", "CPOD", "RFIOC", "DPOD", "DPVC", "DCM"},
expectedSC: "SC2",
expectedSize: "10Gi",
expectedTFN: "testfile.fio",
expectedCM: "CM1",
expectedPVC: "PVC",
},
{ // create pod error
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmConfigMap: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
ConfigMapSCKey: "SC2",
ConfigMapSizeKey: "10Gi",
},
},
cPVC: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "PVC",
},
},
cPod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "Pod",
},
},
cPodErr: fmt.Errorf("pod create error"),
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
},
checker: NotNil,
expectedSteps: []string{"LCM", "SCE", "CPVC", "CPOD", "DPOD", "DPVC", "DCM"},
},
{ // create PVC error
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmConfigMap: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
ConfigMapSCKey: "SC2",
ConfigMapSizeKey: "10Gi",
},
},
cPVCErr: fmt.Errorf("pvc create error"),
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
},
checker: NotNil,
expectedSteps: []string{"LCM", "SCE", "CPVC", "DCM"},
},
{ // storageclass not found
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmConfigMap: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
ConfigMapSCKey: "SC2",
ConfigMapSizeKey: "10Gi",
},
},
sceErr: fmt.Errorf("storageclass not found error"),
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
},
checker: NotNil,
expectedSteps: []string{"LCM", "SCE", "DCM"},
},
{ // testfilename retrieval error, more than one provided
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmConfigMap: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
"testfile.fio2": "testfiledata",
ConfigMapSCKey: "SC2",
ConfigMapSizeKey: "10Gi",
},
},
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
},
checker: NotNil,
expectedSteps: []string{"LCM", "DCM"},
},
{ // storageclass not provided in args or configmap
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmConfigMap: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
},
Data: map[string]string{
"testfile.fio": "testfiledata",
ConfigMapSizeKey: "10Gi",
},
},
cPVC: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "PVC",
},
},
},
args: &RunFIOArgs{
ConfigMapName: "CM1",
JobName: "job",
},
checker: NotNil,
expectedSteps: []string{"LCM", "DCM"},
},
{ // load configmap error
cli: fake.NewSimpleClientset(),
stepper: &fakeFioStepper{
lcmErr: fmt.Errorf("failed to load configmap"),
},
args: nil,
checker: NotNil,
expectedSteps: []string{"LCM"},
},
} {
c.Log(i)
fio := &FIOrunner{
Cli: tc.cli,
fioSteps: tc.stepper,
}
_, err := fio.RunFioHelper(ctx, tc.args)
c.Check(err, tc.checker)
c.Assert(tc.stepper.steps, DeepEquals, tc.expectedSteps)
if err == nil {
c.Assert(tc.expectedSC, Equals, tc.stepper.sceExpSC)
c.Assert(tc.expectedCM, Equals, tc.stepper.lcmExpCM)
c.Assert(tc.expectedSC, Equals, tc.stepper.cPVCExpSC)
c.Assert(tc.expectedSize, Equals, tc.stepper.cPVCExpSize)
c.Assert(tc.expectedTFN, Equals, tc.stepper.cPodExpFN)
c.Assert(tc.expectedCM, Equals, tc.stepper.cPodExpCM)
c.Assert(tc.expectedPVC, Equals, tc.stepper.cPodExpPVC)
}
}
}
type fakeFioStepper struct {
steps []string
sceExpSC string
sceErr error
lcmExpCM string
lcmConfigMap *v1.ConfigMap
lcmErr error
cPVCExpSC string
cPVCExpSize string
cPVC *v1.PersistentVolumeClaim
cPVCErr error
dPVCErr error
cPodExpFN string
cPodExpCM string
cPodExpPVC string
cPod *v1.Pod
cPodErr error
dPodErr error
rFIOout string
rFIOErr error
}
func (f *fakeFioStepper) storageClassExists(ctx context.Context, storageClass string) error {
f.steps = append(f.steps, "SCE")
f.sceExpSC = storageClass
return f.sceErr
}
func (f *fakeFioStepper) loadConfigMap(ctx context.Context, args *RunFIOArgs) (*v1.ConfigMap, error) {
f.steps = append(f.steps, "LCM")
f.lcmExpCM = args.ConfigMapName
return f.lcmConfigMap, f.lcmErr
}
func (f *fakeFioStepper) createPVC(ctx context.Context, storageclass, size string) (*v1.PersistentVolumeClaim, error) {
f.steps = append(f.steps, "CPVC")
f.cPVCExpSC = storageclass
f.cPVCExpSize = size
return f.cPVC, f.cPVCErr
}
func (f *fakeFioStepper) deletePVC(ctx context.Context, pvcName string) error {
f.steps = append(f.steps, "DPVC")
return f.dPVCErr
}
func (f *fakeFioStepper) createPod(ctx context.Context, pvcName, configMapName, testFileName string) (*v1.Pod, error) {
f.steps = append(f.steps, "CPOD")
f.cPodExpCM = configMapName
f.cPodExpFN = testFileName
f.cPodExpPVC = pvcName
return f.cPod, f.cPodErr
}
func (f *fakeFioStepper) deletePod(ctx context.Context, podName string) error {
f.steps = append(f.steps, "DPOD")
return f.dPodErr
}
func (f *fakeFioStepper) runFIOCommand(ctx context.Context, podName, containerName, testFileName string) (string, error) {
f.steps = append(f.steps, "RFIOC")
return f.rFIOout, f.rFIOErr
}
func (f *fakeFioStepper) deleteConfigMap(ctx context.Context, configMap *v1.ConfigMap) error {
f.steps = append(f.steps, "DCM")
return nil
}
func (s *FIOTestSuite) TestStorageClassExists(c *C) {
ctx := context.Background()
for _, tc := range []struct {
cli kubernetes.Interface
storageClass string
checker Checker
}{
{
cli: fake.NewSimpleClientset(),
storageClass: "sc",
checker: NotNil,
},
{
cli: fake.NewSimpleClientset(&scv1.StorageClass{ObjectMeta: metav1.ObjectMeta{Name: "sc"}}),
storageClass: "sc",
checker: IsNil,
},
} {
stepper := &fioStepper{cli: tc.cli}
err := stepper.storageClassExists(ctx, tc.storageClass)
c.Check(err, tc.checker)
}
}
func (s *FIOTestSuite) TestLoadConfigMap(c *C) {
ctx := context.Background()
for i, tc := range []struct {
cli kubernetes.Interface
configMapName string
jobName string
args *RunFIOArgs
cmChecker Checker
errChecker Checker
failCreates bool
hasLabel bool
}{
{ // provided cm name not found
cli: fake.NewSimpleClientset(),
args: &RunFIOArgs{
ConfigMapName: "nonexistantcm",
},
cmChecker: IsNil,
errChecker: NotNil,
},
{ // specified config map found
cli: fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
Namespace: "default",
},
Data: map[string]string{},
}),
args: &RunFIOArgs{
ConfigMapName: "CM1",
},
cmChecker: NotNil,
errChecker: IsNil,
},
{ // specified config map not found in namespace
cli: fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "CM1",
Namespace: "badns",
},
Data: map[string]string{},
}),
args: &RunFIOArgs{
ConfigMapName: "CM1",
},
cmChecker: IsNil,
errChecker: NotNil,
},
{ // creates the default job ConfigMap
cli: fake.NewSimpleClientset(),
cmChecker: NotNil,
errChecker: IsNil,
args: &RunFIOArgs{},
hasLabel: true,
},
{ // job doesn't exist.
cli: fake.NewSimpleClientset(),
cmChecker: IsNil,
errChecker: NotNil,
args: &RunFIOArgs{
JobName: "nonExistentJob",
},
jobName: "nonExistentJob",
},
{ // Fails to create default job
cli: fake.NewSimpleClientset(),
cmChecker: IsNil,
errChecker: NotNil,
args: &RunFIOArgs{},
failCreates: true,
},
} {
c.Log(i)
stepper := &fioStepper{cli: tc.cli}
if tc.failCreates {
stepper.cli.(*fake.Clientset).Fake.PrependReactor("create", "configmaps", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, errors.New("Error creating object")
})
}
cm, err := stepper.loadConfigMap(ctx, tc.args)
c.Check(err, tc.errChecker)
c.Check(cm, tc.cmChecker)
if cm != nil {
_, ok := cm.Labels[CreatedByFIOLabel]
c.Assert(ok, Equals, tc.hasLabel)
}
}
}
func (s *FIOTestSuite) TestCreatePVC(c *C) {
ctx := context.Background()
for _, tc := range []struct {
cli kubernetes.Interface
storageclass string
size string
errChecker Checker
pvcChecker Checker
failCreates bool
}{
{
cli: fake.NewSimpleClientset(),
storageclass: "fakesc",
size: "20Gi",
errChecker: IsNil,
pvcChecker: NotNil,
},
{ // Fails to create pvc
cli: fake.NewSimpleClientset(),
storageclass: "fakesc",
size: "10Gi",
pvcChecker: IsNil,
errChecker: NotNil,
failCreates: true,
},
{ // parse error
cli: fake.NewSimpleClientset(),
storageclass: "fakesc",
size: "Not a quantity",
pvcChecker: IsNil,
errChecker: NotNil,
},
} {
stepper := &fioStepper{cli: tc.cli}
if tc.failCreates {
stepper.cli.(*fake.Clientset).Fake.PrependReactor("create", "*", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, errors.New("Error creating object")
})
}
pvc, err := stepper.createPVC(ctx, tc.storageclass, tc.size)
c.Check(err, tc.errChecker)
c.Check(pvc, tc.pvcChecker)
if pvc != nil {
c.Assert(pvc.GenerateName, Equals, PVCGenerateName)
c.Assert(*pvc.Spec.StorageClassName, Equals, tc.storageclass)
value, ok := pvc.Spec.Resources.Requests.Storage().AsInt64()
c.Assert(ok, Equals, true)
c.Assert(value, Equals, int64(21474836480))
}
}
}
func (s *FIOTestSuite) TestDeletePVC(c *C) {
ctx := context.Background()
stepper := &fioStepper{cli: fake.NewSimpleClientset(&v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc",
Namespace: GetPodNamespace(),
}})}
err := stepper.deletePVC(ctx, "pvc")
c.Assert(err, IsNil)
err = stepper.deletePVC(ctx, "pvc")
c.Assert(err, NotNil)
}
func (s *FIOTestSuite) TestCreatPod(c *C) {
ctx := context.Background()
for _, tc := range []struct {
pvcName string
configMapName string
testFileName string
reactor []k8stesting.Reactor
podReadyErr error
podSpecMergerErr error
errChecker Checker
}{
{
pvcName: "pvc",
configMapName: "cm",
testFileName: "testfile",
errChecker: IsNil,
},
{
pvcName: "pvc",
configMapName: "cm",
testFileName: "testfile",
errChecker: NotNil,
reactor: []k8stesting.Reactor{
&k8stesting.SimpleReactor{
Verb: "create",
Resource: "*",
Reaction: func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) {
return true, &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod"}}, nil
},
},
&k8stesting.SimpleReactor{
Verb: "get",
Resource: "*",
Reaction: func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, errors.New("Error getting object")
},
},
},
},
{
pvcName: "pvc",
configMapName: "cm",
testFileName: "testfile",
errChecker: NotNil,
reactor: []k8stesting.Reactor{
&k8stesting.SimpleReactor{
Verb: "create",
Resource: "*",
Reaction: func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) {
return true, &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod"}}, nil
},
},
},
podReadyErr: fmt.Errorf("pod ready error"),
},
{
pvcName: "pvc",
configMapName: "cm",
testFileName: "testfile",
errChecker: NotNil,
reactor: []k8stesting.Reactor{
&k8stesting.SimpleReactor{
Verb: "create",
Resource: "*",
Reaction: func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, fmt.Errorf("pod create error")
},
},
},
},
{
pvcName: "pvc",
configMapName: "cm",
testFileName: "sdf",
errChecker: NotNil,
podSpecMergerErr: fmt.Errorf("podspecmerger error"),
},
{
pvcName: "pvc",
configMapName: "cm",
testFileName: "",
errChecker: NotNil,
},
{
pvcName: "",
configMapName: "cm",
testFileName: "asdf",
errChecker: NotNil,
},
{
pvcName: "pvc",
configMapName: "",
testFileName: "asd",
errChecker: NotNil,
},
} {
stepper := &fioStepper{
cli: fake.NewSimpleClientset(),
podReady: &fakePodReadyChecker{prcErr: tc.podReadyErr},
podSpecMerger: &fakePodSpecMerger{psmErr: tc.podSpecMergerErr},
}
if tc.reactor != nil {
stepper.cli.(*fake.Clientset).Fake.ReactionChain = tc.reactor
}
pod, err := stepper.createPod(ctx, tc.pvcName, tc.configMapName, tc.testFileName)
c.Check(err, tc.errChecker)
if err == nil {
c.Assert(pod.GenerateName, Equals, PodGenerateName)
c.Assert(len(pod.Spec.Volumes), Equals, 2)
for _, vol := range pod.Spec.Volumes {
switch vol.Name {
case "persistent-storage":
c.Assert(vol.VolumeSource.PersistentVolumeClaim.ClaimName, Equals, tc.pvcName)
case "config-map":
c.Assert(vol.VolumeSource.ConfigMap.Name, Equals, tc.configMapName)
}
}
c.Assert(len(pod.Spec.Containers), Equals, 1)
c.Assert(pod.Spec.Containers[0].Name, Equals, ContainerName)
c.Assert(pod.Spec.Containers[0].Command, DeepEquals, []string{"/bin/sh"})
c.Assert(pod.Spec.Containers[0].Args, DeepEquals, []string{"-c", "tail -f /dev/null"})
c.Assert(pod.Spec.Containers[0].VolumeMounts, DeepEquals, []v1.VolumeMount{
{Name: "persistent-storage", MountPath: VolumeMountPath},
{Name: "config-map", MountPath: ConfigMapMountPath},
})
}
}
}
func (s *FIOTestSuite) TestDeletePod(c *C) {
ctx := context.Background()
stepper := &fioStepper{cli: fake.NewSimpleClientset(&v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "pod",
Namespace: GetPodNamespace(),
}})}
err := stepper.deletePod(ctx, "pod")
c.Assert(err, IsNil)
err = stepper.deletePod(ctx, "pod")
c.Assert(err, NotNil)
}
func (s *FIOTestSuite) TestFioTestFileName(c *C) {
for _, tc := range []struct {
configMap map[string]string
retVal string
errChecker Checker
}{
{
configMap: map[string]string{
ConfigMapSCKey: "storageclass",
ConfigMapSizeKey: "10Gi",
"testfile.fio": "some test data",
},
retVal: "testfile.fio",
errChecker: IsNil,
},
{
configMap: map[string]string{
ConfigMapSCKey: "storageclass",
ConfigMapSizeKey: "10Gi",
"testfile.fio": "some test data",
"testfile2.fio": "some test data2", // only support one file
},
retVal: "",
errChecker: NotNil,
},
} {
ret, err := fioTestFilename(tc.configMap)
c.Check(err, tc.errChecker)
c.Assert(ret, Equals, tc.retVal)
}
}
func (s *FIOTestSuite) TestRunFioCommand(c *C) {
ctx := context.Background()
for _, tc := range []struct {
executor *fakeKubeExecutor
errChecker Checker
podName string
containerName string
testFileName string
}{
{
executor: &fakeKubeExecutor{
keErr: nil,
keStrErr: "",
keStdOut: "success",
},
errChecker: IsNil,
podName: "pod",
containerName: "container",
testFileName: "tfName",
},
{
executor: &fakeKubeExecutor{
keErr: fmt.Errorf("kubeexec err"),
keStrErr: "",
keStdOut: "success",
},
errChecker: NotNil,
podName: "pod",
containerName: "container",
testFileName: "tfName",
},
} {
stepper := &fioStepper{
kubeExecutor: tc.executor,
}
out, err := stepper.runFIOCommand(ctx, tc.podName, tc.containerName, tc.testFileName)
c.Check(err, tc.errChecker)
c.Assert(out, Equals, tc.executor.keStdOut)
c.Assert(tc.executor.keInPodName, Equals, tc.podName)
c.Assert(tc.executor.keInContainerName, Equals, tc.containerName)
c.Assert(len(tc.executor.keInCommand), Equals, 4)
c.Assert(tc.executor.keInCommand[0], Equals, "fio")
c.Assert(tc.executor.keInCommand[1], Equals, "--directory")
c.Assert(tc.executor.keInCommand[2], Equals, VolumeMountPath)
jobFilePath := fmt.Sprintf("%s/%s", ConfigMapMountPath, tc.testFileName)
c.Assert(tc.executor.keInCommand[3], Equals, jobFilePath)
}
}
func (s *FIOTestSuite) TestDeleteConfigMap(c *C) {
ctx := context.Background()
defaultNS := "default"
os.Setenv(PodNamespaceEnvKey, defaultNS)
for _, tc := range []struct {
cli kubernetes.Interface
cm *v1.ConfigMap
errChecker Checker
lenCMList int
}{
{ // Don't delete it unless it has the label
cli: fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "cm",
Namespace: defaultNS,
},
}),
cm: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "cm",
Namespace: defaultNS,
},
},
errChecker: IsNil,
lenCMList: 1,
},
{ // Has label delete
cli: fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "cm",
Namespace: defaultNS,
},
}),
cm: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "cm",
Namespace: defaultNS,
Labels: map[string]string{
CreatedByFIOLabel: "true",
},
},
},
errChecker: IsNil,
lenCMList: 0,
},
{ // No cm exists
cli: fake.NewSimpleClientset(),
cm: &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "cm",
Namespace: defaultNS,
Labels: map[string]string{
CreatedByFIOLabel: "true",
},
},
},
errChecker: NotNil,
},
} {
stepper := &fioStepper{cli: tc.cli}
err := stepper.deleteConfigMap(ctx, tc.cm)
c.Check(err, tc.errChecker)
if err == nil {
list, err := stepper.cli.CoreV1().ConfigMaps(defaultNS).List(ctx, metav1.ListOptions{})
c.Check(err, IsNil)
c.Assert(len(list.Items), Equals, tc.lenCMList)
}
}
os.Unsetenv(PodNamespaceEnvKey)
}
func (s *FIOTestSuite) TestWaitForPodReady(c *C) {
ctx := context.Background()
prChecker := &podReadyChecker{
cli: fake.NewSimpleClientset(),
}
err := prChecker.waitForPodReady(ctx, "somens", "somePod")
c.Check(err, NotNil)
prChecker.cli = fake.NewSimpleClientset(&v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "somePod",
Namespace: "somens",
},
Status: v1.PodStatus{
Phase: v1.PodRunning,
},
})
}
func (s *FIOTestSuite) TestMergePodSpec(c *C) {
ctx := context.Background()
runAsUserInt64 := int64(1)
for _, tc := range []struct {
namespace string
inPodSpec v1.PodSpec
podName string
parentPod *v1.Pod
errChecker Checker
}{
{
parentPod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "podName",
Namespace: "ns",
},
Spec: v1.PodSpec{
NodeSelector: map[string]string{
"node": "selector",
},
Tolerations: []v1.Toleration{
{Value: "toleration"},
},
Containers: []v1.Container{
{Image: "Image"},
},
SecurityContext: &v1.PodSecurityContext{
RunAsUser: &runAsUserInt64,
},
},
},
namespace: "ns",
podName: "podName",
inPodSpec: v1.PodSpec{Containers: []v1.Container{{Name: "container1"}}},
errChecker: IsNil,
},
{
parentPod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "podName",
Namespace: "ns",
},
Spec: v1.PodSpec{
NodeSelector: map[string]string{
"node": "selector",
},
Tolerations: []v1.Toleration{
{Value: "toleration"},
},
Containers: []v1.Container{
{Image: "Image"},
},
SecurityContext: &v1.PodSecurityContext{
RunAsUser: &runAsUserInt64,
},
},
},
namespace: "ns",
podName: "podName",
inPodSpec: v1.PodSpec{Containers: []v1.Container{{Name: "container1"}, {Name: "container2"}}},
errChecker: NotNil,
},
{
namespace: "ns",
podName: "podName",
inPodSpec: v1.PodSpec{Containers: []v1.Container{{Name: "container1"}}},
errChecker: NotNil,
},
{
namespace: "ns",
podName: "",
inPodSpec: v1.PodSpec{Containers: []v1.Container{{Name: "container1"}}},
errChecker: NotNil,
},
} {
tempHostname := os.Getenv(PodNameEnvKey)
defer func() {
os.Setenv(PodNameEnvKey, tempHostname)
}()
os.Setenv(PodNameEnvKey, tc.podName)
cli := fake.NewSimpleClientset()
if tc.parentPod != nil {
cli = fake.NewSimpleClientset(tc.parentPod)
}
psm := podSpecMerger{cli}
outPodSpec, err := psm.mergePodSpec(ctx, tc.namespace, tc.inPodSpec)
c.Check(err, tc.errChecker)
if err == nil {
c.Assert(outPodSpec, Not(DeepEquals), tc.inPodSpec)
c.Assert(outPodSpec.NodeSelector, DeepEquals, tc.parentPod.Spec.NodeSelector)
c.Assert(outPodSpec.Tolerations, DeepEquals, tc.parentPod.Spec.Tolerations)
c.Assert(outPodSpec.Containers[0].Image, Equals, tc.parentPod.Spec.Containers[0].Image)
c.Assert(outPodSpec.SecurityContext, DeepEquals, tc.parentPod.Spec.SecurityContext)
}
os.Setenv(PodNameEnvKey, tempHostname)
}
}
func (s *FIOTestSuite) TestGetPodNamespace(c *C) {
os.Setenv(PodNamespaceEnvKey, "ns")
ns := GetPodNamespace()
c.Assert(ns, Equals, "ns")
os.Unsetenv(PodNamespaceEnvKey)
}
type fakePodReadyChecker struct {
prcErr error
}
func (f *fakePodReadyChecker) waitForPodReady(ctx context.Context, namespace, name string) error {
return f.prcErr
}
type fakePodSpecMerger struct {
psmErr error
}
func (fm *fakePodSpecMerger) mergePodSpec(ctx context.Context, namespace string, podSpec v1.PodSpec) (v1.PodSpec, error) {
return podSpec, fm.psmErr
}
type fakeKubeExecutor struct {
keErr error
keStdOut string
keStrErr string
keInNS string
keInPodName string
keInContainerName string
keInCommand []string
}
func (fk *fakeKubeExecutor) exec(namespace, podName, containerName string, command []string) (string, string, error) {
fk.keInNS = namespace
fk.keInPodName = podName
fk.keInContainerName = containerName
fk.keInCommand = command
return fk.keStdOut, fk.keStrErr, fk.keErr
}