You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ge...@apache.org on 2018/03/16 01:20:46 UTC

lucene-solr:master: SOLR-11749: Introduce bin/solr test suite

Repository: lucene-solr
Updated Branches:
  refs/heads/master 298063eee -> 2ca741d36


SOLR-11749: Introduce bin/solr test suite


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/2ca741d3
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/2ca741d3
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/2ca741d3

Branch: refs/heads/master
Commit: 2ca741d36a3078e7d7b03cb73176a1e99377eefc
Parents: 298063e
Author: Jason Gerlowski <ge...@apache.org>
Authored: Sun Mar 11 10:22:40 2018 -0400
Committer: Jason Gerlowski <ge...@apache.org>
Committed: Thu Mar 15 21:20:13 2018 -0400

----------------------------------------------------------------------
 solr/bin-test/README.md                 |  53 ++++++++
 solr/bin-test/test                      | 191 +++++++++++++++++++++++++++
 solr/bin-test/test_create_collection.sh | 133 +++++++++++++++++++
 solr/bin-test/test_delete_collection.sh |  70 ++++++++++
 solr/bin-test/test_help.sh              | 134 +++++++++++++++++++
 solr/bin-test/test_start_solr.sh        |  39 ++++++
 solr/bin-test/utils/assert.sh           | 123 +++++++++++++++++
 solr/bin-test/utils/cleanup.sh          |  25 ++++
 8 files changed, 768 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/2ca741d3/solr/bin-test/README.md
