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

integration-test: add test scenarios #32

Merged
merged 1 commit into from
Jul 26, 2016
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
59 changes: 59 additions & 0 deletions integration-test/test/basic.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env bats

load test_helper

@test "meta: docker is installed" {
run docker version
echo "$output">&2
[ "$status" -eq 0 ]
Copy link
Member

Choose a reason for hiding this comment

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

Should you check status before running echo? Won't that corrupt "run docker version", which I assume is the intent.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@boumenot nope $status contains the exitcode of the command that is last executed by prefix run ... thanks to bats. I type output here because if it fails on the [ "$status" -eq 0 ] status line, we'll see the output of the command and tell why it failed.

}

@test "meta: can build the test container image" {
run build_docker_image
echo "$output"
[ "$status" -eq 0 ]
}

@test "meta: can start the test container" {
run in_tmp_container fake-waagent
echo "$output"
[ "$output" = "Usage: /sbin/fake-waagent <handlerCommand>" ]
[ "$status" -eq 1 ]
}

@test "meta: can create vm private/public keys" {
run mk_certs
echo "$output"
[ "$status" -eq 0 ]

thumbprint="$output"
[ -f "$certs_dir/$thumbprint.prv" ]
[ -f "$certs_dir/$thumbprint.crt" ]
}

@test "meta: encrypt a protected settings" {
run mk_certs
echo "$output"
[ "$status" -eq 0 ]

tp="$output"
run encrypt_settings "$tp" "`seq 0 1000`"
echo "$output"
[ "$status" -eq 0 ]
[ -n "$output" ]
}

@test "meta: can create a .settings json with public/protected config" {
tp="$mk_certs"
run mk_settings_json '' '{"commandToExecute":"touch /a.txt"}' "$tp"
echo "$output"
[ "$status" -eq 0 ]
}

@test "meta: can create a temporary file" {
run save_tmp_file "foobar"
echo "$output"
[ "$status" -eq 0 ]
[ -f "$output" ]
[[ "$(cat "$output")" == "foobar" ]]
}
120 changes: 120 additions & 0 deletions integration-test/test/handler-commands.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/env bats

load test_helper

setup(){
build_docker_image
}

teardown(){
rm -rf "$certs_dir"
}

@test "handler command: install - creates the data dir" {
run in_container fake-waagent install
echo "$output"
[ "$status" -eq 0 ]
[[ "$output" = *event=installed* ]]

diff="$(container_diff)"
echo "$diff"
[[ "$diff" = *"A /var/lib/azure/custom-script"* ]]
}

@test "handler command: enable - can process empty settings, but fails" {
mk_container sh -c "fake-waagent install && fake-waagent enable"
push_settings '' ''

run start_container
echo "$output"
[ "$status" -eq 1 ]
[[ "$output" == *"invalid configuration: 'commandToExecute' is not specified"* ]]
Copy link
Member

Choose a reason for hiding this comment

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

How valuable is it to verify the error message in detail at this stage. I feel like you have numerous tests to catch this already, so why do it again. Is error code sufficient?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@boumenot maybe I should reduce to invalid configuration but error code is not sufficient as it might have failed due to far too many reasons.


# Validate .status file says enable failed
diff="$(container_diff)"; echo "$diff"
[[ "$diff" = *"A /var/lib/waagent/Extension/status/0.status"* ]]
status_file="$(container_read_file /var/lib/waagent/Extension/status/0.status)"
echo "$status_file"; [[ "$status_file" = *'Enable failed'* ]]
}

@test "handler command: enable - validates json schema" {
mk_container sh -c "fake-waagent install && fake-waagent enable"
push_settings '{"badElement":null, "commandToExecute":"date"}' ''

run start_container
echo "$output"
[ "$status" -eq 1 ]
[[ "$output" == *"json validation error: invalid public settings JSON: badElement"* ]]
}


@test "handler command: enable - captures stdout/stderr into file" {
mk_container sh -c "fake-waagent install && fake-waagent enable"
push_settings '
{
"commandToExecute": "echo HelloStdout>&1; echo HelloStderr>&2"
}' ''
run start_container
echo "$output"
[ "$status" -eq 0 ]

# Validate contents of stdout/stderr files
stdout="$(container_read_file /var/lib/azure/custom-script/download/0/stdout)"
echo "stdout=$stdout" && [[ "$stdout" = "HelloStdout" ]]
stderr="$(container_read_file /var/lib/azure/custom-script/download/0/stderr)"
echo "stderr=$stderr" && [[ "$stderr" = "HelloStderr" ]]
}

@test "handler command: enable - doesn't process the same sequence number again" {
Copy link
Member

Choose a reason for hiding this comment

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

I like this one.

mk_container sh -c \
"fake-waagent install && fake-waagent enable && fake-waagent enable"
push_settings '{"commandToExecute": "date"}' ''

run start_container
echo "$output"
[ "$status" -eq 0 ]
enable_count="$(echo "$output" | grep -c 'event=enabled')"
echo "Enable count=$enable_count"
[ "$enable_count" -eq 1 ]
[[ "$output" == *"this script configuration is already processed, will not run again"* ]] # not processed again
}

@test "handler command: enable - parses protected settings" {
mk_container sh -c "fake-waagent install && fake-waagent enable"
push_settings '' '{"commandToExecute":"touch /a.txt"}'
run start_container
echo "$output"
[ "$status" -eq 0 ]

diff="$(container_diff)"; echo "$diff"
[[ "$diff" == *"A /a.txt"* ]]
}

