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

e2e-tests: Add end-to-end test script and docker compose app #359

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
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
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,18 @@ jobs:
- run: git submodule update --init --recursive
- name: test
run: make -f dev-flow.mk config build test

e2e-test:
name: End-to-end tests
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- run: git config --global --add safe.directory /__w/aktualizr-lite/aktualizr-lite
- run: git submodule update --init --recursive
- run: ./dev-shell-e2e-test.sh make -f dev-flow.mk config build
- run: ./dev-shell-e2e-test.sh pytest e2e-test.py -k 'test_incremental_updates[True-False] or test_incremental_updates[False-False] or test_update_to_latest[False-False] or test_update_to_latest[True-False]'
env:
FACTORY: ${{ secrets.E2E_TEST_FACTORY }}
BASE_TARGET_VERSION: ${{ secrets.E2E_TEST_BASE_TARGET_VERSION }}
USER_TOKEN: ${{ secrets.E2E_TEST_USER_TOKEN }}
33 changes: 33 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,36 @@ all $(TASKS) config-coverage test-coverage-html:

test:
docker run --init -u $(shell id -u):$(shell id -g) --rm -v $(PWD):$(PWD) -w $(PWD) -eTEST_LABEL=$(TEST_LABEL) -eCTEST_ARGS=$(CTEST_ARGS) -eBUILD_DIR=$(BUILD_DIR) -eGTEST_FILTER=$(GTEST_FILTER) $(CONTAINER) make -f dev-flow.mk $@

# Commands to be used inside the aklite-e2e-test docker
BIN ?= build/src/aktualizr-lite
SOTA_DIR = /var/sota
DEVICE_FACTORY ?= ${FACTORY}
DEVICE_TOKEN ?= ${AUTH_TOKEN}
DEVICE_TAG ?= main

${SOTA_DIR}:
mkdir -p ${SOTA_DIR}/reset-apps
mkdir -p ${SOTA_DIR}/compose-apps

register: ${SOTA_DIR}
DEVICE_FACTORY=${DEVICE_FACTORY} lmp-device-register -T ${DEVICE_TOKEN} --start-daemon 0 -d ${SOTA_DIR} -t ${DEVICE_TAG}

