Skip to content

Commit ae0ff06

Browse files
Allow integration tests to run locally
This change adds the ability to run integration tests locally. You will still need a number of environment variables set, including a github PAT. Details on how to use this will come in a subsequent commit. Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
1 parent cffb4f2 commit ae0ff06

File tree

7 files changed

+96
-40
lines changed

7 files changed

+96
-40
lines changed

Makefile

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
SHELL := bash
1+
SHELL := /bin/bash
2+
export SHELLOPTS:=$(if $(SHELLOPTS),$(SHELLOPTS):)pipefail:errexit
23

4+
.ONESHELL:
5+
6+
GEN_PASSWORD=$(shell (/bin/bash -c 'tr -dc "a-zA-Z0-9" </dev/urandom | head -c 32 ; echo '';'))
37
IMAGE_TAG = garm-build
48

59
USER_ID=$(shell ((docker --version | grep -q podman) && echo "0" || id -u))
@@ -9,6 +13,12 @@ GOPATH ?= $(shell go env GOPATH)
913
VERSION ?= $(shell git describe --tags --match='v[0-9]*' --dirty --always)
1014
GARM_REF ?= $(shell git rev-parse --abbrev-ref HEAD)
1115
GO ?= go
16+
export GARM_PASSWORD ?= ${GEN_PASSWORD}
17+
export REPO_WEBHOOK_SECRET = ${GEN_PASSWORD}
18+
export ORG_WEBHOOK_SECRET = ${GEN_PASSWORD}
19+
export CREDENTIALS_NAME ?= test-garm-creds
20+
export WORKFLOW_FILE_NAME ?= test.yml
21+
export GARM_ADMIN_USERNAME ?= admin
1222

1323
.PHONY: help
1424
help: ## Display this help.
@@ -63,6 +73,18 @@ verify-vendor: ## verify if all the go.mod/go.sum files are up-to-date
6373

6474
verify: verify-vendor lint fmtcheck ## Run all verify-* targets
6575

76+
integration: build ## Run integration tests
77+
function cleanup {
78+
if [ -e "$$GITHUB_ENV" ];then
79+
source $$GITHUB_ENV
80+
fi
81+
./test/integration/scripts/taredown_garm.sh
82+
$(GO) run ./test/integration/gh_cleanup/main.go
83+
}
84+
trap cleanup EXIT
85+
@./test/integration/scripts/setup-garm.sh
86+
@$(GO) run ./test/integration/main.go
87+
6688
##@ Development
6789

6890
go-test: ## Run tests

test/integration/config/config.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[default]
2-
callback_url = "${GARM_BASE_URL}/api/v1/callbacks/status"
2+
callback_url = "${GARM_BASE_URL}/api/v1/callbacks"
33
metadata_url = "${GARM_BASE_URL}/api/v1/metadata"
44
webhook_url = "${GARM_BASE_URL}/webhooks"
55
enable_webhook_management = true
@@ -14,14 +14,14 @@ time_to_live = "8760h"
1414

1515
[apiserver]
1616
bind = "0.0.0.0"
17-
port = 9997
17+
port = ${GARM_PORT}
1818
use_tls = false
1919

2020
[database]
2121
backend = "sqlite3"
2222
passphrase = "${DB_PASSPHRASE}"
2323
[database.sqlite3]
24-
db_file = "/etc/garm/garm.db"
24+
db_file = "${GARM_CONFIG_DIR}/garm.db"
2525

2626
[[provider]]
2727
name = "lxd_local"
@@ -36,8 +36,8 @@ name = "test_external"
3636
description = "external test provider"
3737
provider_type = "external"
3838
[provider.external]
39-
config_file = "/etc/garm/test-provider/config"
40-
provider_executable = "/etc/garm/test-provider/garm-external-provider"
39+
config_file = "${GARM_CONFIG_DIR}/test-provider/config"
40+
provider_executable = "${GARM_CONFIG_DIR}/test-provider/garm-external-provider"
4141

4242
[[github]]
4343
name = "${CREDENTIALS_NAME}"

test/integration/e2e/e2e.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ func GetControllerInfo() *params.ControllerInfo {
5151
}
5252

