Skip to content

Commit e0158e3

Browse files
authored
Run end-2-end tests in GitHub Actions CI (feast-dev#6)
Uses docker-compose to deploy alongside with Feast (Core, Kafka, PostgreSQL) containers, a CI container that runs end-to-end tests. As docker-compose runs the container in the same network, it can access the other containers directly through the docker network. With this PR we run a single basic integration test for Feast Core only, to validate the concept. Later on we will try to also deploy the serving container, and run more end-to-end tests.
1 parent 1891360 commit e0158e3

File tree

7 files changed

+140
-22
lines changed

7 files changed

+140
-22
lines changed

.github/workflows/integration-tests.yml

+23-9
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ jobs:
3737
dockerfile: infra/docker/ci/Dockerfile
3838
tags: v${{ github.sha }}
3939

40-
4140
# Cache the Maven repository across runs.
4241
- name: Cache Maven repository
4342
id: cache-maven
@@ -49,27 +48,42 @@ jobs:
4948
${{ runner.os }}-maven-
5049
5150
# Generate the Maven cache if needed by running a throwaway build of Feast.
51+
# --user: run as the host user, to avoid writing .m2 files to the host as root.
52+
# -e MAVEN_CONFIG: See https://github.com/carlossg/docker-maven#running-as-non-root
53+
# -v $PWD:/build: mount the current directory to write .m2 files onto the host.
5254
- name: Generate Maven cache
5355
if: steps.cache-maven.outputs.cache-hit != 'true'
54-
run: docker run --rm --user $(id -u):$(id -g) -v $PWD:/build $IMAGE bash -c "cd /build && mvn -Dmaven.repo.local=/build/.m2/repository -Dgpg.skip=true -B verify -DskipTests"
56+
run: docker run --rm --user $(id -u):$(id -g) -e MAVEN_CONFIG=/build/.m2 -v $PWD:/build $IMAGE bash -c "cd /build && mvn -Dmaven.repo.local=/build/.m2/repository -Dgpg.skip=true -B clean verify -DskipTests"
5557
env:
5658
IMAGE: ${{ secrets.CONTAINERREGISTRY_URL }}/${{ secrets.CONTAINERREGISTRY_IMAGENAMEBASE }}-ci:v${{ github.sha }}
5759

58-
# "docker-compose up --build" builds and starts docker images.
60+
# Build images in parallel.
61+
- name: Build Feast runtime and end-to-end test images
62+
run: |
63+
set -x
64+
docker-compose -f infra/docker-compose/docker-compose.yml build --parallel end-to-end-tests core online-serving
65+
env:
66+
FEAST_VERSION: v${{ github.sha }}
67+
FEAST_CI_IMAGE: ${{ secrets.CONTAINERREGISTRY_URL }}/${{ secrets.CONTAINERREGISTRY_IMAGENAMEBASE }}-ci
68+
FEAST_CORE_IMAGE: ${{ secrets.CONTAINERREGISTRY_URL }}/${{ secrets.CONTAINERREGISTRY_IMAGENAMEBASE }}-core
69+
FEAST_SERVING_IMAGE: ${{ secrets.CONTAINERREGISTRY_URL }}/${{ secrets.CONTAINERREGISTRY_IMAGENAMEBASE }}-serving
70+
71+
# "docker-compose up" starts docker containers.
72+
# "--abort-on-container-exit" ensures that the containers are shutdown when end-to-end
73+
# tests complete, and that the task exit status indicates failure if there are test failures.
5974
# Images fetched from a repository, such as Kafka, will not be built, so this
6075
# step will only build the Feast Core image.
61-
# After this step, the specified containers have been started and Docker Core
62-
# has successfully connected to its required services (such as PostgreSQL).
63-
- name: Start local Feast environment
76+
- name: Run Feast end-to-end test with Docker compose
6477
run: |
65-
docker-compose -f infra/docker-compose/docker-compose.yml up -d --build core redis kafka db
66-
for i in {1..12}; do nc -zv localhost 6565 && break; echo "Waiting for Feast Core to come online on port 6565..."; sleep 10; done
78+
set -x
79+
docker-compose -f infra/docker-compose/docker-compose.yml up --abort-on-container-exit end-to-end-tests
6780
env:
6881
COMPOSE_PROJECT_NAME: feast
6982
FEAST_VERSION: v${{ github.sha }}
83+
FEAST_CI_IMAGE: ${{ secrets.CONTAINERREGISTRY_URL }}/${{ secrets.CONTAINERREGISTRY_IMAGENAMEBASE }}-ci
7084
FEAST_CORE_IMAGE: ${{ secrets.CONTAINERREGISTRY_URL }}/${{ secrets.CONTAINERREGISTRY_IMAGENAMEBASE }}-core
85+
FEAST_SERVING_IMAGE: ${{ secrets.CONTAINERREGISTRY_URL }}/${{ secrets.CONTAINERREGISTRY_IMAGENAMEBASE }}-serving
7186
FEAST_CORE_CONFIG: direct-runner.yml
72-
FEAST_SERVING_IMAGE: gcr.io/kf-feast/feast-serving
7387
FEAST_ONLINE_SERVING_CONFIG: online-serving.yml
7488
FEAST_ONLINE_STORE_CONFIG: redis-store.yml
7589

docs/cicd/README.md

+16-8
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,36 @@
11
# FarFetch CI setup
22

3-
The CI setup ensures that PRs on GitHub are automatically tested before being merging to *master*. The CI jobs defined under
4-
5-
[.github/workflows]: ../../.github/workflows
6-
7-
run compilation, unit and end-to-end tests using GitHub Workflows.
3+
The CI setup ensures that PRs on GitHub are automatically tested before being merging to *master*. The CI jobs defined under [.github/workflows](../../.github/workflows) run compilation, unit and end-to-end tests using GitHub Workflows.
84

95
## Agent configuration
106

117
1. Spin an Azure VM with Ubuntu 18.04. Choose e.g. a B4ms instance (burstable VM with 4 cores)
128
2. Install prerequisites:
139

10+
Install **Docker**:
1411

1512
```
1613
sudo apt update
1714
sudo apt install docker.io
1815
sudo usermod -aG docker $USER
16+
```
17+
18+
Install **docker-compose**:
19+
20+
```
1921
2022
sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
2123
sudo chmod +x docker-compose
2224
```
2325

26+
Upgrade **Git** to a more recent version to ensure repos are properly checked out including `.git` directory (used by Python SDK setup.py):
27+
28+
```
29+
sudo add-apt-repository ppa:git-core/ppa -y
30+
sudo apt-get update
31+
sudo apt-get install git -y
32+
```
33+
2434
3. Follow the actions to [add a self-hosted runner to your repository](https://help.github.com/en/actions/hosting-your-own-runners/adding-self-hosted-runners)
2535
4. Follow the actions to [configure the self-hosted runner as a service](https://help.github.com/en/actions/hosting-your-own-runners/configuring-the-self-hosted-runner-application-as-a-service)
2636

@@ -38,7 +48,7 @@ Once the ACR instance is deployed, fetch the password from the Access keys secti
3848

3949
Populate the GitHub secrets settings with the ACR configuration:
4050

41-
![](create-secrets.png)
51+
![GitHub secrets](create-secrets.png)
4252

4353
- CONTAINERREGISTRY_IMAGENAMEBASE=farfetchfeast
4454
- CONTAINERREGISTRY_PASSWORD=<ACR password>
@@ -50,5 +60,3 @@ Populate the GitHub secrets settings with the ACR configuration:
5060
The integration test job deploys the application components using Docker-compose. Later on, it will be extended to run end-to-end test scenarios.
5161

5262
![Integration test job](integration-test-job.png)
53-
54-

infra/docker-compose/docker-compose.yml

+40-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ services:
2323
- -jar
2424
- /opt/feast/feast-core.jar
2525
- --spring.config.location=classpath:/application.yml,file:/etc/feast/application.yaml
26+
healthcheck:
27+
test: ["CMD", "curl", "-f", "http://localhost:8080/healthz"]
28+
interval: 30s
29+
timeout: 10s
30+
retries: 5
2631

2732
online-serving:
2833
build:
@@ -119,4 +124,38 @@ services:
119124
environment:
120125
POSTGRES_PASSWORD: password
121126
ports:
122-
- "5432:5342"
127+
- "5432:5342"
128+
129+
end-to-end-tests:
130+
build:
131+
context: ../..
132+
dockerfile: tests/e2e/Dockerfile
133+
args:
134+
FEAST_CI_IMAGE: ${FEAST_CI_IMAGE}:${FEAST_VERSION}
135+
volumes:
136+
- ../..:/feast
137+
depends_on:
138+
- core
139+
- online-serving
140+
command:
141+
- bash
142+
- -c
143+
- |
144+
set -ex
145+
cd /feast
146+
147+
make compile-protos-python
148+
149+
# Ensure Feast Core is running and has initialized
150+
for i in {1..60}; do curl -sf http://core:8080/healthz && break; echo "Waiting for Core..."; sleep 1; done
151+
curl -f http://core:8080/healthz
152+
153+
# Run single end-to-end test
154+
cd tests/e2e
155+
pytest basic-ingest-redis-serving.py \
156+
--core_url core:6565 \
157+
--serving_url online-serving:6566 \
158+
-k test_basic_register_feature_set_success \
159+
-sv \
160+
--junitxml=build/junit.xml \
161+
-o junit_family=xunit2

infra/docker/ci/Dockerfile

+5-2
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,8 @@ RUN PROTOC_ZIP=protoc-${PROTOC_VERSION}-linux-x86_64.zip && \
4444
go build && mkdir -p $HOME/bin && cp protoc-gen-docs $HOME/bin
4545

4646
COPY Makefile /build/Makefile
47-
COPY sdk/python/requirements-ci.txt /build/sdk/python/requirements-ci.txt
48-
RUN cd /build && make install-python-ci-dependencies install-go-ci-dependencies && rm -rf /build
47+
COPY sdk/python/requirements-*.txt /build/sdk/python/
48+
RUN cd /build && \
49+
make install-python-ci-dependencies install-go-ci-dependencies && \
50+
pip install -r sdk/python/requirements-dev.txt && \
51+
rm -rf /build

infra/docker/core/Dockerfile

+15-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,22 @@
44

55
FROM maven:3.6-jdk-11-slim as builder
66
ARG REVISION=dev
7-
COPY . /build
7+
88
WORKDIR /build
9+
10+
COPY datatypes datatypes
11+
COPY storage storage
12+
COPY sdk/java sdk/java
13+
COPY core core
14+
COPY ingestion ingestion
15+
COPY protos protos
16+
COPY serving serving
17+
COPY pom.xml pom.xml
18+
19+
# Trick to copy .m2 directory only if it exists.
20+
# The LICENSE file is any file that actually exists, to make sure the command doesn't fail.
21+
COPY LICENSE .m[2] .m2/
22+
923
#
1024
# Setting Maven repository .m2 directory relative to /build folder gives the
1125
# user to optionally use cached repository when building the image by copying

infra/docker/serving/Dockerfile

+15-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,22 @@
44

55
FROM maven:3.6-jdk-11 as builder
66
ARG REVISION=dev
7-
COPY . /build
7+
88
WORKDIR /build
9+
10+
COPY datatypes datatypes
11+
COPY storage storage
12+
COPY sdk/java sdk/java
13+
COPY core core
14+
COPY ingestion ingestion
15+
COPY protos protos
16+
COPY serving serving
17+
COPY pom.xml pom.xml
18+
19+
# Trick to copy .m2 directory only if it exists.
20+
# The LICENSE file is any file that actually exists, to make sure the command doesn't fail.
21+
COPY LICENSE .m[2] .m2/
22+
923
#
1024
# Setting Maven repository .m2 directory relative to /build folder gives the
1125
# user to optionally use cached repository when building the image by copying

tests/e2e/Dockerfile

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
ARG FEAST_CI_IMAGE
2+
3+
FROM ${FEAST_CI_IMAGE}
4+
5+
WORKDIR /feast
6+
7+
COPY Makefile .
8+
COPY protos protos
9+
COPY sdk/python sdk/python
10+
11+
# Compile feast.core Python protobuf module
12+
# FIXME this is redundant with infra/docker/ci/Dockerfile
13+
RUN make compile-protos-python
14+
15+
# Install Feast Python SDK and test requirements
16+
17+
COPY tests/e2e/requirements.txt tests/e2e/requirements.txt
18+
COPY README.md README.md
19+
20+
# setup.py in sdk/python grabs the version number from the .git
21+
# files, but we don't want to COPY .git so as to maximize
22+
# layer reuse. Fool it by initialize an empty .git repository.
23+
RUN git init .
24+
25+
RUN pip install -qe sdk/python && \
26+
pip install -qr tests/e2e/requirements.txt

0 commit comments

Comments
 (0)