tfile="${CTDB_TEST_TMP_DIR}/tunable.$$"
tfile2="${CTDB_TEST_TMP_DIR}/tunable2.$$"
+tdir="${CTDB_TEST_TMP_DIR}/tunabled.$$"
remove_files()
{
rm -f "$tfile" "$tfile2"
+ rm -f "${tdir}/"* 2>/dev/null || true
+ rmdir "$tdir" 2>/dev/null || true
}
test_cleanup remove_files
ok_tunable_1 "$_f1"
if [ -n "$_f2" ]; then
- ok_tunable_1 "$_f2"
+ if [ -f "$_f2" ]; then
+ ok_tunable_1 "$_f2"
+ elif [ -d "$_f2" ]; then
+ for _t in "${_f2}/"*.tunables; do
+ if [ ! -e "$_t" ]; then
+ break
+ fi
+ ok_tunable_1 "$_t"
+ done
+ elif [ ! -e "$_f2" ]; then
+ tunable_log "INFO" "Optional tunables directory ${_f2} not found"
+ fi
fi
# Set result, stripping off lowercase tunable prefix
ok_tunable "$tfile" "$tfile2"
unit_test tunable_test "$tfile" "$tfile2"
-test_case "OK, several tunables, missing 2nd file"
+#
+# 2nd argument is a directory
+#
+
+test_case "OK, several tunables, missing directory"
rm -f "$tfile2"
-ok_tunable "$tfile" "$tfile2"
-unit_test tunable_test "$tfile" "$tfile2"
+rmdir "$tdir" 2>/dev/null || true
+ok_tunable "$tfile" "$tdir"
+unit_test tunable_test "$tfile" "$tdir"
+
+test_case "OK, several tunables, empty directory"
+mkdir -p "$tdir"
+ok_tunable "$tfile" "$tdir"
+unit_test tunable_test "$tfile" "$tdir"
+
+test_case "OK, several tunables, README in directory"
+cat >"${tdir}/README" <<EOF
+This will be ignored because the file doesn't end in ".tunables"
+
+RecoverInterval=55
+EOF
+ok_tunable "$tfile" "$tdir"
+unit_test tunable_test "$tfile" "$tdir"
+
+#
+# README can stay there...
+#
+# Subsequent testcases add files, leaving existing ones there
+#
+
+test_case "OK, several tunables, single file in directory"
+cat >"${tdir}/f70.tunables" <<EOF
+RecoverInterval=45
+EOF
+ok_tunable "$tfile" "$tdir"
+unit_test tunable_test "$tfile" "$tdir"
+
+test_case "OK, several tunables, 2 disjoint files in directory"
+cat >"${tdir}/f10.tunables" <<EOF
+RecoverTimeout=42
+EOF
+ok_tunable "$tfile" "$tdir"
+unit_test tunable_test "$tfile" "$tdir"
+
+test_case "OK, several tunables, 3rd file in directory overlaps"
+cat >"${tdir}/f40.tunables" <<EOF
+RecoverInterval=21
+RecoverTimeout=54
+EOF
+ok_tunable "$tfile" "$tdir"
+unit_test tunable_test "$tfile" "$tdir"
+
+test_case "OK, several tunables, error in directory file"
+cat >"${tdir}/f20.tunables" <<EOF
+Oops!
+EOF
+required_error EINVAL <<EOF
+Loading tunables from ${tfile}
+Loading tunables from ${tdir}/f10.tunables
+Loading tunables from ${tdir}/f20.tunables
+${tdir}/f20.tunables: Invalid tunables line containing "Oops!"
+Loading tunables from ${tdir}/f40.tunables
+Loading tunables from ${tdir}/f70.tunables
+EOF
+unit_test tunable_test "$tfile" "$tdir"
#include "common/tunable.c"
+static void usage(const char * prog)
+{
+ fprintf(stderr,
+ "Usage: %s <filename> [<filename>|<dir>]\n",
+ prog);
+ exit(1);
+}
+
int main(int argc, const char **argv)
{
TALLOC_CTX *mem_ctx;
int i;
if (argc != 2 && argc != 3) {
- fprintf(stderr, "Usage: %s <filename> [<filename>]\n", argv[0]);
- return 1;
+ usage(argv[0]);
}
mem_ctx = talloc_new(NULL);
}
if (argc == 3) {
- status = ctdb_tunable_load_file(mem_ctx, &tun_list, argv[2]);
+ struct stat st = {};
+ int stat_failed = false;
+
+ ret = stat(argv[2], &st);
+ if (ret != 0) {
+ if (errno == ENOENT || errno == EACCES) {
+ stat_failed = true;
+ } else {
+ usage(argv[0]);
+ }
+ }
+
+ /*
+ * If stat() failed then continue and test the failure
+ * path in directory loading. The failure path in
+ * file loading can already be tested with the
+ * mandatory 1st file argument.
+ */
+ if (stat_failed || S_ISDIR(st.st_mode)) {
+ status = ctdb_tunable_load_directory(mem_ctx,
+ &tun_list,
+ argv[2]);
+ } else {
+ status = ctdb_tunable_load_file(mem_ctx,
+ &tun_list,
+ argv[2]);
+ }
if (!status) {
ret = EINVAL;
goto done;
list = ctdb_tunable_names(mem_ctx);
assert(list != NULL);
+ ret = 0;
for (i = 0; i < list->count; i++) {
const char *var = list->var[i];
uint32_t val;