Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions test/functional/ansibletest_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
. "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)

var _ = Describe("AnsibleTest controller", func() {
Expand Down Expand Up @@ -230,4 +231,132 @@ var _ = Describe("AnsibleTest controller", func() {

})

Context("workflow", func() {
When("is created", func() {
BeforeEach(func() {
openstackConfigMap, openstackSecret := CreateCommonOpenstackResources(namespace)
Expect(k8sClient.Create(ctx, openstackConfigMap)).Should(Succeed())
Expect(k8sClient.Create(ctx, openstackSecret)).Should(Succeed())

testOperatorConfigMap := CreateTestOperatorConfigMap(namespace)
Expect(k8sClient.Create(ctx, testOperatorConfigMap)).Should(Succeed())

DeferCleanup(th.DeleteInstance, CreateAnsibleTest(ansibleTestName, GetDefaultAnsibleTestWorkflowSpec()))
})

It("creates PVC with workflow step name", func() {
pvc := GetTestOperatorPVC(namespace, ansibleTestName.Name)
Expect(pvc.Name).To(ContainSubstring(ansibleTestName.Name + "-0-"))
})

It("creates pod with workflow step name", func() {
pod := GetTestOperatorPod(namespace, ansibleTestName.Name)
spec := GetDefaultAnsibleTestWorkflowSpec()
workflow := spec["workflow"].([]map[string]any)
stepName := workflow[0]["stepName"].(string)
Expect(pod.Name).To(Equal(ansibleTestName.Name + "-s00-" + stepName))
})
})

When("overrides spec defaults", func() {
BeforeEach(func() {
openstackConfigMap, openstackSecret := CreateCommonOpenstackResources(namespace)
Expect(k8sClient.Create(ctx, openstackConfigMap)).Should(Succeed())
Expect(k8sClient.Create(ctx, openstackSecret)).Should(Succeed())

testOperatorConfigMap := CreateTestOperatorConfigMap(namespace)
Expect(k8sClient.Create(ctx, testOperatorConfigMap)).Should(Succeed())

DeferCleanup(th.DeleteInstance, CreateAnsibleTest(ansibleTestName, GetDefaultAnsibleTestWorkflowSpec()))
})

It("workflow values take precedence", func() {
pod := GetTestOperatorPod(namespace, ansibleTestName.Name)
spec := GetDefaultAnsibleTestWorkflowSpec()
workflow := spec["workflow"].([]map[string]any)
expectedRepo := workflow[0]["ansibleGitRepo"].(string)
expectedPlaybook := workflow[0]["ansiblePlaybookPath"].(string)

Expect(GetPodEnvVar(pod, "POD_ANSIBLE_GIT_REPO")).To(Equal(expectedRepo))
Expect(GetPodEnvVar(pod, "POD_ANSIBLE_GIT_REPO")).NotTo(Equal(spec["ansibleGitRepo"].(string)))

Expect(GetPodEnvVar(pod, "POD_ANSIBLE_PLAYBOOK")).To(Equal(expectedPlaybook))
Expect(GetPodEnvVar(pod, "POD_ANSIBLE_PLAYBOOK")).NotTo(Equal(spec["ansiblePlaybookPath"].(string)))
})
})

When("inherits from spec defaults", func() {
BeforeEach(func() {
openstackConfigMap, openstackSecret := CreateCommonOpenstackResources(namespace)
Expect(k8sClient.Create(ctx, openstackConfigMap)).Should(Succeed())
Expect(k8sClient.Create(ctx, openstackSecret)).Should(Succeed())

testOperatorConfigMap := CreateTestOperatorConfigMap(namespace)
Expect(k8sClient.Create(ctx, testOperatorConfigMap)).Should(Succeed())

spec := GetDefaultAnsibleTestWorkflowSpec()
workflow := spec["workflow"].([]map[string]any)
delete(workflow[0], "ansibleGitRepo")
delete(workflow[0], "ansiblePlaybookPath")

DeferCleanup(th.DeleteInstance, CreateAnsibleTest(ansibleTestName, spec))
})

It("uses spec-level values when workflow step omits them", func() {
pod := GetTestOperatorPod(namespace, ansibleTestName.Name)
spec := GetDefaultAnsibleTestWorkflowSpec()
expectedRepo := spec["ansibleGitRepo"].(string)
expectedPlaybook := spec["ansiblePlaybookPath"].(string)

Expect(GetPodEnvVar(pod, "POD_ANSIBLE_GIT_REPO")).To(Equal(expectedRepo))
Expect(GetPodEnvVar(pod, "POD_ANSIBLE_PLAYBOOK")).To(Equal(expectedPlaybook))
})
})

When("with multiple workflow steps", func() {
BeforeEach(func() {
openstackConfigMap, openstackSecret := CreateCommonOpenstackResources(namespace)
Expect(k8sClient.Create(ctx, openstackConfigMap)).Should(Succeed())
Expect(k8sClient.Create(ctx, openstackSecret)).Should(Succeed())

testOperatorConfigMap := CreateTestOperatorConfigMap(namespace)
Expect(k8sClient.Create(ctx, testOperatorConfigMap)).Should(Succeed())

DeferCleanup(th.DeleteInstance, CreateAnsibleTest(ansibleTestName, GetDefaultAnsibleTestWorkflowSpec()))
})

It("creates second pod after first pod succeeds", func() {
firstPod := GetTestOperatorPod(namespace, ansibleTestName.Name)
Expect(firstPod.Name).To(Equal(ansibleTestName.Name + "-s00-first-step"))

firstPod.Status.Phase = corev1.PodSucceeded
Expect(k8sClient.Status().Update(ctx, firstPod)).Should(Succeed())

Eventually(func(g Gomega) {
podList := &corev1.PodList{}
listOpts := []client.ListOption{
client.InNamespace(namespace),
client.MatchingLabels{
"instanceName": ansibleTestName.Name,
"operator": "test-operator",
"workflowStep": "1",
},
}
g.Expect(k8sClient.List(ctx, podList, listOpts...)).Should(Succeed())
g.Expect(podList.Items).To(HaveLen(1))
secondPod := podList.Items[0]
g.Expect(secondPod.Name).To(Equal(ansibleTestName.Name + "-s01-second-step"))

spec := GetDefaultAnsibleTestWorkflowSpec()
workflow := spec["workflow"].([]map[string]any)
expectedRepo := workflow[1]["ansibleGitRepo"].(string)
expectedPlaybook := workflow[1]["ansiblePlaybookPath"].(string)

g.Expect(GetPodEnvVar(&secondPod, "POD_ANSIBLE_GIT_REPO")).To(Equal(expectedRepo))
g.Expect(GetPodEnvVar(&secondPod, "POD_ANSIBLE_PLAYBOOK")).To(Equal(expectedPlaybook))
}, timeout, interval).Should(Succeed())
})
})
})

})
83 changes: 83 additions & 0 deletions test/functional/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,17 @@ func ExpectPodNotHasVolumeMount(pod *corev1.Pod, volName string) {
}
}

