From 92886204c614055c30197d6dd4783b8fa7823aa9 Mon Sep 17 00:00:00 2001
From: Michael Hanselmann <hansmi@google.com>
Date: Tue, 25 Sep 2012 11:48:46 +0200
Subject: [PATCH] Add tests for bash completion
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Given the number of settings that need to be controlled a plain bash
script was a better choice over shelltestrunner. Just a few completions
are attempted, but among them should be the most critical ones (e.g.
β€œgnt-instance add --node …”.

Signed-off-by: Michael Hanselmann <hansmi@google.com>
Reviewed-by: Iustin Pop <iustin@google.com>
---
 Makefile.am               |   4 +
 test/bash_completion.bash | 235 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 239 insertions(+)
 create mode 100755 test/bash_completion.bash

diff --git a/Makefile.am b/Makefile.am
index 5ec9cf772..7ae24ef88 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -934,6 +934,7 @@ dist_TESTS = \
 	test/ganeti-cleaner_unittest.bash \
 	test/import-export_unittest.bash \
 	test/cli-test.bash \
+	test/bash_completion.bash \
 	$(python_tests)
 
 nodist_TESTS =
@@ -986,6 +987,7 @@ srclink_files = \
 	test/ganeti-cleaner_unittest.bash \
 	test/import-export_unittest.bash \
 	test/cli-test.bash \
+	test/bash_completion.bash \
 	htest/offline-test.sh \
 	htest/cli-tests-defs.sh \
 	$(all_python_code) \
@@ -1030,6 +1032,8 @@ test/daemon-util_unittest.bash: daemons/daemon-util
 
 test/ganeti-cleaner_unittest.bash: daemons/ganeti-cleaner
 
+test/bash_completion.bash: doc/examples/bash_completion-debug
+
 tools/kvm-ifup: tools/kvm-ifup.in $(REPLACE_VARS_SED)
 	sed -f $(REPLACE_VARS_SED) < $< > $@
 	chmod +x $@
diff --git a/test/bash_completion.bash b/test/bash_completion.bash
new file mode 100755
index 000000000..012ec2796
--- /dev/null
+++ b/test/bash_completion.bash
@@ -0,0 +1,235 @@
+#!/bin/bash
+#
+
+# Copyright (C) 2012 Google Inc.
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+set -e -u -o pipefail
+
+# Disable any locales
+export LC_ALL=C
+
+readonly bash_completion=${TOP_BUILDDIR:-.}/doc/examples/bash_completion-debug
+readonly default_wordbreaks=$' \t\n"'\''@><=;|&(:'
+
+err() {
+  echo "$@"
+  echo 'Aborting'
+  exit 1
+}
+
+contains() {
+  local -r needle="$1"; shift
+
+  for value; do
+    if [[ "$value" = "$needle" ]]; then
+      return 0
+    fi
+  done
+
+  return 1
+}
+
+# Prepares a subshell for testing bash completion functions
+setup() {
+  local -r unused=UNUSED
+
+  set +e +u -o pipefail
+
+  . $bash_completion
+
+  COMP_KEY=$unused
+  COMP_LINE=$unused
+  COMP_POINT=$unused
+  COMP_TYPE=$unused
+  COMP_WORDBREAKS="$default_wordbreaks"
+
+  GANETI_COMPL_LOG=
+
+  unset COMP_CWORD
+  unset COMP_WORDS
+}
+
+# Check if default wordbreaks are still valid (this detects cases where Bash
+# were to change its built-in default value)
+# TODO: May need an update for older Bash versions; some didn't include the
+# colon character (':') in COMP_WORDBREAKS
+(
+  bashdef=$(env - bash --noprofile --norc -c 'echo -n "$COMP_WORDBREAKS"')
+  case "$bashdef" in
+    $default_wordbreaks) ;;
+    *)
+      err 'Bash uses unknown value for COMP_WORDBREAKS'
+      ;;
+  esac
+)
+
+# Check for --help
+for cmd in gnt-{instance,node,group,job}; do
+  (
+    setup
+    COMP_CWORD=2
+    COMP_WORDS=( $cmd list - )
+    _${cmd/-/_}
+    contains --help "${COMPREPLY[@]}" || \
+      err "'$cmd list' did not list --help as an option"
+  )
+done
+
+# Completing a yes/no option
+(
+  setup
+  COMP_CWORD=3
+  COMP_WORDS=( gnt-node modify --drained )
+  _gnt_node
+  if [[ "${COMPREPLY[*]}" != 'no yes' ]]; then
+    err "Completing '${COMP_WORDS[@]}' did not give correct result"
+  fi
+)
+
+# Completing a multiple-choice option
+(
+  setup
+  COMP_CWORD=2
+  COMP_WORDS=( gnt-debug allocator --disk-template=sh foo )
+  _gnt_debug
+  if [[ "${COMPREPLY[*]}" != sharedfile ]]; then
+    err "Completing '${COMP_WORDS[*]}' did not give correct result"
+  fi
+)
+
+# Completing a node name
+(
+  setup
+
+  # Override built-in function
+  _ganeti_nodes() {
+    echo aanode1 bbnode2 aanode3
+  }
+
+  COMP_CWORD=4
+  COMP_WORDS=( gnt-node modify --drained yes aa )
+  _gnt_node
+  if [[ "${COMPREPLY[*]}" != 'aanode1 aanode3' ]]; then
+    err 'Completing node names failed'
+  fi
+)
+
+# Completing an option when it's not at the end
+(
+  setup
+
+  # Override built-in function
+  _ganeti_instances() {
+    echo inst{1..5}
+  }
+
+  # Completing word in the middle
+  COMP_CWORD=2
+  COMP_WORDS=( gnt-instance list --o inst3 inst inst5 )
+  _gnt_node
+  contains --output "${COMPREPLY[@]}" || err 'Did not complete parameter'
+)
+
+# Completing an instance name
+(
+  setup
+
+  # Override built-in function
+  _ganeti_instances() {
+    echo inst{1..5}
+  }
+
+  # Completing word in the middle
+  COMP_CWORD=5
+  COMP_WORDS=( gnt-instance list -o foobar inst1 inst inst5 )
+  _gnt_instance
+  if [[ "${COMPREPLY[*]}" != "$(echo inst{1..5})" ]]; then
+    err "Completing '${COMP_WORDS[*]}' did not give correct result"
+  fi
+)
+
+# Need to test node expansion with different wordbreak settings
+[[ "$default_wordbreaks" == *:* ]] || \
+  err 'No colon in default wordbreak characters'
+for wb in "$default_wordbreaks" "${default_wordbreaks/:/}"; do
+  (
+    setup
+
+    # Override built-in function
+    _ganeti_nodes() {
+      echo node{A..C}
+    }
+
+    COMP_WORDBREAKS="$wb"
+
+    # Completing nodes
+    COMP_CWORD=3
+    COMP_WORDS=( gnt-instance add -n )
+    _gnt_instance
+    if [[ "${COMPREPLY[*]}" != 'nodeA nodeA: nodeB nodeB: nodeC nodeC:' ]]; then
+      err 'Got wrong node list'
+    fi
+
+    COMP_CWORD=3
+    COMP_WORDS=( gnt-instance add -n nodeB )
+    _gnt_instance
+    if [[ "${COMPREPLY[*]}" != 'nodeB nodeB:' ]]; then
+      err 'Got wrong node list'
+    fi
+
+    COMP_CWORD=3
+    COMP_WORDS=( gnt-instance add -n nodeC: )
+    _gnt_instance
+    if [[ "$COMP_WORDBREAKS" == *:* ]]; then
+      expected='nodeA nodeB'
+    else
+      expected='nodeC:nodeA nodeC:nodeB'
+    fi
+    if [[ "${COMPREPLY[*]}" != "$expected" ]]; then
+      err 'Got wrong node list'
+    fi
+  )
+done
+
+# Need to test different settings for the extglob shell option
+for opt in -u -s; do
+  verify_extglob() {
+    if [[ "$(shopt -p extglob)" != "shopt $opt extglob" ]]; then
+      err 'The "extglob" shell option has an unexpected value'
+    fi
+  }
+
+  (
+    shopt $opt extglob
+
+    verify_extglob
+    setup
+    verify_extglob
+
+    # Completing nodes
+    COMP_CWORD=4
+    COMP_WORDS=( gnt-instance add --os-type busybox --no-n )
+    _gnt_instance
+    if [[ "${COMPREPLY[*]}" != '--no-name-check --no-nics' ]]; then
+      err "Completing '${COMP_WORDS[*]}' did not give correct result"
+    fi
+    verify_extglob
+  )
+done
+
+exit 0
-- 
GitLab