git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 01/11] t: add helpers to test for reference existence

From
Patrick Steinhardt <ps@pks.im>
Date
Oct 18, 2023, 05:35 UTC
Message-ID
<e947feb1c77f7e9f3c7f983bbe47137fbce42367.1697607222.git.ps@pks.im>
In-Reply-To
<cover.1697607222.git.ps@pks.im>

There are two major ways to check for the existence of a reference in our tests:

    - `git rev-parse --verify` can be used to check for existence of a
      reference. This only works in the case where the reference is well
      formed though and resolves to an actual object ID. This does not
      work with malformed reference names or invalid contents.
    - `test_path_is_file` can be used to check for existence of a loose
      reference if it is known to not resolve to an actual object ID. It
      by necessity reaches into implementation details of the reference
      backend though.

Similarly, there are two equivalent ways to check for the absence of a reference:

    - `test_must_fail git rev-parse` can be used to check for the
      absence of a reference. It could fail due to a number of reasons
      though, and all of these reasons will be thrown into the same bag
      as an absent reference.
    - `test_path_is_missing` can be used to check explicitly for the
      absence of a loose reference, but again reaches into internal
      implementation details of the reference backend.

So both our tooling to check for the presence and for the absence of references in tests is lacking as either failure cases are thrown into the same bag or we need to reach into internal implementation details of the respective reference backend.

Introduce a new subcommand for our ref-store test helper that explicitly checks only for the presence or absence of a reference. This addresses these limitations:

    - We can check for the presence of references with malformed names.
    - We can check for the presence of references that don't resolve.
    - We can explicitly handle the case where a reference is missing by
      special-casing ENOENT errors.
    - We don't need to reach into implementation details of the backend,
      which would allow us to use this helper for the future reftable
      backend.

Next to this subcommand we also provide two wrappers `test_ref_exists` and `test_ref_missing` that make the helper easier to use.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 t/README                  |  9 ++++++
 t/helper/test-ref-store.c | 27 +++++++++++++++-
 t/test-lib-functions.sh   | 66 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 101 insertions(+), 1 deletion(-)
diff --git a/t/README b/t/README
index 61080859899..779f7e7dd86 100644
--- a/t/README
+++ b/t/README
@@ -928,6 +928,15 @@ see test-lib-functions.sh for the full list and their options.
    committer times to defined state.  Subsequent calls will
    advance the times by a fixed amount.
 
+ - test_ref_exists <ref>, test_ref_missing <ref>
+
+   Check whether a reference exists or is missing. In contrast to
+   git-rev-parse(1), these helpers also work with invalid reference
+   names and references whose contents are unresolvable. The latter
+   function also distinguishes generic errors from the case where a
+   reference explicitly doesn't exist and is thus safer to use than
+   `test_must_fail git rev-parse`.
+
  - test_commit <message> [<filename> [<contents>]]
 
    Creates a commit with the given message, committing the given
diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c
index 48552e6a9e0..7400f560ab6 100644
--- a/t/helper/test-ref-store.c
+++ b/t/helper/test-ref-store.c
@@ -1,6 +1,6 @@
 #include "test-tool.h"
 #include "hex.h"
-#include "refs.h"
+#include "refs/refs-internal.h"
 #include "setup.h"
 #include "worktree.h"
 #include "object-store-ll.h"
@@ -221,6 +221,30 @@ static int cmd_verify_ref(struct ref_store *refs, const char **argv)
 	return ret;
 }
 