----------------------------------------------------------------------
diff --git a/solr/bin-test/README.md b/solr/bin-test/README.md
new file mode 100644
index 0000000..2a429c4
--- /dev/null
+++ b/solr/bin-test/README.md
@@ -0,0 +1,53 @@
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ -->
+
+# bin/solr Tests
+
+This directory contains tests for the `bin/solr` command-line scripts.  For
+instructions on running these tests, run `bin-test/test -h`.
+
+## Test Harness/Infrastructure
+
+Where possible, these tests model themselves after the pattern well-established
+by JUnit.
+  - JUnit's `@Test` is emulated using the function name prefix: `solr_test_`
+    Any bash functions starting with that prefix are identified as tests.
+  - JUnit's `@Before` and `@After` are imitated using the function names
+    `solr_unit_test_before`, and `solr_unit_test_after`.  If a suite contains
+    these functions, they will be run before and after each test.
+  - JUnit's `@BeforeClass` and `@AfterClass` are imitated using the function
+    names: `solr_suite_before`, and `solr_suite_after`.  If a suite contains
+    these functions, they will be run at the very beginning and end of suite
+    execution.
+  - Test success/failure is judged by the test's return value. 0 indicates
+    success; non-zero indicates failure.  Unlike in JUnit/Java which has
+    exceptions, bash assertions have no way to suspend test execution on
+    failure.  Because of this, assertions are often followed by ` || return 1`,
+    which ensures the test exists immediately if the assertion fails.  Existing
+    tests provided examples of this.
+
+## Test Helpers
+
+A variety of assertions and general utilities are available for use in
+`bin-test/utils/`.
+
+## Limitations
+
+1. Currently this test suite is only available for \*nix environments
+2. Tests written in bash are both slow, and harder to maintain than traditional
+   JUnit tests.  If a test _can_ be written as a JUnit test, it should be.  This
+   suite should only be used to test things that cannot be tested by JUnit.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/2ca741d3/solr/bin-test/test
----------------------------------------------------------------------
diff --git a/solr/bin-test/test b/solr/bin-test/test
new file mode 100755
index 0000000..f67c522
--- /dev/null
+++ b/solr/bin-test/test
@@ -0,0 +1,191 @@
+#!/bin/bash
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+function ensure_cwd_is_solr() {
+  local cwd=`pwd`
+  if [[ "solr" != `basename $cwd` ]]
+  then
+    echo "ERROR: Please run this script from the 'solr' directory."
+    exit 1
+  fi
+}
+
+function run_suite_before_if_present() {
+  if declare -f solr_suite_before > /dev/null ; then
+    solr_suite_before
+  fi
+}
+
+function run_suite_after_if_present() {
+  if declare -f solr_suite_after > /dev/null ; then
+    solr_suite_after
+  fi
+}
+
+function run_test_before_if_present() {
+  if declare -f solr_unit_test_before > /dev/null ; then
+    solr_unit_test_before
+  fi
+}
+
+function run_test_after_if_present() {
+  if declare -f solr_unit_test_after > /dev/null ; then
+    solr_unit_test_after
+  fi
+}
+
+function run_test_suite() {
+  local test_file=$1
+  local test_name_filter="${2:-}"
+
+  echo "Executing $test_file"
+  source $test_file
+  test_names="$(declare -F | awk '{print $3}' | grep 'solr_test')"
+
+  run_suite_before_if_present
+  for test_name in $test_names
+  do
+    if [[ -z "$test_name_filter" || "$test_name_filter" == "$test_name" ]]; then
+      run_single_test $test_name
+    fi
+    unset -f $test_name
+  done
+  run_suite_after_if_present
+
+  unset solr_suite_before
+  unset solr_suite_after
+  unset solr_unit_test_before
+  unset solr_unit_test_after
+}
+
+function run_single_test() {
+  local test_name=$1
+
+  echo -n "  $test_name "
+  run_test_before_if_present
+  let NUM_TESTS+=1
+  output=$($test_name)
+  if [[ $? -ne 0 ]]; then
+    let NUM_FAILURES+=1
+    echo "FAILED"
+    echo "---------------------------------------------------"
+    echo "$output"
+    echo "---------------------------------------------------"
+  else
+    let NUM_SUCCESSES+=1
+    echo "SUCCEEDED"
+  fi
+  run_test_after_if_present
+}
+
+function ensure_param_arg_present() {
+  if [[ $# -lt 2 || "$2" == -* ]]; then
+    echo "Option '$1' requires a single argument, but none provided."
+    exit 1
+  fi
+}
+
+function print_help() {
+  echo "Usage: bin-test/test [-h] [-s SUITE_NAME] [-t SUITE_NAME#TEST_NAME]"
+  echo ""
+  echo "  Run tests for the 'bin/solr' Solr startup/admin scripts.  By default all tests are run."
+  echo "  Tests suites or single tests can be selected by use of the options below:"
+  echo ""
+  echo "  -s|--run-single-suite    Runs all tests living in the specified file.  Filename argument"
+  echo "                           should include the full file extension, but no path prefix."
+  echo "                           (e.g. test_help.sh works, bin-test/test_help.sh and test_help"
+  echo "                           do not)"
+  echo ""
+  echo "  -t|--run-single-test     Runs the specified test from the specified test suite file."
+  echo "                           Takes an argument in the form 'SUITE_NAME#TEST_NAME', where"
+  echo "                           SUITE_NAME is the filename of a test suite (see -s above), and"
+  echo "                           TEST_NAME matches the name of a bash test function present in"
+  echo "                           that file"
+  echo ""
+  echo "  -h|--help                You're soaking in it."
+  echo ""
+  exit 0
+}
+
+function run_all_tests() {
+  test_files="$(find bin-test -name "test_*.sh")"
+
+  for test_file in $test_files
+  do
+    run_test_suite $test_file
+  done
+}
+
+
+## MAIN ##
+##########
+ensure_cwd_is_solr
+
+# Can be 'all', 'help', 'single-suite', or 'single-test'
+MODE="all"
+SUITE_NAME=""
+TEST_NAME=""
+NUM_TESTS=0
+NUM_SUCCESSES=0
+NUM_FAILURES=0
+
+while [[ $# -gt 0 ]]
+do
+  case $1 in
+    -h|--help)
+      MODE="help"
+      shift 1
+    ;;
+    -s|--run-single-suite)
+      ensure_param_arg_present $@
+      MODE="single-suite"
+      SUITE_NAME="bin-test/$2"
+      shift 2
+    ;;
+    -t|--run-single-test)
+      ensure_param_arg_present $@
+      MODE="single-test"
+      SUITE_NAME="bin-test/$(echo "$2" | cut -d "#" -f 1 | tr -d " ")"
+      TEST_NAME=$(echo "$2" | cut -d "#" -f 2 | tr -d " ")
+      shift 2
+    ;;
+    *)
+      echo "WARNING: Unexpected argument [$1] detected, ignoring."
+      shift 1
+    ;;
+  esac
+done
+
+case $MODE in
+  "help")
+    print_help
+    MAIN_RESULT=0
+  ;;
+  "single-suite")
+    run_test_suite $SUITE_NAME
+    MAIN_RESULT=$?
+  ;;
+  "single-test")
+    run_test_suite $SUITE_NAME $TEST_NAME
+    MAIN_RESULT=$?
+  ;;
+  "all")
+    run_all_tests
+    MAIN_RESULT=$?
+esac
+echo "Ran $NUM_TESTS tests, with $NUM_SUCCESSES passing, and $NUM_FAILURES failures"
+exit $MAIN_RESULT

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/2ca741d3/solr/bin-test/test_create_collection.sh
----------------------------------------------------------------------
diff --git a/solr/bin-test/test_create_collection.sh b/solr/bin-test/test_create_collection.sh
new file mode 100644
index 0000000..011c4ab
--- /dev/null
+++ b/solr/bin-test/test_create_collection.sh
@@ -0,0 +1,133 @@
+#!/bin/bash
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+source bin-test/utils/assert.sh
+source bin-test/utils/cleanup.sh
+
+
+# All tests should start with solr_test
+
+function solr_suite_before() {
+  bin/solr stop -all > /dev/null 2>&1
+  bin/solr start -c > /dev/null 2>&1
+
+
+  local source_configset_dir="server/solr/configsets/sample_techproducts_configs"
+  TMP_CONFIGSET_DIR="/tmp/test_config"
+  rm -rf $TMP_CONFIGSET_DIR; cp -r $source_configset_dir $TMP_CONFIGSET_DIR
+}
+
+function solr_suite_after() {
+  bin/solr stop -all > /dev/null 2>&1
+  rm -rf $TMP_CONFIGSET_DIR
+}
+
+function solr_unit_test_before() {
+  delete_all_collections > /dev/null 2>&1
+}
+
+function solr_unit_test_after() {
+  delete_all_collections > /dev/null 2>&1
+}
+
+
+function solr_test_can_create_collection() {
+  local create_cmd="bin/solr create_collection -c COLL_NAME"
+  local expected_output="Created collection 'COLL_NAME'"
+  local actual_output; actual_output=$($create_cmd)
+
+  assert_cmd_succeeded "$create_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_output" || return 1
+}
+
+function solr_test_rejects_d_option_with_invalid_config_dir() {
+  local create_cmd="bin/solr create_collection -c COLL_NAME -d /asdf"
+  local expected_output="Specified configuration directory /asdf not found!"
+  local actual_output; actual_output=$($create_cmd)
+
+  assert_cmd_failed "$create_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_output" || return 1
+}
+
+function solr_test_accepts_d_option_with_explicit_builtin_config() {
+  local create_cmd="bin/solr create_collection -c COLL_NAME -d sample_techproducts_configs"
+  local expected_output="Created collection 'COLL_NAME'"
+  local actual_output; actual_output=$($create_cmd)
+
+  assert_cmd_succeeded "$create_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_output" || return 1
+}
+
+function solr_test_accepts_d_option_with_explicit_path_to_config() {
+  local create_cmd="bin/solr create_collection -c COLL_NAME -d $TMP_CONFIGSET_DIR"
+  local expected_output="Created collection 'COLL_NAME'"
+  local actual_output; actual_output=$($create_cmd)
+
+  assert_cmd_succeeded "$create_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_output" || return 1
+}
+
+function solr_test_accepts_n_option_as_config_name() {
+  local create_cmd="bin/solr create_collection -c COLL_NAME -n other_conf_name"
+  local expected_name_output="Created collection 'COLL_NAME'"
+  local expected_config_name_output="config-set 'other_conf_name'"
+  local actual_output; actual_output=$($create_cmd)
+
+  # Expect to fail, change to success
+  assert_cmd_succeeded "$create_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_name_output" || return 1
+  assert_output_contains "$actual_output" "$expected_config_name_output" || return 1
+}
+
+function solr_test_allows_config_reuse_when_n_option_specifies_same_config() {
+  local create_cmd1="bin/solr create_collection -c COLL_NAME_1 -n shared_config"
+  local expected_coll_name_output1="Created collection 'COLL_NAME_1'"
+  local create_cmd2="bin/solr create_collection -c COLL_NAME_2 -n shared_config"
+  local expected_coll_name_output2="Created collection 'COLL_NAME_2'"
+  local expected_config_name_output="config-set 'shared_config'"
+
+  local actual_output1; actual_output1=$($create_cmd1)
+  assert_cmd_succeeded "$create_cmd1" || return 1
+  assert_output_contains "$actual_output1" "$expected_coll_name_output1" || return 1
+  assert_output_contains "$actual_output1" "$expected_config_name_output" || return 1
+
+  local actual_output2; actual_output2=$($create_cmd2)
+  assert_cmd_succeeded "$create_cmd2" || return 1
+  assert_output_contains "$actual_output2" "$expected_coll_name_output2" || return 1
+  assert_output_contains "$actual_output2" "$expected_config_name_output" || return 1
+}
+
+function solr_test_create_multisharded_collections_when_s_provided() {
+  local create_cmd="bin/solr create_collection -c COLL_NAME -s 2"
+  local expected_coll_name_output="Created collection 'COLL_NAME'"
+  local expected_shards_output="2 shard(s)"
+
+  local actual_output; actual_output=$($create_cmd)
+  assert_cmd_succeeded "$create_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_coll_name_output" || return 1
+  assert_output_contains "$actual_output" "$expected_shards_output" || return 1
+}
+
+function solr_test_creates_replicated_collections_when_r_provided() {
+  local create_cmd="bin/solr create_collection -c COLL_NAME -rf 2"
+  local expected_coll_name_output="Created collection 'COLL_NAME'"
+  local expected_rf_output="2 replica(s)"
+
+  local actual_output; actual_output=$($create_cmd)
+  assert_cmd_succeeded "$create_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_coll_name_output" || return 1
+  assert_output_contains "$actual_output" "$expected_rf_output" || return 1
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/2ca741d3/solr/bin-test/test_delete_collection.sh
----------------------------------------------------------------------
diff --git a/solr/bin-test/test_delete_collection.sh b/solr/bin-test/test_delete_collection.sh
new file mode 100644
index 0000000..00d3d72
--- /dev/null
+++ b/solr/bin-test/test_delete_collection.sh
@@ -0,0 +1,70 @@
+#!/bin/bash
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+source bin-test/utils/assert.sh
+source bin-test/utils/cleanup.sh
+
+
+# All tests should start with solr_test
+
+function solr_suite_before() {
+  bin/solr stop -all > /dev/null 2>&1
+  bin/solr start -c > /dev/null 2>&1
+}
+
+function solr_suite_after() {
+  bin/solr stop -all > /dev/null 2>&1
+}
+
+function solr_unit_test_before() {
+  delete_all_collections
+}
+
+function solr_unit_test_after() {
+  delete_all_collections
+}
+
+function solr_test_can_delete_collection() {
+  bin/solr create_collection -c COLL_NAME
+  assert_collection_exists "COLL_NAME" || return 1
+
+  bin/solr delete -c "COLL_NAME"
+  assert_collection_doesnt_exist "COLL_NAME" || return 1
+}
+
+function solr_test_deletes_accompanying_zk_config_by_default() {
+  bin/solr create_collection -c "COLL_NAME"
+  assert_config_exists "COLL_NAME" || return 1
+
+  bin/solr delete -c "COLL_NAME"
+  assert_config_doesnt_exist "COLL_NAME" || return 1
+}
+
+function solr_test_deletes_accompanying_zk_config_with_nondefault_name() {
+  bin/solr create_collection -c "COLL_NAME" -n "NONDEFAULT_CONFIG_NAME"
+  assert_config_exists "NONDEFAULT_CONFIG_NAME" || return 1
+
+  bin/solr delete -c "COLL_NAME"
+  assert_config_doesnt_exist "NONDEFAULT_CONFIG_NAME"
+}
+
+function solr_test_deleteConfig_option_can_opt_to_leave_config_in_zk() {
+  bin/solr create_collection -c "COLL_NAME"
+  assert_config_exists "COLL_NAME"
+
+  bin/solr delete -c "COLL_NAME" -deleteConfig false
+  assert_config_exists "COLL_NAME"
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/2ca741d3/solr/bin-test/test_help.sh
----------------------------------------------------------------------
diff --git a/solr/bin-test/test_help.sh b/solr/bin-test/test_help.sh
new file mode 100644
index 0000000..e9c8c8a
--- /dev/null
+++ b/solr/bin-test/test_help.sh
@@ -0,0 +1,134 @@
+#!/bin/bash
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+source bin-test/utils/assert.sh
+
+function solr_test_start_help_flag_prints_help() {
+  local help_cmd="bin/solr start -help"
+  local expected_output="Usage: solr start"
+  local actual_output; actual_output=$($help_cmd)
+
+  assert_cmd_succeeded "$help_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_output" || return 1
+  assert_output_not_contains "$actual_output" "ERROR" || return 1
+}
+
+function solr_test_stop_help_flag_prints_help() {
+  local help_cmd="bin/solr stop -help"
+  local expected_output="Usage: solr stop"
+  local actual_output; actual_output=$($help_cmd)
+
+  assert_cmd_succeeded "$help_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_output" || return 1
+  assert_output_not_contains "$actual_output" "ERROR" || return 1
+}
+
+function solr_test_restart_help_flag_prints_help() {
+  local help_cmd="bin/solr restart -help"
+  local expected_output="Usage: solr restart"
+  local actual_output; actual_output=$($help_cmd)
+
+  assert_cmd_succeeded "$help_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_output" || return 1
+  assert_output_not_contains "$actual_output" "ERROR" || return 1
+}
+
+function solr_test_status_help_flag_prints_help() {
+  #TODO Currently the status flag doesn't return nice help text!
+  return 0
+}
+
+function solr_test_healthcheck_help_flag_prints_help() {
+  local help_cmd="bin/solr healthcheck -help"
+  local expected_output="Usage: solr healthcheck"
+  local actual_output; actual_output=$($help_cmd)
+
+  assert_cmd_succeeded "$help_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_output" || return 1
+  assert_output_not_contains "$actual_output" "ERROR" || return 1
+}
+
+function solr_test_create_help_flag_prints_help() {
+  local help_cmd="bin/solr create -help"
+  local expected_output="Usage: solr create"
+  local actual_output; actual_output=$($help_cmd)
+
+  assert_cmd_succeeded "$help_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_output" || return 1
+  assert_output_not_contains "$actual_output" "ERROR" || return 1
+}
+
+function solr_test_create_core_help_flag_prints_help() {
+  local help_cmd="bin/solr create_core -help"
+  local expected_output="Usage: solr create_core"
+  local actual_output; actual_output=$($help_cmd)
+
+  assert_cmd_succeeded "$help_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_output" || return 1
+  assert_output_not_contains "$actual_output" "ERROR" || return 1
+}
+
+function solr_test_create_collection_help_flag_prints_help() {
+  local help_cmd="bin/solr create_collection -help"
+  local expected_output="Usage: solr create_collection"
+  local actual_output; actual_output=$($help_cmd)
+
+  assert_cmd_succeeded "$help_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_output" || return 1
+  assert_output_not_contains "$actual_output" "ERROR" || return 1
+}
+
+function solr_test_delete_help_flag_prints_help() {
+  local help_cmd="bin/solr delete -help"
+  local expected_output="Usage: solr delete"
+  local actual_output; actual_output=$($help_cmd)
+
+  assert_cmd_succeeded "$help_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_output" || return 1
+  assert_output_not_contains "$actual_output" "ERROR" || return 1
+}
+
+function solr_test_version_help_flag_prints_help() {
+  #TODO Currently the version -help flag doesn't return nice help text!
+  return 0
+}
+
+function solr_test_zk_help_flag_prints_help() {
+  local help_cmd="bin/solr zk -help"
+  local expected_output="Usage: solr zk"
+  local actual_output; actual_output=$($help_cmd)
+
+  assert_cmd_succeeded "$help_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_output" || return 1
+  assert_output_not_contains "$actual_output" "ERROR" || return 1
+}
+
+function solr_test_auth_help_flag_prints_help() {
+  local help_cmd="bin/solr auth -help"
+  local expected_output="Usage: solr auth"
+  local actual_output; actual_output=$($help_cmd)
+
+  assert_cmd_succeeded "$help_cmd" || return 1
+  assert_output_contains "$actual_output" "$expected_output" || return 1
+  assert_output_not_contains "$actual_output" "ERROR" || return 1
+}
+
+function solr_test_assert_help_flag_prints_help() {
+  #TODO Currently the assert -help flag doesn't return nice help text!
+  # It returns autogenerated SolrCLI help, which is similar but not _quite_
+  # the same thing.
+  return 0
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/2ca741d3/solr/bin-test/test_start_solr.sh
----------------------------------------------------------------------
diff --git a/solr/bin-test/test_start_solr.sh b/solr/bin-test/test_start_solr.sh
new file mode 100644
index 0000000..4ec5952
--- /dev/null
+++ b/solr/bin-test/test_start_solr.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# All tests should start with solr_test
+
+function solr_suite_before() {
+  bin/solr stop -all > /dev/null 2>&1
+}
+
+function solr_suite_after() {
+  bin/solr stop -all > /dev/null 2>&1
+}
+
+function solr_test_11740_checks_f() {
+  # SOLR-11740
+  bin/solr start
+  bin/solr start -p 7574
+  bin/solr stop -all 2>&1 | grep -i "forcefully killing"
+  rcode=$?
+  if [[ $rcode -eq 0 ]]
+  then
+    echo "Unexpected forceful kill - please check."
+    return 2
+  fi
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/2ca741d3/solr/bin-test/utils/assert.sh
----------------------------------------------------------------------
diff --git a/solr/bin-test/utils/assert.sh b/solr/bin-test/utils/assert.sh
new file mode 100644
index 0000000..7c0f323
--- /dev/null
+++ b/solr/bin-test/utils/assert.sh
@@ -0,0 +1,123 @@
+#!/bin/bash
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+ASSERT_SUCCEEDED=1
+ASSERT_FAILURE=0
+
+function assert_cmd_succeeded() {
+  retval=$?
+  
+  if [[ $? -ne 0 ]]; then
+    echo "Expected command $1 to succeed, but exited with $retval"
+    return $ASSERT_FAILURE
+  fi
+
+  return $ASSERT_SUCCESS
+}
+
+function assert_cmd_failed() {
+  retval=$?
+  
+  if [[ $? -eq 0 ]]; then
+    echo "Expected command $1 to fail, but exited with $retval"
+    return $ASSERT_FAILURE
+  fi
+
+  return $ASSERT_SUCCESS
+}
+
+function assert_output_contains() {
+  local actual_output="$1"
+  local needle="$2"
+
+  if echo "$actual_output" | grep -q "$needle"; then
+    return $ASSERT_SUCCESS
+  fi
+
+  echo "Expected to find "$needle" in output [$actual_output]"
+  return $ASSERT_FAILURE
+}
+
+function assert_output_not_contains() {
+  local actual_output="$1"
+  local needle="$2"
+
+  if echo "$actual_output" | grep -q "$needle"; then
+    echo "Didn't expect to find "$needle" in output [$actual_output]"
+    return $ASSERT_FAILURE
+  fi
+
+  return $ASSERT_SUCCESS
+}
+
+function assert_collection_exists() {
+  local coll_name=$1
+  local coll_list=$(bin/solr zk ls /collections -z localhost:9983)
+
+  for coll in "$coll_list";
+  do
+    if [[ $(echo $coll | tr -d " ") -eq $coll_name ]]; then
+      return $ASSERT_SUCCESS
+    fi
+  done
+
+  echo "Expected to find collection named [$coll_name], but could only find: $coll_list"
+  return $ASSERT_FAILURE
+}
+
+function assert_collection_doesnt_exist() {
+  local coll_name=$1
+  local coll_list=$(bin/solr zk ls /collections -z localhost:9983)
+  for coll in "$coll_list";
+  do
+    if [[ $(echo $coll | tr -d " ") -eq $coll_name ]]; then
+      echo "Expected not to find collection [$coll_name], but it exists"
+      return $ASSERT_FAILURE
+    fi
+  done
+
+  return $ASSERT_SUCCESS
+}
+
+function assert_config_exists() {
+  local config_name=$1
+  local config_list=$(bin/solr zk ls /configs -z localhost:9983)
+
+  for config in "$config_list";
+  do
+    if [[ $(echo $config | tr -d " ") -eq $config_name ]]; then
+      return $ASSERT_SUCCESS
+    fi
+  done
+
+  echo "Expected to find config named [$config_name], but could only find: $config_list"
+  return $ASSERT_FAILURE
+}
+
+function assert_config_doesnt_exist() {
+  local config_name=$1
+  local config_list=$(bin/solr zk ls /configs -z localhost:9983)
+
+  for config in "$config_list";
+  do
+    if [[ $(echo $config | tr -d " ") -eq $config_name ]]; then
+      echo "Expected not to find config [$config_name], but it exists"
+      return $ASSERT_FAILURE
+    fi
+  done
+
+  return $ASSERT_SUCCESS
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/2ca741d3/solr/bin-test/utils/cleanup.sh
----------------------------------------------------------------------
diff --git a/solr/bin-test/utils/cleanup.sh b/solr/bin-test/utils/cleanup.sh
new file mode 100644
index 0000000..096cc28
--- /dev/null
+++ b/solr/bin-test/utils/cleanup.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+function delete_all_collections() {
+  local collection_list="$(bin/solr zk ls /collections -z localhost:9983)"
+  for collection in $collection_list;
+  do
+    if [[ -n $collection ]]; then
+      bin/solr delete -c $collection
+    fi
+  done
+}