Skip to content

Commit 8339f8d

Browse files
feat: Adding first feast operator e2e test. (#4791)
* Abstracted the code to reuse the validations across different test cases. Incorporated the code review comments. Signed-off-by: lrangine <[email protected]> * Abstracted the code to reuse the validations across different test cases. Incorporated the code review comments. Signed-off-by: lrangine <[email protected]> * Abstracted the code to reuse the validations across different test cases. Incorporated the code review comments. Signed-off-by: lrangine <[email protected]> * adding the validations to check featurestore conditions are in ready state. Signed-off-by: lrangine <[email protected]> * Fixing the integration tests on the PR by updating the make target as per updated code. Signed-off-by: lrangine <[email protected]> * Fixing lint errors with line length Signed-off-by: lrangine <[email protected]> * changing the feast operator image name to localhost to incorporate code review comment. Signed-off-by: lrangine <[email protected]> --------- Signed-off-by: lrangine <[email protected]>
1 parent dc9f825 commit 8339f8d

5 files changed

Lines changed: 326 additions & 61 deletions

File tree

‎infra/feast-operator/Makefile‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@ docker-build: ## Build docker image with the manager.
145145
$(CONTAINER_TOOL) build -t ${IMG} .
146146

147147
## Build feast docker image.
148-
.PHONY: feast-docker-build
149-
feast-image-build:
150-
cd ./../.. && VERSION=operator.v0 REGISTRY=example.com make build-feature-transformation-server-docker
148+
.PHONY: feast-ci-dev-docker-img
149+
feast-ci-dev-docker-img:
150+
cd ./../.. && make build-feature-server-dev
151151

152152

153153
.PHONY: docker-push

‎infra/feast-operator/README.md‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,28 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131131
See the License for the specific language governing permissions and
132132
limitations under the License.
133133

134+
135+
136+
## Running End-to-End integration tests on local(dev) environment
137+
You need a kind cluster to run the e2e tests on local(dev) environment.
138+
139+
```shell
140+
# Default kind cluster configuration is not enough to run all the pods. In my case i was using docker with colima. kind uses the cpi and memory assigned to docker.
141+
# below memory configuration worked well but if you are using other docker runtime then please increase the cpu and memory.
142+
colima start --cpu 10 --memory 15 --disk 100
143+
144+
# create the kind cluster
145+
kind create cluster
146+
147+
# set kubernetes context to the recently created kind cluster
148+
kubectl cluster-info --context kind-kind
149+
150+
# run the command from operator directory to run e2e tests.
151+
make test-e2e
152+
153+
# delete cluster once you are done.
154+
kind delete cluster
155+
```
156+
157+
158+

‎infra/feast-operator/test/e2e/e2e_test.go‎

Lines changed: 98 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -27,40 +27,26 @@ import (
2727
"github.com/feast-dev/feast/infra/feast-operator/test/utils"
2828
)
2929

30-
const namespace = "feast-operator-system"
30+
const feastControllerNamespace = "feast-operator-system"
3131

3232
var _ = Describe("controller", Ordered, func() {
3333
BeforeAll(func() {
34-
By("installing prometheus operator")
35-
Expect(utils.InstallPrometheusOperator()).To(Succeed())
36-
37-
By("installing the cert-manager")
38-
Expect(utils.InstallCertManager()).To(Succeed())
39-
4034
By("creating manager namespace")
41-
cmd := exec.Command("kubectl", "create", "ns", namespace)
35+
cmd := exec.Command("kubectl", "create", "ns", feastControllerNamespace)
4236
_, _ = utils.Run(cmd)
4337
})
4438

4539
AfterAll(func() {
46-
By("uninstalling the Prometheus manager bundle")
47-
utils.UninstallPrometheusOperator()
48-
49-
By("uninstalling the cert-manager bundle")
50-
utils.UninstallCertManager()
51-
52-
By("removing manager namespace")
53-
cmd := exec.Command("kubectl", "delete", "ns", namespace)
54-
_, _ = utils.Run(cmd)
40+
//Add any post clean up code here.
5541
})
5642

5743
Context("Operator", func() {
58-
It("should run successfully", func() {
59-
var controllerPodName string
44+
It("Should be able to deploy and run a default feature store CR successfully", func() {
45+
//var controllerPodName string
6046
var err error
6147

6248
// projectimage stores the name of the image used in the example
63-
var projectimage = "example.com/feast-operator:v0.0.1"
49+
var projectimage = "localhost/feast-operator:v0.0.1"
6450

6551
By("building the manager(Operator) image")
6652
cmd := exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", projectimage))
@@ -72,13 +58,20 @@ var _ = Describe("controller", Ordered, func() {
7258
ExpectWithOffset(1, err).NotTo(HaveOccurred())
7359

7460
By("building the feast image")
75-
cmd = exec.Command("make", "feast-image-build")
61+
cmd = exec.Command("make", "feast-ci-dev-docker-img")
62+
_, err = utils.Run(cmd)
63+
ExpectWithOffset(1, err).NotTo(HaveOccurred())
64+
// this image will be built in above make target.
65+
var feastImage = "feastdev/feature-server:dev"
66+
var feastLocalImage = "localhost/feastdev/feature-server:dev"
67+
68+
By("Tag the local feast image for the integration tests")
69+
cmd = exec.Command("docker", "image", "tag", feastImage, feastLocalImage)
7670
_, err = utils.Run(cmd)
7771
ExpectWithOffset(1, err).NotTo(HaveOccurred())
7872

79-
var feastImage = "example.com/feature-transformation-server:operator.v0"
80-
By("loading the the feast image on Kind")
81-
err = utils.LoadImageToKindClusterWithName(feastImage)
73+
By("loading the the feast image on Kind cluster")
74+
err = utils.LoadImageToKindClusterWithName(feastLocalImage)
8275
ExpectWithOffset(1, err).NotTo(HaveOccurred())
8376

8477
By("installing CRDs")
@@ -91,41 +84,88 @@ var _ = Describe("controller", Ordered, func() {
9184
_, err = utils.Run(cmd)
9285
ExpectWithOffset(1, err).NotTo(HaveOccurred())
9386

94-
By("validating that the controller-manager pod is running as expected")
95-
verifyControllerUp := func() error {
96-
// Get pod name
97-
98-
cmd = exec.Command("kubectl", "get",
99-
"pods", "-l", "control-plane=controller-manager",
100-
"-o", "go-template={{ range .items }}"+
101-
"{{ if not .metadata.deletionTimestamp }}"+
102-
"{{ .metadata.name }}"+
103-
"{{ \"\\n\" }}{{ end }}{{ end }}",
104-
"-n", namespace,
105-
)
106-
107-
podOutput, err := utils.Run(cmd)
108-
ExpectWithOffset(2, err).NotTo(HaveOccurred())
109-
podNames := utils.GetNonEmptyLines(string(podOutput))
110-
if len(podNames) != 1 {
111-
return fmt.Errorf("expect 1 controller pods running, but got %d", len(podNames))
112-
}
113-
controllerPodName = podNames[0]
114-
ExpectWithOffset(2, controllerPodName).Should(ContainSubstring("controller-manager"))
115-
116-
// Validate pod status
117-
cmd = exec.Command("kubectl", "get",
118-
"pods", controllerPodName, "-o", "jsonpath={.status.phase}",
119-
"-n", namespace,
120-
)
121-
status, err := utils.Run(cmd)
122-
ExpectWithOffset(2, err).NotTo(HaveOccurred())
123-
if string(status) != "Running" {
124-
return fmt.Errorf("controller pod in %s status", status)
125-
}
126-
return nil
87+
timeout := 2 * time.Minute
88+
89+
controllerDeploymentName := "feast-operator-controller-manager"
90+
By("Validating that the controller-manager deployment is in available state")
91+
err = checkIfDeploymentExistsAndAvailable(feastControllerNamespace, controllerDeploymentName, timeout)
92+
Expect(err).To(BeNil(), fmt.Sprintf(
93+
"Deployment %s is not available but expected to be available. \nError: %v\n",
94+
controllerDeploymentName, err,
95+
))
96+
fmt.Printf("Feast Control Manager Deployment %s is available\n", controllerDeploymentName)
97+
98+
By("deploying the Simple Feast Custom Resource to Kubernetes")
99+
cmd = exec.Command("kubectl", "apply", "-f",
100+
"test/testdata/feast_integration_test_crs/v1alpha1_default_featurestore.yaml")
101+
_, cmdOutputerr := utils.Run(cmd)
102+
ExpectWithOffset(1, cmdOutputerr).NotTo(HaveOccurred())
103+
104+
namespace := "default"
105+
106+
deploymentNames := [3]string{"feast-simple-feast-setup-registry", "feast-simple-feast-setup-online",
107+
"feast-simple-feast-setup-offline"}
108+
for _, deploymentName := range deploymentNames {
109+
By(fmt.Sprintf("validate the feast deployment: %s is up and in availability state.", deploymentName))
110+
err = checkIfDeploymentExistsAndAvailable(namespace, deploymentName, timeout)
111+
Expect(err).To(BeNil(), fmt.Sprintf(
112+
"Deployment %s is not available but expected to be available. \nError: %v\n",
113+
deploymentName, err,
114+
))
115+
fmt.Printf("Feast Deployment %s is available\n", deploymentName)
127116
}
128-
EventuallyWithOffset(1, verifyControllerUp, time.Minute, time.Second).Should(Succeed())
117+
118+
By("Check if the feast client - kubernetes config map exists.")
119+
configMapName := "feast-simple-feast-setup-client"
120+
err = checkIfConfigMapExists(namespace, configMapName)
121+
Expect(err).To(BeNil(), fmt.Sprintf(
122+
"config map %s is not available but expected to be available. \nError: %v\n",
123+
configMapName, err,
124+
))
125+
fmt.Printf("Feast Deployment %s is available\n", configMapName)
126+
127+
serviceAccountNames := [3]string{"feast-simple-feast-setup-registry", "feast-simple-feast-setup-online",
128+
"feast-simple-feast-setup-offline"}
129+
for _, serviceAccountName := range serviceAccountNames {
130+
By(fmt.Sprintf("validate the feast service account: %s is available.", serviceAccountName))
131+
err = checkIfServiceAccountExists(namespace, serviceAccountName)
132+
Expect(err).To(BeNil(), fmt.Sprintf(
133+
"Service account %s does not exist in namespace %s. Error: %v",
134+
serviceAccountName, namespace, err,
135+
))
136+
fmt.Printf("Service account %s exists in namespace %s\n", serviceAccountName, namespace)
137+
}
138+
139+
serviceNames := [3]string{"feast-simple-feast-setup-registry", "feast-simple-feast-setup-online",
140+
"feast-simple-feast-setup-offline"}
141+
for _, serviceName := range serviceNames {
142+
By(fmt.Sprintf("validate the kubernetes service name: %s is available.", serviceName))
143+
err = checkIfKubernetesServiceExists(namespace, serviceName)
144+
Expect(err).To(BeNil(), fmt.Sprintf(
145+
"kubernetes service %s is not available but expected to be available. \nError: %v\n",
146+
serviceName, err,
147+
))
148+
fmt.Printf("kubernetes service %s is available\n", serviceName)
149+
}
150+
151+
By(fmt.Sprintf("Checking FeatureStore customer resource: %s is in Ready Status.", "simple-feast-setup"))
152+
err = checkIfFeatureStoreCustomResourceConditionsInReady("simple-feast-setup", namespace)
153+
Expect(err).To(BeNil(), fmt.Sprintf(
154+
"FeatureStore custom resource %s all conditions are not in ready state. \nError: %v\n",
155+
"simple-feast-setup", err,
156+
))
157+
fmt.Printf("FeatureStore customer resource %s conditions are in Ready State\n", "simple-feast-setup")
158+
159+
By("deleting the feast deployment")
160+
cmd = exec.Command("kubectl", "delete", "-f",
161+
"test/testdata/feast_integration_test_crs/v1alpha1_default_featurestore.yaml")
162+
_, cmdOutputerr = utils.Run(cmd)
163+
ExpectWithOffset(1, cmdOutputerr).NotTo(HaveOccurred())
164+
165+
By("Uninstalling the feast CRD")
166+
cmd = exec.Command("kubectl", "delete", "deployment", controllerDeploymentName, "-n", feastControllerNamespace)
167+
_, err = utils.Run(cmd)
168+
ExpectWithOffset(1, err).NotTo(HaveOccurred())
129169

130170
})
131171
})

0 commit comments

Comments
 (0)