+static int cmd_ref_exists(struct ref_store *refs, const char **argv)
+{
+	const char *refname = notnull(*argv++, "refname");
+	struct strbuf unused_referent = STRBUF_INIT;
+	struct object_id unused_oid;
+	unsigned int unused_type;
+	int failure_errno;
+
+	if (refs_read_raw_ref(refs, refname, &unused_oid, &unused_referent,
+			      &unused_type, &failure_errno)) {
+		/*
+		 * We handle ENOENT separately here such that it is possible to
+		 * distinguish actually-missing references from any kind of
+		 * generic error.
+		 */
+		if (failure_errno == ENOENT)
+			return 17;
+		return -1;
+	}
+
+	strbuf_release(&unused_referent);
+	return 0;
+}
+
 static int cmd_for_each_reflog(struct ref_store *refs,
 			       const char **argv UNUSED)
 {
@@ -325,6 +349,7 @@ static struct command commands[] = {
 	{ "for-each-ref--exclude", cmd_for_each_ref__exclude },
 	{ "resolve-ref", cmd_resolve_ref },
 	{ "verify-ref", cmd_verify_ref },
+	{ "ref-exists", cmd_ref_exists },
 	{ "for-each-reflog", cmd_for_each_reflog },
 	{ "for-each-reflog-ent", cmd_for_each_reflog_ent },
 	{ "for-each-reflog-ent-reverse", cmd_for_each_reflog_ent_reverse },
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 2f8868caa17..212fddffa96 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -251,6 +251,72 @@ debug () {
 	done
 }
 
+# Usage: test_ref_exists [options] <ref>
+#   -C <dir>:
+#	Run all git commands in directory <dir>
+#   --refdb <refdb>:
+#	The reference database to run in. One of:
+#		- "main", the main reference database (default).
+#		- "submodule:<submodule>", the reference database of a
+#		  submodule.
+#		- "worktree:<worktree>", the reference database for a
+#		  worktree's per-worktree references.
+#
+# This helper function checks whether a reference exists. Symrefs will not be
+# resolved. Can be used to check references with bad names.
+test_ref_exists () {
+	local indir=
+	local refdb=main
+
+	while test $# != 0
+	do
+		case "$1" in
+		-C)
+			indir="$2"
+			shift
+			;;
+		--refdb)
+			refdb="$2"
+			shift
+			;;
+		*)
+			break
+			;;
+		esac
+		shift
+	done &&
+
+	indir=${indir:+"$indir"/} &&
+
+	if test "$#" != 1
+	then
+		BUG "expected exactly one reference"
+	fi &&
+
+	test-tool ${indir:+ -C "$indir"} ref-store "${refdb}" ref-exists "$1"
+}
+
+# Behaves the same as test_ref_exists, except that it checks for the absence of
+# a reference. This is preferable to `! test_ref_exists` as this function is
+# able to distinguish actually-missing references from other, generic errors.
+test_ref_missing () {
+	test_ref_exists "$@"
+	case "$?" in
+	17)
+		# This is the good case.
+		return 0
+		;;
+	0)
+		echo >&4 "test_ref_missing: reference exists"
+		return 1
+		;;
+	*)
+		echo >&4 "test_ref_missing: generic error"
+		return 1
+		;;
+	esac
+}
+
 # Usage: test_commit [options] <message> [<file> [<contents> [<tag>]]]
 #   -C <dir>:
 #	Run all git commands in directory <dir>
