#!/bin/bash # # run_tests.sh # # Copyright (C) 2017, Branko Majic # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # program="run_tests.sh" function usage() { cat <. EOF } function version() { cat < | | | | This program is free software: you can redistribute it and/or modify | | it under the terms of the GNU General Public License as published by | | the Free Software Foundation, either version 3 of the License, or | | (at your option) any later version. | | | | This program is distributed in the hope that it will be useful, | | but WITHOUT ANY WARRANTY; without even the implied warranty of | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | GNU General Public License for more details. | | | | You should have received a copy of the GNU General Public License | | along with this program. If not, see . | +-----------------------------------------------------------------------+ EOF } # Set-up colours for message printing if we're not piping and terminal is # capable of outputting the colors. _color_terminal=$(tput colors 2>&1) if [[ -t 1 ]] && (( ${_color_terminal} > 0 )); then _text_bold=$(tput bold) _text_white=$(tput setaf 7) _text_blue=$(tput setaf 6) _text_green=$(tput setaf 2) _text_yellow=$(tput setaf 3) _text_red=$(tput setaf 1) _text_reset=$(tput sgr0) else _text_bold="" _text_white="" _text_blue="" _text_green="" _text_yellow="" _text_red="" _text_reset="" fi # Set-up functions for printing coloured messages. function debug() { if [[ $debug != 0 ]]; then echo "${_text_bold}${_text_blue}[DEBUG]${_text_reset}" "$@" fi } function info() { echo "${_text_bold}${_text_white}[INFO] ${_text_reset}" "$@" } function success() { echo "${_text_bold}${_text_green}[OK] ${_text_reset}" "$@" } function warning() { echo "${_text_bold}${_text_yellow}[WARN] ${_text_reset}" "$@" } function error() { echo "${_text_bold}${_text_red}[ERROR]${_text_reset}" "$@" >&2 } # Define error codes. SUCCESS=0 ERROR_ARGUMENTS=1 ERROR_NO_ROLES=2 ERROR_MISSING_BINARY=3 ERROR_FAILED_ROLES=4 ERROR_REPORT=5 # Disable debug mode by default. debug=0 # Default values. report=0 tests=all # If no arguments were given, just show usage help. if [[ -z $1 ]]; then usage exit "$SUCCESS" fi # Parse the arguments while getopts "rl:qdvh" opt; do case "$opt" in r) report=1;; l) tests="$OPTARG";; d) debug=1;; v) version exit "$SUCCESS";; h) usage exit "$SUCCESS";; *) usage exit "$ERROR_ARGUMENTS";; esac done i=$OPTIND shift $(($i-1)) # Test if the necessary binaries are available. if ! type molecule > /dev/null 2>&1; then error "Could not locate binary: molecule. Please ensure you are running the script from within correctly set-up Python virtual environment." exit $ERROR_MISSING_BINARY fi # Assume success. test_result=0 # Verify arguments. if [[ $tests != "all" && $tests != "lint" ]]; then error "Unsupported type of tests requested: $tests" exit $ERROR_ARGUMENTS fi # Assemble list of roles to run against. roles=() roles_to_test=() roles_to_skip=() # Assemble list of roles to test. if [[ $1 == "all" ]]; then debug "Testing of all roles was requested, assembling role list." # Traverse directory. for role_dir in roles/*; do if [[ -d $role_dir ]]; then debug "Located candiate role in directory $role_dir" roles+=("${role_dir#roles/}") else debug "Ignoring non-directory $role_dir" fi done else while [[ -n $1 ]]; do roles+=($1) shift 1 done fi if [[ ${#roles[@]} == 0 ]]; then error "No role has been specified for testing." exit $ERROR_ARGUMENTS fi # Determine which roles have available tests. for role in "${roles[@]}"; do role_dir="roles/$role" if [[ ! -d "roles/$role" ]]; then warning "Could not locate role $role in directory $role_dir" roles_to_skip+=("$role") elif [[ -f "$role_dir/molecule/default/molecule.yml" ]]; then debug "Role $role contains Molecule configuration." roles_to_test+=("$role") else warning "Role $role cannot be tested - missing Molecule configuration." roles_to_skip+=("$role") fi done # Output some helpful info, and ensure we can actually run tests against # something. info "Testing requested for roles: ${roles[@]}" [[ ${#roles_to_skip[@]} != 0 ]] && info "The following roles will not be tested: ${roles_to_skip[@]}" if [[ ${#roles_to_test[@]} == 0 ]]; then error "No roles can be tested." exit $ERROR_NO_ROLES fi info "The following roles will be tested: ${roles_to_test[@]}" # Prepare directory for storing reports. if [[ $report == 1 ]]; then report_directory="$(pwd)/test_report-$(date +%Y_%m_%d-%H_%M_%S)" report_summary="${report_directory}/summary.txt" if ! mkdir "$report_directory"; then error "Failed to create report directory $report_directory" exit $ERROR_REPORT fi touch "$report_summary" debug "Created report directory $report_directory." # Output skipped roles to summary immediatelly. for role in "${roles_to_skip[@]}"; do echo "[SKIP] $role" >> "$report_summary" done else debug "No report directory will be created." fi # Test the roles. passed_roles=() failed_roles=() work_dir="$(pwd)" for role in "${roles_to_test[@]}"; do # Calculate directories between which we need to move. role_dir="$work_dir/roles/$role" # Run tests. cd "$role_dir" if [[ $report == 1 ]]; then report_file="$report_directory/role-${role}.txt" else report_file="/dev/null" fi info "Running tests for: $role" if [[ $tests == all ]]; then molecule test --destroy always 2>&1 | tee "$report_file" elif [[ $tests == lint ]]; then molecule lint 2>&1 | tee "$report_file" fi # Determine result. if [[ "${PIPESTATUS[0]}" == 0 ]]; then passed_roles+=("$role") # Log failure in summary if requested. [[ $report == 1 ]] && echo "[PASS] $role" >> "$report_summary" else test_result=$ERROR_FAILED_ROLES failed_roles+=("$role") # Log failure in summary if requested. [[ $report == 1 ]] && echo "[FAIL] $role" >> "$report_summary" fi # Make sure the instances have been cleaned-up to avoid errors. if [[ $tests == all ]]; then molecule destroy fi done for role in "${roles_to_skip[@]}"; do warning "SKIP: $role" done for role in "${passed_roles[@]}"; do success "PASS: $role" done for role in "${failed_roles[@]}"; do error "FAIL: $role" done exit $test_result