5353
func GracefulCleanup() {
54+
slog.Info("Graceful cleanup")
5455
// disable all the pools
5556
pools, err := listPools(cli, authToken)
5657
if err != nil {
@@ -62,7 +63,7 @@ func GracefulCleanup() {
6263
if _, err := updatePool(cli, authToken, pool.ID, poolParams); err != nil {
6364
panic(err)
6465
}
65-
slog.Info("Pool disabled", "pool_id", pool.ID)
66+
slog.Info("Pool disabled", "pool_id", pool.ID, "stage", "graceful_cleanup")
6667
}
6768

6869
// delete all the instances
@@ -75,7 +76,7 @@ func GracefulCleanup() {
7576
if err := deleteInstance(cli, authToken, instance.Name, false); err != nil {
7677
panic(err)
7778
}
78-
slog.Info("Instance deletion initiated", "instance", instance.Name)
79+
slog.Info("Instance deletion initiated", "instance", instance.Name, "stage", "graceful_cleanup")
7980
}
8081
}
8182

@@ -91,7 +92,7 @@ func GracefulCleanup() {
9192
if err := deletePool(cli, authToken, pool.ID); err != nil {
9293
panic(err)
9394
}
94-
slog.Info("Pool deleted", "pool_id", pool.ID)
95+
slog.Info("Pool deleted", "pool_id", pool.ID, "stage", "graceful_cleanup")
9596
}
9697

9798
// delete all the repositories
@@ -103,7 +104,7 @@ func GracefulCleanup() {
103104
if err := deleteRepo(cli, authToken, repo.ID); err != nil {
104105
panic(err)
105106
}
106-
slog.Info("Repo deleted", "repo_id", repo.ID)
107+
slog.Info("Repo deleted", "repo_id", repo.ID, "stage", "graceful_cleanup")
107108
}
108109

109110
// delete all the organizations
@@ -115,7 +116,7 @@ func GracefulCleanup() {
115116
if err := deleteOrg(cli, authToken, org.ID); err != nil {
116117
panic(err)
117118
}
118-
slog.Info("Org deleted", "org_id", org.ID)
119+
slog.Info("Org deleted", "org_id", org.ID, "stage", "graceful_cleanup")
119120
}
120121
}
121122