-- 
2.42.0
Previous: Patrick SteinhardtNext: Junio C Hamano
Message 2 of 59 in “t: reduce direct disk access to data structures”
  1. 00/11 t: reduce direct disk access to data structuresPatrick Steinhardt, Oct 18, 2023
  2. 01/11 t: add helpers to test for reference existencePatrick Steinhardt, Oct 18, 2023
  3. Junio C HamanoOct 18, 2023
  4. Patrick SteinhardtOct 23, 2023
  5. Eric SunshineOct 18, 2023
  6. Patrick SteinhardtOct 23, 2023
  7. 02/11 t: allow skipping expected object ID in `ref-store update-ref`Patrick Steinhardt, Oct 18, 2023
  8. Junio C HamanoOct 18, 2023
  9. Patrick SteinhardtOct 23, 2023
  10. Junio C HamanoOct 23, 2023
  11. 03/11 t: convert tests to use helpers for reference existencePatrick Steinhardt, Oct 18, 2023
  12. Junio C HamanoOct 18, 2023
  13. 04/11 t: convert tests to not write references via the filesystemPatrick Steinhardt, Oct 18, 2023
  14. Junio C HamanoOct 18, 2023
  15. Patrick SteinhardtOct 23, 2023
  16. Junio C HamanoOct 23, 2023
  17. Junio C HamanoOct 18, 2023
  18. Patrick SteinhardtOct 23, 2023
  19. 05/11 t: convert tests to not access symrefs via the filesystemPatrick Steinhardt, Oct 18, 2023
  20. Junio C HamanoOct 20, 2023
  21. 06/11 t: convert tests to not access reflog via the filesystemPatrick Steinhardt, Oct 18, 2023
  22. Junio C HamanoOct 21, 2023
  23. 07/11 t1450: convert tests to remove worktrees via git-worktree(1)Patrick Steinhardt, Oct 18, 2023
  24. 08/11 t4207: delete replace references via git-update-ref(1)Patrick Steinhardt, Oct 18, 2023
  25. Han-Wen NienhuysOct 18, 2023
  26. Patrick SteinhardtOct 23, 2023
  27. Taylor BlauOct 23, 2023
  28. Patrick SteinhardtOct 24, 2023
  29. 09/11 t7300: assert exact states of repoPatrick Steinhardt, Oct 18, 2023
  30. 10/11 t7900: assert the absence of refs via git-for-each-ref(1)Patrick Steinhardt, Oct 18, 2023
  31. 11/11 t: mark several tests that assume the files backend with REFFILESPatrick Steinhardt, Oct 18, 2023
  32. Patrick SteinhardtOct 18, 2023
  33. Junio C HamanoOct 18, 2023
  34. Patrick SteinhardtOct 23, 2023
  35. Junio C HamanoOct 18, 2023
  36. Han-Wen NienhuysOct 19, 2023
  37. Junio C HamanoOct 19, 2023
  38. Patrick SteinhardtOct 23, 2023
  39. 0/9 t: reduce direct disk access to data structuresPatrick Steinhardt, Oct 24, 2023
  40. 1/9 t: allow skipping expected object ID in `ref-store update-ref`Patrick Steinhardt, Oct 24, 2023
  41. 2/9 t: convert tests to not write references via the filesystemPatrick Steinhardt, Oct 24, 2023
  42. 3/9 t: convert tests to not access symrefs via the filesystemPatrick Steinhardt, Oct 24, 2023
  43. 4/9 t: convert tests to not access reflog via the filesystemPatrick Steinhardt, Oct 24, 2023
  44. 5/9 t1450: convert tests to remove worktrees via git-worktree(1)Patrick Steinhardt, Oct 24, 2023
  45. Eric SunshineOct 27, 2023
  46. 6/9 t4207: delete replace references via git-update-ref(1)Patrick Steinhardt, Oct 24, 2023
  47. 7/9 t7300: assert exact states of repoPatrick Steinhardt, Oct 24, 2023
  48. 8/9 t7900: assert the absence of refs via git-for-each-ref(1)Patrick Steinhardt, Oct 24, 2023
  49. 9/9 t: mark several tests that assume the files backend with REFFILESPatrick Steinhardt, Oct 24, 2023
  50. 0/9 t: reduce direct disk access to data structuresPatrick Steinhardt, Nov 2, 2023
  51. 1/9 t: allow skipping expected object ID in `ref-store update-ref`Patrick Steinhardt, Nov 2, 2023
  52. 2/9 t: convert tests to not write references via the filesystemPatrick Steinhardt, Nov 2, 2023
  53. 3/9 t: convert tests to not access symrefs via the filesystemPatrick Steinhardt, Nov 2, 2023
  54. 4/9 t: convert tests to not access reflog via the filesystemPatrick Steinhardt, Nov 2, 2023
  55. 5/9 t1450: convert tests to remove worktrees via git-worktree(1)Patrick Steinhardt, Nov 2, 2023
  56. 6/9 t4207: delete replace references via git-update-ref(1)Patrick Steinhardt, Nov 2, 2023
  57. 7/9 t7300: assert exact states of repoPatrick Steinhardt, Nov 2, 2023
  58. 8/9 t7900: assert the absence of refs via git-for-each-ref(1)Patrick Steinhardt, Nov 2, 2023
  59. 9/9 t: mark several tests that assume the files backend with REFFILESPatrick Steinhardt, Nov 2, 2023

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.