Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Adding first feast operator e2e test. #4791

Merged
6 changes: 3 additions & 3 deletions infra/feast-operator/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,9 @@ docker-build: ## Build docker image with the manager.
$(CONTAINER_TOOL) build -t ${IMG} .

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


.PHONY: docker-push
Expand Down
25 changes: 25 additions & 0 deletions infra/feast-operator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,28 @@ 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.



## Running End-to-End integration tests on local(dev) environment
You need a kind cluster to run the e2e tests on local(dev) environment.

```shell
# 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.
# below memory configuration worked well but if you are using other docker runtime then please increase the cpu and memory.
colima start --cpu 10 --memory 15 --disk 100

# create the kind cluster
kind create cluster

# set kubernetes context to the recently created kind cluster
kubectl cluster-info --context kind-kind

# run the command from operator directory to run e2e tests.
make test-e2e

# delete cluster once you are done.
kind delete cluster
```



156 changes: 98 additions & 58 deletions infra/feast-operator/test/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,40 +27,26 @@ import (
"github.com/feast-dev/feast/infra/feast-operator/test/utils"
)

const namespace = "feast-operator-system"
const feastControllerNamespace = "feast-operator-system"

var _ = Describe("controller", Ordered, func() {
BeforeAll(func() {
By("installing prometheus operator")
Expect(utils.InstallPrometheusOperator()).To(Succeed())

By("installing the cert-manager")
Expect(utils.InstallCertManager()).To(Succeed())

By("creating manager namespace")
cmd := exec.Command("kubectl", "create", "ns", namespace)
cmd := exec.Command("kubectl", "create", "ns", feastControllerNamespace)
_, _ = utils.Run(cmd)
})

AfterAll(func() {
By("uninstalling the Prometheus manager bundle")
utils.UninstallPrometheusOperator()

By("uninstalling the cert-manager bundle")
utils.UninstallCertManager()

By("removing manager namespace")
cmd := exec.Command("kubectl", "delete", "ns", namespace)
_, _ = utils.Run(cmd)
//Add any post clean up code here.
})

Context("Operator", func() {
It("should run successfully", func() {
var controllerPodName string
It("Should be able to deploy and run a default feature store CR successfully", func() {
//var controllerPodName string
var err error

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

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

By("building the feast image")
cmd = exec.Command("make", "feast-image-build")
cmd = exec.Command("make", "feast-ci-dev-docker-img")
_, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
// this image will be built in above make target.
var feastImage = "feastdev/feature-server:dev"
lokeshrangineni marked this conversation as resolved.
Show resolved Hide resolved
var feastLocalImage = "localhost/feastdev/feature-server:dev"

By("Tag the local feast image for the integration tests")
cmd = exec.Command("docker", "image", "tag", feastImage, feastLocalImage)
_, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())

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

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

By("validating that the controller-manager pod is running as expected")
verifyControllerUp := func() error {
// Get pod name

cmd = exec.Command("kubectl", "get",
"pods", "-l", "control-plane=controller-manager",
"-o", "go-template={{ range .items }}"+
"{{ if not .metadata.deletionTimestamp }}"+
"{{ .metadata.name }}"+
"{{ \"\\n\" }}{{ end }}{{ end }}",
"-n", namespace,
)

podOutput, err := utils.Run(cmd)
ExpectWithOffset(2, err).NotTo(HaveOccurred())
podNames := utils.GetNonEmptyLines(string(podOutput))
if len(podNames) != 1 {
return fmt.Errorf("expect 1 controller pods running, but got %d", len(podNames))
}
controllerPodName = podNames[0]
ExpectWithOffset(2, controllerPodName).Should(ContainSubstring("controller-manager"))

// Validate pod status
cmd = exec.Command("kubectl", "get",
"pods", controllerPodName, "-o", "jsonpath={.status.phase}",
"-n", namespace,
)
status, err := utils.Run(cmd)
ExpectWithOffset(2, err).NotTo(HaveOccurred())
if string(status) != "Running" {
return fmt.Errorf("controller pod in %s status", status)
}
return nil
timeout := 2 * time.Minute

controllerDeploymentName := "feast-operator-controller-manager"
By("Validating that the controller-manager deployment is in available state")
err = checkIfDeploymentExistsAndAvailable(feastControllerNamespace, controllerDeploymentName, timeout)
Expect(err).To(BeNil(), fmt.Sprintf(
"Deployment %s is not available but expected to be available. \nError: %v\n",
controllerDeploymentName, err,
))
fmt.Printf("Feast Control Manager Deployment %s is available\n", controllerDeploymentName)

By("deploying the Simple Feast Custom Resource to Kubernetes")
cmd = exec.Command("kubectl", "apply", "-f",
"test/testdata/feast_integration_test_crs/v1alpha1_default_featurestore.yaml")
_, cmdOutputerr := utils.Run(cmd)
ExpectWithOffset(1, cmdOutputerr).NotTo(HaveOccurred())

namespace := "default"

deploymentNames := [3]string{"feast-simple-feast-setup-registry", "feast-simple-feast-setup-online",
"feast-simple-feast-setup-offline"}
for _, deploymentName := range deploymentNames {
By(fmt.Sprintf("validate the feast deployment: %s is up and in availability state.", deploymentName))
err = checkIfDeploymentExistsAndAvailable(namespace, deploymentName, timeout)
Expect(err).To(BeNil(), fmt.Sprintf(
"Deployment %s is not available but expected to be available. \nError: %v\n",
deploymentName, err,
))
fmt.Printf("Feast Deployment %s is available\n", deploymentName)
}
EventuallyWithOffset(1, verifyControllerUp, time.Minute, time.Second).Should(Succeed())

By("Check if the feast client - kubernetes config map exists.")
configMapName := "feast-simple-feast-setup-client"
err = checkIfConfigMapExists(namespace, configMapName)
Expect(err).To(BeNil(), fmt.Sprintf(
"config map %s is not available but expected to be available. \nError: %v\n",
configMapName, err,
))
fmt.Printf("Feast Deployment %s is available\n", configMapName)

serviceAccountNames := [3]string{"feast-simple-feast-setup-registry", "feast-simple-feast-setup-online",
"feast-simple-feast-setup-offline"}
for _, serviceAccountName := range serviceAccountNames {
By(fmt.Sprintf("validate the feast service account: %s is available.", serviceAccountName))
err = checkIfServiceAccountExists(namespace, serviceAccountName)
Expect(err).To(BeNil(), fmt.Sprintf(
"Service account %s does not exist in namespace %s. Error: %v",
serviceAccountName, namespace, err,
))
fmt.Printf("Service account %s exists in namespace %s\n", serviceAccountName, namespace)
}

serviceNames := [3]string{"feast-simple-feast-setup-registry", "feast-simple-feast-setup-online",
"feast-simple-feast-setup-offline"}
for _, serviceName := range serviceNames {
By(fmt.Sprintf("validate the kubernetes service name: %s is available.", serviceName))
err = checkIfKubernetesServiceExists(namespace, serviceName)
Expect(err).To(BeNil(), fmt.Sprintf(
"kubernetes service %s is not available but expected to be available. \nError: %v\n",
serviceName, err,
))
fmt.Printf("kubernetes service %s is available\n", serviceName)
}

By(fmt.Sprintf("Checking FeatureStore customer resource: %s is in Ready Status.", "simple-feast-setup"))
err = checkIfFeatureStoreCustomResourceConditionsInReady("simple-feast-setup", namespace)
Expect(err).To(BeNil(), fmt.Sprintf(
"FeatureStore custom resource %s all conditions are not in ready state. \nError: %v\n",
"simple-feast-setup", err,
))
fmt.Printf("FeatureStore customer resource %s conditions are in Ready State\n", "simple-feast-setup")

By("deleting the feast deployment")
cmd = exec.Command("kubectl", "delete", "-f",
"test/testdata/feast_integration_test_crs/v1alpha1_default_featurestore.yaml")
_, cmdOutputerr = utils.Run(cmd)
ExpectWithOffset(1, cmdOutputerr).NotTo(HaveOccurred())

By("Uninstalling the feast CRD")
cmd = exec.Command("kubectl", "delete", "deployment", controllerDeploymentName, "-n", feastControllerNamespace)
_, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())

})
})
Expand Down
Loading
Loading