@test "handler command: enable - downloads files" {
mk_container sh -c "fake-waagent install && fake-waagent enable"
# download an external script and run it
push_settings '{
"fileUris": [
"https://gist.github.com/anonymous/8c83af2923ec8dd4a92309594a6c90d7/raw/f26c2cbf68e22d42f703b78f8a4562c5c8e43ba7/script.sh"
Copy link
Member

@boumenot boumenot Jul 26, 2016

Choose a reason for hiding this comment

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

How long do gists last? Can you just check this into the repo instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@boumenot until they shut down the gist service (or change its url schema), I guess we can do what you said.

],
"commandToExecute":"./script.sh"
}'
run start_container
echo "$output"
[ "$status" -eq 0 ]

diff="$(container_diff)"; echo "$diff"
[[ "$diff" == *"A /var/lib/azure/custom-script/download/0/script.sh"* ]] # file downloaded
[[ "$diff" == *"A /b.txt"* ]] # created by script.sh
}

@test "handler command: uninstall - deletes the data dir" {
run in_container sh -c \
"fake-waagent install && fake-waagent uninstall"
echo "$output"
[ "$status" -eq 0 ]

echo "$output"; [ "$status" -eq 0 ]
diff="$(container_diff)" && echo "$diff"
[[ "$diff" != */var/lib/azure/custom-script* ]]
}
126 changes: 126 additions & 0 deletions integration-test/test/test_helper.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Test helpers for BATS tests

IMAGE=custom-script
DOCKERFILE=test.Dockerfile
TEST_CONTAINER=test

certs_dir="$BATS_TEST_DIRNAME/certs"

build_docker_image() {
echo "Building test image..."
docker build -q -f $DOCKERFILE -t $IMAGE . 1>&2
}

in_tmp_container() {
docker run --rm $IMAGE "$@"
}

rm_container() {
docker rm -f $TEST_CONTAINER &>/dev/null && \
echo "Deleted test container." || true
}

mk_container() {
rm_container && echo "Creating test container with commands: $@">&2 && \
docker create --name=$TEST_CONTAINER $IMAGE "$@" 1>/dev/null
}

in_container() {
set -e
rm_container
mk_container "$@"
echo "Starting test container...">&2
start_container
}

start_container() {
docker start --attach $TEST_CONTAINER
}

container_diff() {
docker diff $TEST_CONTAINER
}

container_read_file() { # reads the file at container path $1
set -eo pipefail
Copy link
Member

Choose a reason for hiding this comment

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

Why is this scoped to this method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe setting -e globally has issues with bats sstephenson/bats#171

docker cp $TEST_CONTAINER:"$1" - | tar x --to-stdout
}

mk_certs() { # creates certs/{THUMBPRINT}.(crt|key) files under ./certs/ and prints THUMBPRINT
set -eo pipefail
mkdir -p "$certs_dir" && cd "$certs_dir" && rm -f "$certs_dir/*"
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -batch &>/dev/null
thumbprint=$(openssl x509 -in cert.pem -fingerprint -noout| sed 's/.*=//g' | sed 's/://g')
Copy link
Member

Choose a reason for hiding this comment

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

😁 The variable is called thumbprint, but the command is fingerprint. You've been here too long!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@boumenot I'm just preserving the terminology of waagent (authored by people stayed here too long as well)

mv cert.pem $thumbprint.crt && \
mv key.pem $thumbprint.prv
echo $thumbprint
}

push_certs() { # pushes certs/{$1}.(crt|key) files to container
set -e
docker cp "$certs_dir/$1.crt" $TEST_CONTAINER:/var/lib/waagent/
docker cp "$certs_dir/$1.prv" $TEST_CONTAINER:/var/lib/waagent/
echo "Pushed certs to container.">&2
}

encrypt_settings(){ # encrypts the message ($2) with the key with given cert thumbprint ($1)
set -eo pipefail
tp="$1"; msg="$2"
echo "$(openssl smime -inkey "$certs_dir/$tp.prv" -encrypt -outform DER "$certs_dir/$tp.crt" < <(echo "$msg") | base64 -w0)"
}

mk_settings_json() { # turns json public settings ($1) and ($2) into a json encrypted with "$3".(crt|prv)
set -e
pub="$1"
prot="$2"
cert_tp="$3"
if [ -z "$pub" ]; then pub="null"; fi
if [ -n "$prot" ]; then
prot="\"$(encrypt_settings "$cert_tp" "$prot")\""
else
cert_tp="null"
prot="null"
fi

cat <<-EOF
{
"runtimeSettings": [
{
"handlerSettings": {
"protectedSettingsCertThumbprint": "$cert_tp",
"publicSettings": $pub,
"protectedSettings": $prot
}
}
]
}
EOF
}

push_settings() { # creates and copies 0.settings file with given public settings ($1) and ($2) values.
set -e

if [ -n "$2" ]; then
cert_tp="$(mk_certs)"
push_certs "$cert_tp"
fi

cfg_file="$(save_tmp_file "$(mk_settings_json "$1" "$2" "$cert_tp") ")"
echo ".settings: $(cat "$cfg_file")" >&2
copy_config "$cfg_file"
echo ".settings file pushed to container." >&2
}

save_tmp_file(){ # saves $1 into a temporary file and returns its path
fp="$(mktemp)"
touch "$fp"
cat <<< "$1" > "$fp"
echo "$fp"
}

copy_config() { # places specified settings file ($1) into container as 0.settings
set -e
echo "Copying $1 to container as 0.settings." >&2
docker cp "$1" "$TEST_CONTAINER:/var/lib/waagent/Extension/config/0.settings"
echo "Copied settings into container.">&2
}