unregister:
@rm -rf ${SOTA_DIR}/sql.db
@rm ${SOTA_DIR}/*.toml

check:
${BIN} check

update:
@ostree config set core.mode bare-user
${BIN} pull
@ostree config set core.mode bare-user-only
${BIN} install

reboot:
@rm -f /var/run/aktualizr-session/need_reboot

run:
${BIN} run
85 changes: 63 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,7 @@ The make environment variables are:
If `-f dev-flow.mk` is specified, then the `make` command is executed on a host, otherwise the `foundries/aklite-dev` container is used.
A user can specify their own container to run the commands in by overriding `CONTAINER` environment variable.

#### Build Custom Client Example

[The example of the custom client](./examples/custom-client-cxx/main.cc) depends on the `libaktualizr` and `libaktualizr_lite` libraries,
therefore they should be built prior to building of the example. Then, run:
```
make [-f dev-flow.mk] custom-client
```

### Test
### Unit Test

```
[<MAKE ENV VARS>] make [-f dev-flow.mk] test
Expand All @@ -59,22 +51,71 @@ The make environment variables are:
* `CTEST_ARGS` - additional `ctest` parameters, by default is set to `--output-on-failure`.
* `GTEST_FILTER` - a regexp to filter tests within gtest suits, e.g. `GTEST_FILTER="*OstreeUpdateNoSpaceRetry*" TEST_LABEL="aklite:liteclient" make`.

### Usage
### Development Test Environment

[Run aktualizr-lite locally against your Factory](./how-to-run-locally.md)
In order to facilitate development and testing of aktualizr-lite, an development container is made available.
It works in conjunction with a container running dockerd,
providing an environment where most of the functional aspects can be tested.
It allows the communication with an actual factory instance, getting updates and sending back events.

#### Run Custom Client Example
#### Prerequisites
1. Linux host/VM (tested on Ubuntu and Arch Linux)
2. Docker engine and client, version >= 20.10.xx
3. Docker compose, version >= 2.22.0

Prior to running of the custom client example, a user should execute all steps listed in [the how to run locally guide](./how-to-run-locally.md).
Then, the following command will start the custom client:
```
LD_LIBRARY_PATH="$LD_LIBRARY_PATH:./build/aktualizr/src/libaktualizr/:./build/src" \
AKLITE_CONFIG_DIR=<device config dir | sota.toml> ./build-custom/custom-sota-client
```
or in the dev container:
#### Set required environment variables
1. `FACTORY` - Name of your FoundriesFactory.
2. `USER_TOKEN` - Token to access your FoundriesFactory obtained from [Foundries.io settings page](https://app.foundries.io/settings/tokens/).

#### Development in the development container
Run `./dev-shell-e2e-test.sh`. The initial/first run may take some time as necessary container images are downloaded and built. Subsequent runs will be faster.

##### Register/Unregister device
Inside the development container, run `make register` or `make unregister` to register or unregister a device, respectively.
Override the `DEVICE_TAG` environment variable if you need to register a device and set its tag to a non-default value (`main`).
For example, `DEVICE_TAG=devel make register`.

##### Build aktualizr-lite
Run `make -f dev-flow.mk` to build the aktualizr-lite client.

##### Configure your development device
You can add additional configuration `*.toml` snippets to the default device configuration by placing them in `<sota-project-home-dir>/.device/etc.sota`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be useful to add an example. Something like:

cat <sota-project-home-dir>/.device/etc.sota/z-90-apps.toml

[pacman]
compose_apps="myapp"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


For example, a subset of applications that should to be started automatically can be set by creating a `<sota-project-home-dir>/.device/etc.sota/z-90-apps.toml` file with the following content:
```
docker run --rm -v $PWD:$PWD -w $PWD \
-e LD_LIBRARY_PATH="$LD_LIBRARY_PATH:./build-cont/aktualizr/src/libaktualizr/:./build-cont/src" \
-e AKLITE_CONFIG_DIR="<device config dir | sota.toml>" foundries/aklite-dev ./build-cont-custom/custom-sota-client
[pacman]
compose_apps="myapp1,myapp2"
```

##### Check/Update local TUF metadata
Run `make check` to update the local TUF (The Update Framework) repository and get a list of available targets. Alternatively, run `./build/src/atualizr-lite check`.

##### Update your development device
1. Run `make update` to update your development device to the latest available target. The initial update may take some time since it pulls the target's ostree repository from scratch. Subsequent updates are faster as they pull only the differences between two commits.
2. If a device reboot is required, run `make reboot`.
3. Finalize the update and run updated apps, if any, by running `make run`.

##### Develop and debug aktualizr-lite
After the initial update, you can continue developing and debugging aktualizr-lite:
1. Make code changes.
2. Build the code with `make -f dev-flow.mk`.
3. Run or debug one of the SOTA client commands, for example:
```bash
./build/src/atualizr-lite check # Check for TUF metadata changes and update local TUF repository if any changes are found
./build/src/atualizr-lite pull [<target>] # Pull the specified target content (ostree and/or apps)
./build/src/atualizr-lite install [<target>] # Install the pulled target
./build/src/atualizr-lite run # Finalize target installation if required after a device reboot

gdb --args ./build/src/atualizr-lite [<command&params>] # Debug

###### Emulating device reboot
To emulate a device reboot in the development container, remove the `/var/run/aktualizr-session/need_reboot` file if it exists.

### Usage on Local Environment

[Run aktualizr-lite locally against your Factory](./how-to-run-locally.md)

### Custom Client Example

Aktualizr-lite provides an API that can be used for creating a custom update client.
An example of such client is available at https://github.com/foundriesio/sotactl
2 changes: 1 addition & 1 deletion dev-flow.mk
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

CCACHE_DIR = $(shell pwd)/.ccache
BUILD_DIR ?= build
TARGET ?= aklite-tests
TARGET ?= aklite-tests aktualizr-get
TEST_LABEL ?= aklite
CTEST_ARGS ?= --output-on-failure
CXX ?= clang++
Expand Down
17 changes: 17 additions & 0 deletions dev-shell-e2e-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash

docker_dir=docker-e2e-test
docker_path=${PWD}/${docker_dir}

# Function to execute custom commands before exiting
down() {
docker compose --env-file=${docker_path}/.env.dev -f ${docker_path}/docker-compose.yml down --remove-orphans
# remove the docker runtime part
docker volume rm ${docker_dir}_docker-runtime
}

# Register the cleanup function to be called on EXIT
trap down EXIT

mkdir -p $PWD/.device/sysroot
docker compose --env-file=${docker_path}/.env.dev -f ${docker_path}/docker-compose.yml run -e DEV_USER=$(id -u) -e DEV_GROUP=$(id -g) -e BASE_TARGET_VERSION=${BASE_TARGET_VERSION} -e USER_TOKEN=${USER_TOKEN} aklite-e2e-test "$@"
19 changes: 19 additions & 0 deletions docker-e2e-test/.env.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FACTORY=$FACTORY
AUTH_TOKEN=$USER_TOKEN
DEVICE_TAG=main

DEV_DIR=$PWD/.device
SOTA_DIR=$DEV_DIR/sota
USR_SOTA_DIR=$DEV_DIR/usr.sota
ETC_SOTA_DIR=$DEV_DIR/etc.sota
DOCKER_DIR=$DEV_DIR/docker

# /sysroot dir containing ostree repo in /sysroot/ostree/repo
SYSROOT=$DEV_DIR/sysroot
BOOTDIR=$DEV_DIR/boot

# /var/lib/docker
DOCKER_DATA_ROOT=$DOCKER_DIR/data

# Dir containing Dockerfile and build context to build the "aklite-test" image
AKLITE_E2E_TEST_DOCKER_DIR=$PWD/docker-e2e-test
73 changes: 73 additions & 0 deletions docker-e2e-test/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
FROM golang:1.22.2-bookworm AS composeapp
# Build composeapp
WORKDIR /build
RUN git clone https://github.com/foundriesio/composeapp.git && cd composeapp \
&& STOREROOT=/var/sota/reset-apps COMPOSEROOT=/var/sota/compose-apps BASESYSTEMCONFIG=/usr/lib/docker make \
&& cp ./bin/composectl /usr/bin/

# We may add fioctl and fioconfig to the test sequence. For now, we don't use them
# WORKDIR /build
# RUN git clone https://github.com/foundriesio/fioconfig.git && cd fioconfig \
# && make bin/fioconfig-linux-amd64 \
# && cp ./bin/fioconfig-linux-amd64 /usr/bin/fioconfig

# WORKDIR /build
# RUN git clone https://github.com/foundriesio/fioctl.git && cd fioctl \
# && make fioctl-linux-amd64 \
# && cp ./bin/fioctl-linux-amd64 /usr/bin/fioctl


FROM foundries/aklite-dev AS aklite

# Install composectl
COPY --from=composeapp /build/composeapp/bin/composectl /usr/bin/

# # Install fioconfig
# COPY --from=composeapp /build/fioconfig/bin/fioconfig-linux-amd64 /usr/bin/fioconfig

# # Install fioctl
# COPY --from=composeapp /build/fioctl/bin/fioctl-linux-amd64 /usr/bin/fioctl


# Install lmp-device-register
RUN apt-get install -y libboost-iostreams-dev

RUN git clone https://github.com/foundriesio/lmp-device-register \
&& cd lmp-device-register && git checkout mp-90 \
&& cmake -S . -B ./build -DDOCKER_COMPOSE_APP=ON -DHARDWARE_ID=intel-corei7-64 && cmake --build ./build --target install


# Add Docker's official GPG key:
RUN apt-get update && apt-get install -y ca-certificates curl
RUN install -m 0755 -d /etc/apt/keyrings
RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
RUN chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
RUN echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null

RUN apt-get update && apt-get install -y docker-ce-cli docker-compose-plugin

# Install docker credential helper and auth configuration
COPY config.json /usr/lib/docker/config.json
COPY docker-credential-fio-helper /usr/bin/docker-credential-fio-helper

# Install gosu required for the entry/startup script to add a user and group in the container
RUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.14/gosu-amd64" && \
chmod +x /usr/local/bin/gosu && \
gosu nobody true

# Install pytest
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir pytest

# Copy the entrypoint script
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh

# Set entrypoint
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["bash"]
6 changes: 6 additions & 0 deletions docker-e2e-test/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"credHelpers": {
"hub.foundries.io": "fio-helper"
}
}

45 changes: 45 additions & 0 deletions docker-e2e-test/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
version: '3.8'

services:
dockerd:
image: docker:25.0-dind
command: ["dockerd", "-H", "unix:///var/run/docker/docker.sock"]
volumes:
- ${DOCKER_DATA_ROOT}:/var/lib/docker
- docker-runtime:/var/run/docker
privileged: true

aklite-e2e-test:
build:
context: ${AKLITE_E2E_TEST_DOCKER_DIR}
args:
AKLITE_VER: master
dockerfile: Dockerfile

image: aklite-e2e-test
volumes:
- "${PWD}:${PWD}"
- ${SYSROOT}:/sysroot
- ${SYSROOT}/ostree:/ostree
- ${BOOTDIR}:/boot
- ${SOTA_DIR}:/var/sota
- ${USR_SOTA_DIR}:/usr/lib/sota/conf.d
- ${ETC_SOTA_DIR}:/etc/sota/conf.d
- ${DOCKER_DATA_ROOT}:/var/lib/docker
- docker-runtime:/var/run/docker
working_dir: "${PWD}"
hostname: device
user: "root"
environment:
- FACTORY=${FACTORY}
- AUTH_TOKEN=${AUTH_TOKEN}
- DEVICE_TAG=${DEVICE_TAG}
- DOCKER_HOST=unix:///var/run/docker/docker.sock
- DOCKER_CONFIG=/usr/lib/docker
- CXX=clang++
- CC=clang
depends_on:
- dockerd

volumes:
docker-runtime:
19 changes: 19 additions & 0 deletions docker-e2e-test/docker-credential-fio-helper
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/sh -e

# Use stderr for logging err output in libaktualizr
export LOG_STDERR=1
SOTA_DIR="${SOTA_DIR-/var/sota}"

LOGLEVEL="${CREDS_LOGLEVEL-4}"

if [ "$1" = "get" ] ; then
if [ ! -f ${SOTA_DIR}/sota.toml ] ; then
echo "ERROR: Device does not appear to be registered under $SOTA_DIR"
exit 1
fi
server=$(grep -m1 '^[[:space:]]*server' ${SOTA_DIR}/sota.toml | cut -d\" -f2)
if [ -z $server ] ; then
server="https://ota-lite.foundries.io:8443"
fi
exec /usr/local/bin/aktualizr-get --loglevel $LOGLEVEL -u ${server}/hub-creds/
fi
Loading
Loading