Skip to content
Merged
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
8 changes: 8 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,11 @@ jobs:
- ../hack/test-templates/test-misc.yaml # TODO: merge net-user-v2 into test-misc
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# BATS tests don't expect lima version warnings like:
# msg="treating lima version \"ea336ae\" from \"/Users/runner/.lima-bats/dummy/lima-version\" as very latest release"
fetch-depth: 0
submodules: true
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version: 1.25.x
Expand All @@ -319,6 +324,9 @@ jobs:
sudo modprobe kvm
# `sudo usermod -aG kvm $(whoami)` does not take an effect on GHA
sudo chown $(whoami) /dev/kvm
- name: "Run BATS integration tests"
run: make bats
if: matrix.template == '../hack/test-templates/test-misc.yaml'
- name: Install ansible-playbook
run: |
sudo apt-get install -y --no-install-recommends ansible
Expand Down
16 changes: 16 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[submodule "hack/bats/lib/bats-core"]
path = hack/bats/lib/bats-core
url = https://github.com/lima-vm/bats-core.git
branch = master
[submodule "hack/bats/lib/bats-file"]
path = hack/bats/lib/bats-file
url = https://github.com/lima-vm/bats-file.git
branch = master
[submodule "hack/bats/lib/bats-assert"]
path = hack/bats/lib/bats-assert
url = https://github.com/lima-vm/bats-assert.git
branch = master
[submodule "hack/bats/lib/bats-support"]
path = hack/bats/lib/bats-support
url = https://github.com/lima-vm/bats-support.git
branch = master
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,10 @@ check-generated:
((git diff $$(find . -name '*.pb.desc') | cat) && \
(echo "Please run 'make generate' when making changes to proto files and check-in the generated file changes" && false))

.PHONY: bats
bats: native
PATH=$$PWD/_output/bin:$$PATH ./hack/bats/lib/bats-core/bin/bats --timing ./hack/bats/tests

.PHONY: lint
lint: check-generated
golangci-lint run ./...
Expand Down
48 changes: 48 additions & 0 deletions hack/bats/helpers/load.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
set -o errexit -o nounset -o pipefail

# Don't run the tests in ~/.lima because they may destroy _config, _templates etc.
export LIMA_HOME=${LIMA_BATS_LIMA_HOME:-$HOME/.lima-bats}

absolute_path() {
(
cd "$1"
pwd
)
}

PATH_BATS_HELPERS=$(absolute_path "$(dirname "${BASH_SOURCE[0]}")")
PATH_BATS_ROOT=$(absolute_path "$PATH_BATS_HELPERS/..")

source "$PATH_BATS_ROOT/lib/bats-support/load.bash"
source "$PATH_BATS_ROOT/lib/bats-assert/load.bash"
source "$PATH_BATS_ROOT/lib/bats-file/load.bash"

bats_require_minimum_version 1.5.0

# If called from foo() this function will call local_foo() if it exist.
call_local_function() {
local func
func="local_${FUNCNAME[1]}"
if [ "$(type -t "$func")" = "function" ]; then
"$func"
fi
}