@@ -125,12 +126,12 @@ func appendCtrlInfoToGitHubEnv(controllerInfo *params.ControllerInfo) error {
125126
slog.Info("GITHUB_ENV not set, skipping appending controller info")
126127
return nil
127128
}
128-
file, err := os.OpenFile(envFile, os.O_WRONLY|os.O_APPEND, os.ModeAppend)
129+
file, err := os.OpenFile(envFile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o644)
129130
if err != nil {
130131
return err
131132
}
132133
defer file.Close()
133-
if _, err := file.WriteString(fmt.Sprintf("GARM_CONTROLLER_ID=%s\n", controllerInfo.ControllerID)); err != nil {
134+
if _, err := file.WriteString(fmt.Sprintf("export GARM_CONTROLLER_ID=%s\n", controllerInfo.ControllerID)); err != nil {
134135
return err
135136
}
136137
return nil

test/integration/e2e/instances.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ func waitInstanceStatus(name string, status commonParams.InstanceStatus, runnerS
3434
}
3535

3636
func DeleteInstance(name string, forceRemove bool) {
37+
slog.Info("Delete instance", "instance_name", name, "force_remove", forceRemove)
3738
if err := deleteInstance(cli, authToken, name, forceRemove); err != nil {
39+
slog.Error("Failed to delete instance", "instance_name", name, "error", err)
3840
panic(err)
3941
}
4042
slog.Info("Instance deletion initiated", "instance_name", name)
@@ -103,7 +105,8 @@ func WaitPoolInstances(poolID string, status commonParams.InstanceStatus, runner
103105
"runner_status", runnerStatus,
104106
"desired_instance_count", instancesCount,
105107
"pool_instance_count", len(poolInstances))
106-
if int(pool.MinIdleRunners) == len(poolInstances) {
108+
// With the addition of JIT runners, we need to make sure that instancesCount is equal to MinIdleRunners.
109+
if int(pool.MinIdleRunners) == len(poolInstances) && int(pool.MinIdleRunners) == instancesCount {
107110
return nil
108111
}
109112
time.Sleep(5 * time.Second)

test/integration/e2e/repositories.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func InstallRepoWebhook(id string) *params.HookInfo {
4242
}
4343
_, err := installRepoWebhook(cli, authToken, id, webhookParams)
4444
if err != nil {
45+
slog.Error("Failed to install repo webhook", "error", err)
4546
panic(err)
4647
}
4748
webhookInfo, err := getRepoWebhook(cli, authToken, id)
@@ -59,9 +60,10 @@ func UninstallRepoWebhook(id string) {
5960
}
6061

6162
func CreateRepoPool(repoID string, poolParams params.CreatePoolParams) *params.Pool {
62-
slog.Info("Create repo pool", "repo_id", repoID)
63+
slog.Info("Create repo pool", "repo_id", repoID, "pool_params", poolParams)
6364
pool, err := createRepoPool(cli, authToken, repoID, poolParams)
6465
if err != nil {
66+
slog.Error("Failed to create repo pool", "error", err)
6567
panic(err)
6668
}
6769
return pool

test/integration/main.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,13 @@ import (
1111
"github.com/cloudbase/garm/test/integration/e2e"
1212
)
1313

14-
const (
15-
adminUsername = "admin"
14+
var (
15+
adminPassword = os.Getenv("GARM_PASSWORD")
16+
adminUsername = os.Getenv("GARM_ADMIN_USERNAME")
1617
adminFullName = "GARM Admin"
1718
adminEmail = "admin@example.com"
18-
)
1919

20-
var (
2120
baseURL = os.Getenv("GARM_BASE_URL")
22-
adminPassword = os.Getenv("GARM_PASSWORD")
2321
credentialsName = os.Getenv("CREDENTIALS_NAME")
2422

2523
repoName = os.Getenv("REPO_NAME")
@@ -116,11 +114,13 @@ func main() {
116114
/////////////////////////////
117115
// Test external provider ///
118116
/////////////////////////////
117+
slog.Info("Testing external provider")
119118
repoPool2 := e2e.CreateRepoPool(repo.ID, repoPoolParams2)
120-
_ = e2e.UpdateRepoPool(repo.ID, repoPool2.ID, repoPoolParams2.MaxRunners, 1)
119+
newParams := e2e.UpdateRepoPool(repo.ID, repoPool2.ID, repoPoolParams2.MaxRunners, 1)
120+
slog.Info("Updated repo pool", "new_params", newParams)
121121
err := e2e.WaitPoolInstances(repoPool2.ID, commonParams.InstanceRunning, params.RunnerPending, 1*time.Minute)
122122
if err != nil {
123-
slog.With(slog.Any("error", err)).Error("Failed to wait for instance to be running")
123+
slog.With(slog.Any("error", err)).Error("Failed to wait for instance to be running", "pool_id", repoPool2.ID, "provider_name", repoPoolParams2.ProviderName)
124124
}
125125
repoPool2 = e2e.GetRepoPool(repo.ID, repoPool2.ID)
126126
e2e.DisableRepoPool(repo.ID, repoPool2.ID)

test/integration/scripts/setup-garm.sh

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,14 @@ BINARIES_DIR="$PWD/bin"
66
CONTRIB_DIR="$PWD/contrib"
77
CONFIG_DIR="$PWD/test/integration/config"
88
CONFIG_DIR_PROV="$PWD/test/integration/provider"
9-
PROVIDER_BIN_DIR="/opt/garm/providers.d/lxd"
9+
GARM_CONFIG_DIR=${GARM_CONFIG_DIR:-"/etc/garm"}
10+
PROVIDER_BIN_DIR="$GARM_CONFIG_DIR/providers.d/lxd"
11+
IS_GH_WORKFLOW=${IS_GH_WORKFLOW:-"true"}
12+
export LXD_PROVIDER_LOCATION=${LXD_PROVIDER_LOCATION:-""}
13+
export RUN_USER=${RUN_USER:-"garm"}
14+
export GARM_PORT=${GARM_PORT:-"9997"}
15+
export GARM_SERVICE_NAME=${GARM_SERVICE_NAME:-"garm"}
16+
export GARM_CONFIG_FILE=${GARM_CONFIG_FILE:-"${GARM_CONFIG_DIR}/config.toml"}
1017

1118
if [[ ! -f $BINARIES_DIR/garm ]] || [[ ! -f $BINARIES_DIR/garm-cli ]]; then
1219
echo "ERROR: Please build GARM binaries first"
@@ -41,33 +48,54 @@ function wait_open_port() {
4148
export JWT_AUTH_SECRET="$(generate_secret)"
4249
export DB_PASSPHRASE="$(generate_secret)"
4350

44-
# Group "adm" is the LXD daemon group as set by the "canonical/setup-lxd" GitHub action.
45-
sudo useradd --shell /usr/bin/false --system --groups adm --no-create-home garm
46-
sudo mkdir -p /etc/garm
51+
if [ $IS_GH_WORKFLOW == "true" ]; then
52+
# Group "adm" is the LXD daemon group as set by the "canonical/setup-lxd" GitHub action.
53+
sudo useradd --shell /usr/bin/false --system --groups adm --no-create-home garm
54+
fi
55+
56+
sudo mkdir -p ${GARM_CONFIG_DIR}
4757
sudo mkdir -p $PROVIDER_BIN_DIR
58+
sudo chown -R $RUN_USER:$RUN_USER ${PROVIDER_BIN_DIR}
59+
sudo chown -R $RUN_USER:$RUN_USER ${GARM_CONFIG_DIR}
4860

4961
export LXD_PROVIDER_EXECUTABLE="$PROVIDER_BIN_DIR/garm-provider-lxd"
50-
export LXD_PROVIDER_CONFIG="/etc/garm/garm-provider-lxd.toml"
62+
export LXD_PROVIDER_CONFIG="${GARM_CONFIG_DIR}/garm-provider-lxd.toml"
5163
sudo cp $CONFIG_DIR/garm-provider-lxd.toml $LXD_PROVIDER_CONFIG
5264

53-
git clone https://github.com/cloudbase/garm-provider-lxd ~/garm-provider-lxd
54-
pushd ~/garm-provider-lxd
55-
go build -o $LXD_PROVIDER_EXECUTABLE
56-
popd
65+
function clone_and_build_lxd_provider() {
66+
git clone https://github.com/cloudbase/garm-provider-lxd ~/garm-provider-lxd
67+
pushd ~/garm-provider-lxd
68+
go build -o $LXD_PROVIDER_EXECUTABLE
69+
popd
70+
}
5771

58-
cat $CONFIG_DIR/config.toml | envsubst | sudo tee /etc/garm/config.toml
59-
sudo chown -R garm:garm /etc/garm
72+
if [ $IS_GH_WORKFLOW == "true" ]; then
73+
clone_and_build_lxd_provider
74+
else
75+
if [ -z "$LXD_PROVIDER_LOCATION" ];then
76+
clone_and_build_lxd_provider
77+
else
78+
cp $LXD_PROVIDER_LOCATION $LXD_PROVIDER_EXECUTABLE
79+
fi
6080

61-
sudo mkdir /etc/garm/test-provider
81+
fi
82+
83+
cat $CONFIG_DIR/config.toml | envsubst | sudo tee ${GARM_CONFIG_DIR}/config.toml > /dev/null
84+
sudo chown -R $RUN_USER:$RUN_USER ${GARM_CONFIG_DIR}
85+
86+
sudo mkdir -p ${GARM_CONFIG_DIR}/test-provider
6287
sudo touch $CONFIG_DIR_PROV/config
63-
sudo cp $CONFIG_DIR_PROV/* /etc/garm/test-provider
88+
sudo cp $CONFIG_DIR_PROV/* ${GARM_CONFIG_DIR}/test-provider
6489

6590
sudo mv $BINARIES_DIR/* /usr/local/bin/
66-
sudo cp $CONTRIB_DIR/garm.service /etc/systemd/system/garm.service
67-
68-
sudo systemctl daemon-reload
69-
sudo systemctl start garm
91+
mkdir -p $HOME/.local/share/systemd/user/
92+
cat $CONFIG_DIR/garm.service| envsubst | tee $HOME/.local/share/systemd/user/${GARM_SERVICE_NAME}.service > /dev/null
93+
sudo chown -R $RUN_USER:$RUN_USER ${GARM_CONFIG_DIR}
7094

71-
wait_open_port 127.0.0.1 9997
95+
systemctl --user daemon-reload
96+
systemctl --user restart ${GARM_SERVICE_NAME}
97+
wait_open_port 127.0.0.1 ${GARM_PORT}
7298

7399
echo "GARM is up and running"
100+
echo "GARM config file is $GARM_CONFIG_FILE"
101+
echo "GARM service name is $GARM_SERVICE_NAME"

0 commit comments

Comments
 (0)