Move C API tests out of root build dir into 'capitests' subdir.
[libguestfs.git] / src / generator.ml
index 5eb6122..6741541 100755 (executable)
@@ -153,6 +153,11 @@ can easily destroy all your data>."
  * skipped.  Useful if testing a command which might not work on
  * all variations of libguestfs builds.  A test that has prerequisite
  * of 'Always' is run unconditionally.
+ *
+ * In addition, packagers can skip individual tests by setting the
+ * environment variables:     eg:
+ *   SKIP_TEST_<CMD>_<NUM>=1  SKIP_TEST_COMMAND_3=1  (skips test #3 of command)
+ *   SKIP_TEST_<CMD>=1        SKIP_TEST_ZEROFREE=1   (skips all zerofree tests)
  *)
 type tests = (test_init * test_prereq * test) list
 and test =
@@ -240,11 +245,6 @@ and test_init =
 and seq = cmd list
 and cmd = string list
 
-(* Canned test prerequisites. *)
-let env_is_true env =
-  sprintf "const char *str = getenv (\"%s\");
-  return str && strcmp (str, \"1\") == 0;" env
-
 (* Note about long descriptions: When referring to another
  * action, use the format C<guestfs_other> (ie. the full name of
  * the C function).  This will be replaced as appropriate in other
@@ -1192,51 +1192,51 @@ particular that the filename is not prepended to the output
 (the C<-b> option).");
 
   ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
-   [InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
+   [InitBasicFS, Always, TestOutput (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command"; "/test-command 1"]], "Result1");
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
+    InitBasicFS, Always, TestOutput (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command"; "/test-command 2"]], "Result2\n");
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
+    InitBasicFS, Always, TestOutput (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command"; "/test-command 3"]], "\nResult3");
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
+    InitBasicFS, Always, TestOutput (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command"; "/test-command 4"]], "\nResult4\n");
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
+    InitBasicFS, Always, TestOutput (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command"; "/test-command 5"]], "\nResult5\n\n");
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
+    InitBasicFS, Always, TestOutput (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command"; "/test-command 6"]], "\n\nResult6\n\n");
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
+    InitBasicFS, Always, TestOutput (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command"; "/test-command 7"]], "");
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
+    InitBasicFS, Always, TestOutput (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command"; "/test-command 8"]], "\n");
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
+    InitBasicFS, Always, TestOutput (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command"; "/test-command 9"]], "\n\n");
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
+    InitBasicFS, Always, TestOutput (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput (
+    InitBasicFS, Always, TestOutput (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestLastFail (
+    InitBasicFS, Always, TestLastFail (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command"; "/test-command"]])],
@@ -1271,47 +1271,47 @@ all filesystems that are needed are mounted at the right
 locations.");
 
   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
-   [InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
+   [InitBasicFS, Always, TestOutputList (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command_lines"; "/test-command 1"]], ["Result1"]);
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
+    InitBasicFS, Always, TestOutputList (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command_lines"; "/test-command 2"]], ["Result2"]);
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
+    InitBasicFS, Always, TestOutputList (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command_lines"; "/test-command 3"]], ["";"Result3"]);
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
+    InitBasicFS, Always, TestOutputList (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command_lines"; "/test-command 4"]], ["";"Result4"]);
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
+    InitBasicFS, Always, TestOutputList (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
+    InitBasicFS, Always, TestOutputList (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
+    InitBasicFS, Always, TestOutputList (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command_lines"; "/test-command 7"]], []);
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
+    InitBasicFS, Always, TestOutputList (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command_lines"; "/test-command 8"]], [""]);
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
+    InitBasicFS, Always, TestOutputList (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command_lines"; "/test-command 9"]], ["";""]);
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
+    InitBasicFS, Always, TestOutputList (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
-    InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList (
+    InitBasicFS, Always, TestOutputList (
       [["upload"; "test-command"; "/test-command"];
        ["chmod"; "493"; "/test-command"];
        ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
@@ -2006,7 +2006,7 @@ This runs C<hexdump -C> on the given C<path>.  The result is
 the human-readable, canonical hex dump of the file.");
 
   ("zerofree", (RErr, [String "device"]), 97, [],
-   [InitNone, Unless (env_is_true "SKIP_ZEROFREE"), TestOutput (
+   [InitNone, Always, TestOutput (
       [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
        ["mkfs"; "ext3"; "/dev/sda1"];
        ["mount"; "/dev/sda1"; "/"];
@@ -2114,6 +2114,7 @@ are activated or deactivated.");
      ["write_file"; "/new"; "test content"; "0"];
      ["umount"; "/"];
      ["lvresize"; "/dev/VG/LV"; "20"];
+     ["e2fsck_f"; "/dev/VG/LV"];
      ["resize2fs"; "/dev/VG/LV"];
      ["mount"; "/dev/VG/LV"; "/"];
      ["cat"; "/new"]], "test content")],
@@ -2128,7 +2129,13 @@ is lost.");
    "resize an ext2/ext3 filesystem",
    "\
 This resizes an ext2 or ext3 filesystem to match the size of
-the underlying device.");
+the underlying device.
+
+I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
+on the C<device> before calling this command.  For unknown reasons
+C<resize2fs> sometimes gives an error about this and sometimes not.
+In any case, it is always safe to call C<guestfs_e2fsck_f> before
+calling this function.");
 
   ("find", (RStringList "names", [String "directory"]), 107, [],
    [InitBasicFS, Always, TestOutputList (
@@ -2169,6 +2176,17 @@ an error.
 
 The returned list is sorted.");
 
+  ("e2fsck_f", (RErr, [String "device"]), 108, [],
+   [], (* lvresize tests this *)
+   "check an ext2/ext3 filesystem",
+   "\
+This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
+filesystem checker on C<device>, noninteractively (C<-p>),
+even if the filesystem appears to be clean (C<-f>).
+
+This command is only needed because of C<guestfs_resize2fs>
+(q.v.).  Normally you should use C<guestfs_fsck>.");
+
 ]
 
 let all_functions = non_daemon_functions @ daemon_functions
@@ -3699,10 +3717,7 @@ int main (int argc, char *argv[])
 
   guestfs_set_error_handler (g, print_error, NULL);
 
-  srcdir = getenv (\"srcdir\");
-  if (!srcdir) srcdir = \".\";
-  chdir (srcdir);
-  guestfs_set_path (g, \".\");
+  guestfs_set_path (g, \"../appliance\");
 
   filename = \"test1.img\";
   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
@@ -3852,6 +3867,20 @@ int main (int argc, char *argv[])
 and generate_one_test name i (init, prereq, test) =
   let test_name = sprintf "test_%s_%d" name i in
 
+  pr "\
+static int %s_skip (void)
+{
+  const char *str;
+
+  str = getenv (\"SKIP_%s\");
+  if (str && strcmp (str, \"1\") == 0) return 1;
+  str = getenv (\"SKIP_TEST_%s\");
+  if (str && strcmp (str, \"1\") == 0) return 1;
+  return 0;
+}
+
+" test_name (String.uppercase test_name) (String.uppercase name);
+
   (match prereq with
    | Disabled | Always -> ()
    | If code | Unless code ->
@@ -3862,22 +3891,33 @@ and generate_one_test name i (init, prereq, test) =
        pr "\n";
   );
 
-  pr "static int %s (void)\n" test_name;
-  pr "{\n";
+  pr "\
+static int %s (void)
+{
+  if (%s_skip ()) {
+    printf (\"%%s skipped (reason: SKIP_TEST_* variable set)\\n\", \"%s\");
+    return 0;
+  }
+
+" test_name test_name test_name;
 
   (match prereq with
    | Disabled ->
        pr "  printf (\"%%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
    | If _ ->
-       pr "  if (%s_prereq ()) {\n" test_name;
+       pr "  if (! %s_prereq ()) {\n" test_name;
+       pr "    printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
+       pr "    return 0;\n";
+       pr "  }\n";
+       pr "\n";
        generate_one_test_body name i test_name init test;
-       pr "  } else\n";
-       pr "    printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name
    | Unless _ ->
-       pr "  if (! %s_prereq ()) {\n" test_name;
+       pr "  if (%s_prereq ()) {\n" test_name;
+       pr "    printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
+       pr "    return 0;\n";
+       pr "  }\n";
+       pr "\n";
        generate_one_test_body name i test_name init test;
-       pr "  } else\n";
-       pr "    printf (\"%%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name
    | Always ->
        generate_one_test_body name i test_name init test
   );
@@ -4551,9 +4591,12 @@ and generate_fish_completion () =
 #ifdef HAVE_LIBREADLINE
 
 static const char *const commands[] = {
+  BUILTIN_COMMANDS_FOR_COMPLETION,
 ";
 
-  (* Get the commands and sort them, including the aliases. *)
+  (* Get the commands, including the aliases.  They don't need to be
+   * sorted - the generator() function just does a dumb linear search.
+   *)
   let commands =
     List.map (
       fun (name, _, _, flags, _, _, _) ->
@@ -4565,7 +4608,6 @@ static const char *const commands[] = {
        if name <> alias then [name2; alias] else [name2]
     ) all_functions in
   let commands = List.flatten commands in
-  let commands = List.sort compare commands in
 
   List.iter (pr "  \"%s\",\n") commands;
 
@@ -6447,11 +6489,16 @@ public class GuestFS {
          doc ^ "\n\n" ^ danger_will_robinson
        else doc in
       let doc = pod2text ~width:60 name doc in
+      let doc = List.map (             (* RHBZ#501883 *)
+       function
+       | "" -> "<p>"
+       | nonempty -> nonempty
+      ) doc in
       let doc = String.concat "\n   * " doc in
 
       pr "  /**\n";
       pr "   * %s\n" shortdesc;
-      pr "   *\n";
+      pr "   * <p>\n";
       pr "   * %s\n" doc;
       pr "   * @throws LibGuestFSException\n";
       pr "   */\n";
@@ -7132,7 +7179,7 @@ Run it from the top source directory using the command
   generate_daemon_actions ();
   close ();
 
-  let close = output_to "tests.c" in
+  let close = output_to "capitests/tests.c" in
   generate_tests ();
   close ();