func GetPodEnvVar(pod *corev1.Pod, envName string) string {
for _, container := range pod.Spec.Containers {
for _, env := range container.Env {
if env.Name == envName {
return env.Value
}
}
}
return ""
}

func GetDefaultConfigMapExtraMount() ExtraMount {
return ExtraMount{
VolName: ExtraConfigVolName,
Expand Down Expand Up @@ -296,6 +307,28 @@ func GetDefaultAnsibleTestSpec() map[string]any {
}
}

func GetDefaultAnsibleTestWorkflowSpec() map[string]any {
return map[string]any{
"storageClass": DefaultStorageClass,
"ansibleGitRepo": "https://github.com/example/test-repo",
"ansiblePlaybookPath": "tests/playbook.yaml",
"workflow": []map[string]any{
{
"stepName": "first-step",
"storageClass": DefaultStorageClass,
"ansibleGitRepo": "https://github.com/example/workflow-repo",
"ansiblePlaybookPath": "tests/workflow-playbook.yaml",
},
{
"stepName": "second-step",
"storageClass": DefaultStorageClass,
"ansibleGitRepo": "https://github.com/example/second-repo",
"ansiblePlaybookPath": "tests/second-playbook.yaml",
},
},
}
}

func AnsibleTestConditionGetter(name types.NamespacedName) condition.Conditions {
instance := GetAnsibleTest(name)
return instance.Status.Conditions
Expand Down Expand Up @@ -369,6 +402,37 @@ func GetDefaultTempestSpec() map[string]any {
}
}

func GetDefaultTempestWorkflowSpec() map[string]any {
return map[string]any{
"storageClass": DefaultStorageClass,
"tempestRun": map[string]any{
"includeList": "tempest.api.identity.v3.*",
},
"tempestconfRun": map[string]any{
"networkID": "spec-network-id",
},
"workflow": []map[string]any{
{
"stepName": "first-step",
"storageClass": DefaultStorageClass,
"tempestRun": map[string]any{
"includeList": "tempest.api.compute.*",
},
"tempestconfRun": map[string]any{
"networkID": "workflow-network-id",
},
},
{
"stepName": "second-step",
"storageClass": DefaultStorageClass,
"tempestRun": map[string]any{
"includeList": "tempest.api.network.*",
},
},
},
}
}

func TempestConditionGetter(name types.NamespacedName) condition.Conditions {
instance := GetTempest(name)
return instance.Status.Conditions
Expand Down Expand Up @@ -403,6 +467,25 @@ func GetDefaultTobikoSpec() map[string]any {
}
}

func GetDefaultTobikoWorkflowSpec() map[string]any {
return map[string]any{
"storageClass": DefaultStorageClass,
"testenv": "sanity",
"workflow": []map[string]any{
{
"stepName": "first-step",
"storageClass": DefaultStorageClass,
"testenv": "compute",
},
{
"stepName": "second-step",
"storageClass": DefaultStorageClass,
"testenv": "network",
},
},
}
}

func TobikoConditionGetter(name types.NamespacedName) condition.Conditions {
instance := GetTobiko(name)
return instance.Status.Conditions
Expand Down
Loading
Loading