Skip to content

Commit

Permalink
kcov: Convert to public kcov-ubuntu module
Browse files Browse the repository at this point in the history
  • Loading branch information
mbland committed Nov 6, 2016
1 parent 5592dee commit b9333a6
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 55 deletions.
50 changes: 34 additions & 16 deletions scripts/lib/kcov → lib/kcov-ubuntu
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
# Exports:
#
# run_kcov
# Downloads and compiles kcov if necessary, then runs tests under kcov
#
# This will eventually be extracted into a plugin library of its own.
# This may eventually be extracted into a plugin library of its own, which is
# why its exported functions don't contain a `@go.` prefix.

declare -r KCOV_DEV_PACKAGES=(
declare -r __KCOV_DEV_PACKAGES=(
'binutils-dev'
'cmake'
'libcurl4-openssl-dev'
Expand All @@ -17,8 +19,26 @@ declare -r KCOV_DEV_PACKAGES=(
'libiberty-dev'
'zlib1g-dev'
)
declare -r KCOV_URL='https://github.com/SimonKagstrom/kcov'
declare -r __KCOV_URL='https://github.com/SimonKagstrom/kcov'

# Downloads and compiles kcov if necessary, then runs tests under kcov
#
# The reason this function exists is because the kcov distribution available via
# apt-get on Travis CI is out-of-date and doesn't support the features needed to
# collect Bash coverage and send it to Coveralls.
#
# First this function will check for apt-get and whether the coverage output dir
# ($2) is already present. Then it will clone the kcov repository and build it
# from source if the binary isn't already present. Once the binary is in place,
# it will run kcov using the supplied patterns and arguments.
#
# Arguments:
# $1: The directory into which to clone and build kcov
# $2: The coverage output directory; it must not already exist
# $3: The kcov --include-pattern argument value
# $4: The kcov --exclude-pattern argument value
# $5: The Coveralls URL for the project (appears in successful output)
# ...: Arguments to run the test executable
run_kcov() {
local kcov_dir="$1"
local coverage_dir="$2"
Expand All @@ -36,7 +56,7 @@ run_kcov() {
@go.printf '%s %s\n' "The $coverage_dir directory already exists." \
'Please move or remove this directory first.' >&2
return 1
elif ! ( [[ -f "$kcov_path" ]] || clone_and_build_kcov "$kcov_dir" ); then
elif ! ( [[ -f "$kcov_path" ]] || _clone_and_build_kcov "$kcov_dir" ); then
return 1
fi

Expand All @@ -49,17 +69,15 @@ run_kcov() {
kcov_flags+=("--coveralls-id=$TRAVIS_JOB_ID")
fi

local kcov_argv=(
"$kcov_path" "${kcov_flags[@]}" "$coverage_dir" "$_GO_SCRIPT" 'test' "$@")
local kcov_argv=("$kcov_path" "${kcov_flags[@]}" "$coverage_dir" "$@")
mkdir "$coverage_dir"
printf 'Starting coverage run:\n %s\n' "${kcov_argv[*]}"

# We redirect stderr because all the kcov coverage info will get dumped to the
# Travis log otherwise.
if "${kcov_argv[@]}" 2>/dev/null; then
if [[ "$send_to_coveralls" == 'false' ]]; then
@go.printf 'Coverage results located in:\n %s\n' \
"$_GO_ROOTDIR/$coverage_dir"
@go.printf 'Coverage results located in:\n %s\n' "$PWD/$coverage_dir"
else
@go.printf 'Coverage results sent to:\n %s\n' "$coveralls_url"
fi
Expand All @@ -69,26 +87,26 @@ run_kcov() {
fi
}

clone_and_build_kcov() {
_clone_and_build_kcov() {
# The only way to be sure we've got a compatible version of kcov is to clone
# and compile it ourselves.
local kcov_dir="$1"

if [[ ! -d "$kcov_dir" ]]; then
@go.printf 'Cloning kcov repository from %s...\n' "$KCOV_URL"
@go.printf 'Cloning kcov repository from %s...\n' "$__KCOV_URL"

if ! git clone "$KCOV_URL" "$kcov_dir"; then
@go.printf "Failed to clone $KCOV_URL into $kcov_dir." >&2
if ! git clone "$__KCOV_URL" "$kcov_dir"; then
@go.printf "Failed to clone $__KCOV_URL into $kcov_dir." >&2
return 1
fi
fi

# Travis uses the "addons > apt > packages" property from .travis.yml to
# install packages before the test suite is run, so no need to check here.
if [[ -z "$TRAVIS_OS_NAME" ]] && ! check_kcov_dev_packages_installed; then
if [[ -z "$TRAVIS_OS_NAME" ]] && ! _check_kcov_dev_packages_installed; then
@go.printf "Installing dev packages to build kcov...\n"

if ! sudo apt-get install -y "${KCOV_DEV_PACKAGES[@]}"; then
if ! sudo apt-get install -y "${__KCOV_DEV_PACKAGES[@]}"; then
@go.printf "Failed to install dev packages needed to build kcov." >&2
return 1
fi
Expand All @@ -103,9 +121,9 @@ clone_and_build_kcov() {
return 1
}

check_kcov_dev_packages_installed() {
_check_kcov_dev_packages_installed() {
local packages
packages="$(dpkg-query -W -f='${Package} ${Status}\n' \
"${KCOV_DEV_PACKAGES[@]}")"
"${__KCOV_DEV_PACKAGES[@]}")"
[[ "$?" -eq '0' && ! "$packages" =~ deinstall ]]
}
4 changes: 2 additions & 2 deletions scripts/test
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ _test_tab_completion() {
}

_test_coverage() {
. "$_GO_USE_MODULES" 'kcov'
. "$_GO_USE_MODULES" 'kcov-ubuntu'
run_kcov "tests/kcov" "tests/coverage" \
'go,go-core.bash,lib/,libexec/,scripts/' \
'/tmp,tests/bats/' \
'https://coveralls.io/github/mbland/go-script-bash' \
"$@"
"$_GO_SCRIPT" 'test' "$@"
}

_test() {
Expand Down
76 changes: 40 additions & 36 deletions tests/kcov.bats
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,10 @@ teardown() {
}

write_kcov_go_script() {
local go_script=(
". \"$_GO_ROOTDIR/scripts/lib/kcov\""
"PATH=\"$FAKE_BIN_DIR:\$PATH\""
"$@")
create_test_go_script "${go_script[@]}"
create_test_go_script \
". \"\$_GO_USE_MODULES\" 'kcov-ubuntu'" \
"PATH=\"$FAKE_BIN_DIR:\$PATH\"" \
"$@"
}

write_kcov_dummy() {
Expand All @@ -62,51 +61,51 @@ write_kcov_dummy() {
}

@test "$SUITE: check dev packages installed" {
write_kcov_go_script check_kcov_dev_packages_installed
write_kcov_go_script '_check_kcov_dev_packages_installed'
run "$TEST_GO_SCRIPT"
assert_success ''

run cat "$FAKE_BIN_DIR/dpkg-query.out"
. 'scripts/lib/kcov'
assert_success "-W -f=\${Package} \${Status}\\n ${KCOV_DEV_PACKAGES[*]}"
. 'lib/kcov-ubuntu'
assert_success "-W -f=\${Package} \${Status}\\n ${__KCOV_DEV_PACKAGES[*]}"
}

@test "$SUITE: check dev packages fails on dpkg-query error" {
write_kcov_go_script check_kcov_dev_packages_installed
write_kcov_go_script '_check_kcov_dev_packages_installed'
echo 'exit 1' >>"$FAKE_BIN_DIR/dpkg-query"
run "$TEST_GO_SCRIPT"
assert_failure ''
}

@test "$SUITE: check dev packages fails if a package deinstalled" {
write_kcov_go_script check_kcov_dev_packages_installed
write_kcov_go_script '_check_kcov_dev_packages_installed'
echo 'echo deinstall' >>"$FAKE_BIN_DIR/dpkg-query"
run "$TEST_GO_SCRIPT"
assert_failure ''
}

@test "$SUITE: clone and build" {
local go_script=(
'check_kcov_dev_packages_installed() { return 1; }'
'clone_and_build_kcov tests/kcov')
'_check_kcov_dev_packages_installed() { return 1; }'
'_clone_and_build_kcov tests/kcov')
local IFS=$'\n'
write_kcov_go_script "${go_script[*]}"
echo 'mkdir -p "$3"' >> "$FAKE_BIN_DIR/git"

run env TRAVIS_OS_NAME= "$TEST_GO_SCRIPT"
. 'scripts/lib/kcov'
. 'lib/kcov-ubuntu'
local expected_output=(
"Cloning kcov repository from $KCOV_URL..."
"Cloning kcov repository from $__KCOV_URL..."
'Installing dev packages to build kcov...'
'Building kcov...')
assert_success "${expected_output[*]}"

run cat "$FAKE_BIN_DIR/git.out"
assert_success "clone $KCOV_URL tests/kcov"
assert_success "clone $__KCOV_URL tests/kcov"

run cat "$FAKE_BIN_DIR/sudo.out"
IFS=' '
assert_success "apt-get install -y ${KCOV_DEV_PACKAGES[*]}"
assert_success "apt-get install -y ${__KCOV_DEV_PACKAGES[*]}"

run cat "$FAKE_BIN_DIR/cmake.out"
assert_success '.'
Expand All @@ -116,26 +115,26 @@ write_kcov_dummy() {
}

@test "$SUITE: clone and build fails if clone fails" {
write_kcov_go_script 'clone_and_build_kcov tests/kcov'
write_kcov_go_script '_clone_and_build_kcov tests/kcov'
echo 'exit 1' >> "$FAKE_BIN_DIR/git"

run env TRAVIS_OS_NAME= "$TEST_GO_SCRIPT"
. 'scripts/lib/kcov'
. 'lib/kcov-ubuntu'
local expected_output=(
"Cloning kcov repository from $KCOV_URL..."
"Failed to clone $KCOV_URL into tests/kcov.")
"Cloning kcov repository from $__KCOV_URL..."
"Failed to clone $__KCOV_URL into tests/kcov.")
local IFS=$'\n'
assert_failure "${expected_output[*]}"
}

@test "$SUITE: clone and build fails if install fails" {
write_kcov_go_script 'clone_and_build_kcov tests/kcov'
write_kcov_go_script '_clone_and_build_kcov tests/kcov'
echo 'exit 1' >>"$FAKE_BIN_DIR/dpkg-query"
echo 'exit 1' >> "$FAKE_BIN_DIR/sudo"
mkdir -p "$TEST_GO_ROOTDIR/tests/kcov"

run env TRAVIS_OS_NAME= "$TEST_GO_SCRIPT"
. 'scripts/lib/kcov'
. 'lib/kcov-ubuntu'
local expected_output=(
'Installing dev packages to build kcov...'
'Failed to install dev packages needed to build kcov.')
Expand All @@ -144,12 +143,12 @@ write_kcov_dummy() {
}

@test "$SUITE: clone and build fails if cmake fails" {
write_kcov_go_script 'clone_and_build_kcov tests/kcov'
write_kcov_go_script '_clone_and_build_kcov tests/kcov'
mkdir -p "$TEST_GO_ROOTDIR/tests/kcov"
echo 'exit 1' >> "$FAKE_BIN_DIR/cmake"

run env TRAVIS_OS_NAME= "$TEST_GO_SCRIPT"
. 'scripts/lib/kcov'
. 'lib/kcov-ubuntu'
local expected_output=(
'Building kcov...'
'Failed to build kcov.')
Expand All @@ -158,12 +157,12 @@ write_kcov_dummy() {
}

@test "$SUITE: clone and build fails if make fails" {
write_kcov_go_script 'clone_and_build_kcov tests/kcov'
write_kcov_go_script '_clone_and_build_kcov tests/kcov'
mkdir -p "$TEST_GO_ROOTDIR/tests/kcov"
echo 'exit 1' >> "$FAKE_BIN_DIR/make"

run env TRAVIS_OS_NAME= "$TEST_GO_SCRIPT"
. 'scripts/lib/kcov'
. 'lib/kcov-ubuntu'
local expected_output=(
'Building kcov...'
'Failed to build kcov.')
Expand All @@ -173,8 +172,8 @@ write_kcov_dummy() {

@test "$SUITE: clone and build doesn't install dev packages on Travis" {
local go_script=(
'check_kcov_dev_packages_installed() { return 1; }'
'clone_and_build_kcov tests/kcov')
'_check_kcov_dev_packages_installed() { return 1; }'
'_clone_and_build_kcov tests/kcov')
local IFS=$'\n'
write_kcov_go_script "${go_script[*]}"

Expand All @@ -201,15 +200,17 @@ write_kcov_dummy() {
}

@test "$SUITE: fail to run kcov if not present and can't be built" {
write_kcov_go_script 'clone_and_build_kcov() { echo "KCOV: $*"; return 1; }' \
write_kcov_go_script \
'_clone_and_build_kcov() { echo "KCOV: $*"; return 1; }' \
"run_kcov ${RUN_KCOV_ARGV[*]}"
run "$TEST_GO_SCRIPT"
assert_failure "KCOV: $KCOV_DIR"
}

@test "$SUITE: success when kcov already built" {
write_kcov_dummy "IFS=\$'\\n'; echo \"\$*\""
write_kcov_go_script "run_kcov ${RUN_KCOV_ARGV[*]} foo bar/baz"
write_kcov_go_script \
"run_kcov ${RUN_KCOV_ARGV[*]} \"$TEST_GO_SCRIPT\" test foo bar/baz"

local kcov_argv=("${KCOV_ARGV_START[@]}" "$KCOV_COVERAGE_DIR"
"$TEST_GO_SCRIPT" 'test' 'foo' 'bar/baz')
Expand All @@ -227,12 +228,12 @@ write_kcov_dummy() {

@test "$SUITE: success after building kcov" {
local go_script=(
'clone_and_build_kcov() {'
'_clone_and_build_kcov() {'
" mkdir -p '${KCOV_PATH%/*}'"
" printf '#! /usr/bin/env bash\n' >'$KCOV_PATH'"
" chmod 700 '$KCOV_PATH'"
'}'
"run_kcov ${RUN_KCOV_ARGV[*]} foo bar/baz")
"run_kcov ${RUN_KCOV_ARGV[*]} \"$TEST_GO_SCRIPT\" test foo bar/baz")
write_kcov_go_script "${go_script[@]}"

local kcov_argv=("${KCOV_ARGV_START[@]}" "$KCOV_COVERAGE_DIR"
Expand All @@ -250,7 +251,8 @@ write_kcov_dummy() {

@test "$SUITE: failure if kcov returns an error status" {
write_kcov_dummy "printf 'Oh noes!\n' >&2; exit 1"
write_kcov_go_script "run_kcov ${RUN_KCOV_ARGV[*]} foo bar/baz"
write_kcov_go_script \
"run_kcov ${RUN_KCOV_ARGV[*]} \"$TEST_GO_SCRIPT\" test foo bar/baz"

local kcov_argv=("${KCOV_ARGV_START[@]}" "$KCOV_COVERAGE_DIR"
"$TEST_GO_SCRIPT" 'test' 'foo' 'bar/baz')
Expand All @@ -266,7 +268,8 @@ write_kcov_dummy() {

@test "$SUITE: send results to Coveralls when running on Travis" {
write_kcov_dummy
write_kcov_go_script "run_kcov ${RUN_KCOV_ARGV[*]} foo bar/baz"
write_kcov_go_script \
"run_kcov ${RUN_KCOV_ARGV[*]} \"$TEST_GO_SCRIPT\" test foo bar/baz"

local kcov_argv=("${KCOV_ARGV_START[@]}"
"--coveralls-id=666" "$KCOV_COVERAGE_DIR"
Expand All @@ -289,8 +292,9 @@ write_kcov_dummy() {
"$KCOV_INCLUDE_PATTERNS"
"$KCOV_EXCLUDE_PATTERNS")
write_kcov_dummy
# Note that the coveage_url argument is the empty string.
write_kcov_go_script "run_kcov ${run_kcov_argv[*]} '' foo bar/baz"
# Note that the coverage_url argument is the empty string.
write_kcov_go_script \
"run_kcov ${run_kcov_argv[*]} '' \"$TEST_GO_SCRIPT\" test foo bar/baz"

local kcov_argv=("${KCOV_ARGV_START[@]}" "$KCOV_COVERAGE_DIR"
"$TEST_GO_SCRIPT" 'test' 'foo' 'bar/baz')
Expand Down
5 changes: 4 additions & 1 deletion tests/test.bats
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ load assertions
load script_helper

teardown() {
restore_stubbed_core_modules
remove_test_go_rootdir
}

Expand Down Expand Up @@ -107,7 +108,7 @@ write_bats_dummy_stub_kcov_lib_and_copy_test_script() {
create_bats_test_script "tests/bats/libexec/bats"

# Stub the kcov lib to assert it's called correctly.
create_test_command_script 'lib/kcov' \
create_core_module_stub 'kcov-ubuntu' \
"run_kcov() { IFS=\$'\n'; echo \"\$*\"; }"

if [[ ! -d "$TEST_GO_SCRIPTS_DIR" ]]; then
Expand All @@ -127,6 +128,8 @@ write_bats_dummy_stub_kcov_lib_and_copy_test_script() {
'go,go-core.bash,lib/,libexec/,scripts/'
'/tmp,tests/bats/'
'https://coveralls.io/github/mbland/go-script-bash'
"$TEST_GO_SCRIPT"
'test'
'foo'
'bar/baz')

Expand Down

0 comments on commit b9333a6

Please sign in to comment.