setup_file() {
if [[ ${CI:-} == true ]]; then
# Without a terminal the output is using TAP formatting, which does not include the filename
local TEST_FILENAME=${BATS_TEST_FILENAME#"$PATH_BATS_ROOT/tests/"}
TEST_FILENAME=${TEST_FILENAME%.bats}
echo "# ===== ${TEST_FILENAME} =====" >&3
fi
call_local_function
}
teardown_file() {
call_local_function
}
setup() {
call_local_function
}
teardown() {
call_local_function
}
1 change: 1 addition & 0 deletions hack/bats/lib/bats-assert
Submodule bats-assert added at 3be0fb
1 change: 1 addition & 0 deletions hack/bats/lib/bats-core
Submodule bats-core added at 397c4a
1 change: 1 addition & 0 deletions hack/bats/lib/bats-file
Submodule bats-file added at 0f24d0
1 change: 1 addition & 0 deletions hack/bats/lib/bats-support
Submodule bats-support added at 0954ab
153 changes: 153 additions & 0 deletions hack/bats/tests/preserve-env.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
load "../helpers/load"

NAME=bats

local_setup_file() {
unset LIMA_SHELLENV_ALLOW
unset LIMA_SHELLENV_BLOCK

if [[ -n "${LIMA_BATS_REUSE_INSTANCE:-}" ]]; then
run limactl list --format '{{.Status}}' "$NAME"
[[ $status == 0 ]] && [[ $output == "Running" ]] && return
fi
limactl unprotect "$NAME" || :
limactl delete --force "$NAME" || :
# Make sure that the host agent doesn't inherit file handles 3 or 4.
# Otherwise bats will not finish until the host agent exits.
limactl start --yes --name "$NAME" template://default 3>&- 4>&-
}

local_teardown_file() {
if [[ -z "${LIMA_BATS_REUSE_INSTANCE:-}" ]]; then
limactl delete --force "$NAME"
fi
}

local_setup() {
# make sure changes from previous tests are removed
limactl shell "$NAME" sh -c '[ ! -f ~/.bash_profile ] || sed -i -E "/^export (FOO|BAR|SSH_)/d" ~/.bash_profile'
}

@test 'there are no FOO*, BAR*, or SSH_FOO* variables defined in the VM' {
# just to confirm because the other tests depend on these being unused
run -0 limactl shell "$NAME" printenv
refute_line --regexp '^FOO'
refute_line --regexp '^BAR'
refute_line --regexp '^SSH_FOO'
}

@test 'environment is not preserved by default' {
export FOO=foo
run -0 limactl shell "$NAME" printenv
refute_line --regexp '^FOO='
}

@test 'environment is preserved with --preserve-env' {
export FOO=foo
run -0 limactl shell --preserve-env "$NAME" printenv
assert_line FOO=foo
}

@test 'profile settings inside the VM take precedence over preserved variables' {
limactl shell "$NAME" sh -c 'echo "export FOO=bar" >>~/.bash_profile'
export FOO=foo
run -0 limactl shell --preserve-env "$NAME" printenv
assert_line FOO=bar
}

@test 'builtin block list is used when LIMA_SHELLENV_BLOCK is not set' {
# default block list includes SSH_*
export SSH_FOO=ssh_foo
run -0 limactl shell --preserve-env "$NAME" printenv
refute_line --regexp '^SSH_FOO='
}

@test 'custom block list replaces builtin block list' {
export LIMA_SHELLENV_BLOCK=FOO
export FOO=foo
export SSH_FOO=foo
run -0 limactl shell --preserve-env "$NAME" printenv
refute_line --regexp '^FOO='
assert_line SSH_FOO=foo
}

@test 'custom block list starting with + appends to builtin block list' {
export LIMA_SHELLENV_BLOCK=+FOO
export FOO=foo
export SSH_FOO=foo
run -0 limactl shell --preserve-env "$NAME" printenv
refute_line --regexp '^FOO='
refute_line --regexp '^SSH_FOO='
}

@test 'block list entries can use * wildcard at the end' {
export LIMA_SHELLENV_BLOCK="FOO*"
export FOO=foo
export FOOBAR=foobar
export BAR=bar
run -0 limactl shell --preserve-env "$NAME" printenv
refute_line --regexp '^FOO'
assert_line BAR=bar
}

@test 'wildcard does only work at the end of the pattern' {
export LIMA_SHELLENV_BLOCK="*FOO"
export FOO=foo
export BARFOO=barfoo
run -0 limactl shell --preserve-env "$NAME" printenv
assert_line FOO=foo
assert_line BARFOO=barfoo
}

@test 'block list can use a , separated list with whitespace ignored' {
export LIMA_SHELLENV_BLOCK="FOO*, , BAR"
export FOO=foo
export FOOBAR=foobar
export BAR=bar
export BARBAZ=barbaz
run -0 limactl shell --preserve-env "$NAME" printenv
refute_line --regexp '^FOO'
refute_line --regexp '^BAR='
assert_line BARBAZ=barbaz
}

@test 'allow list overrides block list but blocks everything else' {
export LIMA_SHELLENV_ALLOW=SSH_FOO
export SSH_FOO=ssh_foo
export SSH_BAR=ssh_bar
export BAR=bar
run -0 limactl shell --preserve-env "$NAME" printenv
assert_line SSH_FOO=ssh_foo
refute_line --regexp '^SSH_BAR='
refute_line --regexp '^BAR='
}

@test 'allow list can use a , separated list with whitespace ignored' {
export LIMA_SHELLENV_ALLOW="FOO*, , BAR"
export FOO=foo
export FOOBAR=foobar
export BAR=bar
export BARBAZ=barbaz
run -0 limactl shell --preserve-env "$NAME" printenv
assert_line FOO=foo
assert_line FOOBAR=foobar
assert_line BAR=bar
refute_line --regexp '^BARBAZ='
}

@test 'setting both allow list and block list generates a warning' {
export LIMA_SHELLENV_ALLOW=FOO
export LIMA_SHELLENV_BLOCK=BAR
export FOO=foo
run -0 --separate-stderr limactl shell --preserve-env "$NAME" printenv FOO
assert_output foo
assert_stderr --regexp 'level=warning msg="Both LIMA_SHELLENV_BLOCK and LIMA_SHELLENV_ALLOW are set'
}

@test 'limactl info includes the default block list' {
run -0 limactl info
run -0 limactl yq '.shellEnvBlock[]' <<<"$output"
assert_line PATH
assert_line "SSH_*"
assert_line USER
}
69 changes: 69 additions & 0 deletions hack/bats/tests/protect.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
load "../helpers/load"

NAME=dummy
CLONE=clone
NOTEXIST=notexist

local_setup_file() {
for INSTANCE in "$NAME" "$CLONE" "$NOTEXIST"; do
limactl unprotect "$INSTANCE" || :
limactl delete --force "$INSTANCE" || :
done
}

@test 'create dummy instance' {
# needs an image that clonefile() can process; /dev/null doesn't work
limactl create --name "$NAME" - <<<"{images: [location: /etc/profile], disk: 1M}"
}

@test 'protecting a non-existing instance fails' {
run -1 limactl protect "${NOTEXIST}"
assert_output --partial 'failed to inspect instance'
}

@test 'protecting the dummy instance succeeds' {
run -0 limactl protect "$NAME"
assert_output --regexp "Protected \\\\\"$NAME\\\\\""
assert_file_exists "$LIMA_HOME/$NAME/protected"
}

@test 'protecting it again shows a warning, but succeeds' {
run -0 limactl protect "$NAME"
assert_output --partial 'already protected. Skipping'
assert_file_exists "$LIMA_HOME/$NAME/protected"
}

@test 'cloning a protected instance creates an unprotected clone' {
run -0 limactl clone --yes "$NAME" "$CLONE"
# TODO there is currently no output from the clone command, which feels wrong
refute_output
assert_file_not_exists "$LIMA_HOME/$CLONE/protected"
}

@test 'deleting the unprotected clone instance succeeds' {
run -0 limactl delete --force "$CLONE"
assert_output --regexp "Deleted \\\\\"$CLONE\\\\\""
}

@test 'deleting protected dummy instance fails' {
run -1 limactl delete --force "$NAME"
assert_output --partial 'instance is protected'
assert_file_exists "$LIMA_HOME/$NAME/protected"
}

@test 'unprotecting the dummy instance succeeds' {
run -0 limactl unprotect "$NAME"
assert_output --regexp "Unprotected \\\\\"$NAME\\\\\""
assert_file_not_exists "$LIMA_HOME/$NAME/protected"
}

@test 'unprotecting it again shows a warning, but succeeds' {
run -0 limactl unprotect "$NAME"
assert_output --partial "isn't protected. Skipping"
assert_file_not_exists "$LIMA_HOME/$NAME/protected"
}

@test 'deleting unprotected dummy instance succeeds' {
run -0 limactl delete --force "$NAME"
assert_output --regexp "Deleted \\\\\"$NAME\\\\\""
}
Loading