Commit 2766b92de755871b666217912d865c46ed289011

Patrick Steinhardt 2019-07-21T15:10:34

config_file: refresh when creating an iterator When creating a new iterator for a config file backend, then we should always make sure that we're up to date by calling `config_refresh`. Otherwise, we might not notice when another process has modified the configuration file and thus will represent outdated values. Add two tests to config::stress that verify that we get up-to-date values when reading configuration entries via `git_config_iterator`.

diff --git a/src/config_file.c b/src/config_file.c
index 1b674b1..88bba90 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -270,13 +270,12 @@ static int config_iterator_new(
 	struct git_config_backend *backend)
 {
 	diskfile_header *bh = GIT_CONTAINER_OF(backend, diskfile_header, parent);
-	git_config_entries *entries;
+	git_config_entries *entries = NULL;
 	int error;
 
-	if ((error = git_config_entries_dup(&entries, bh->entries)) < 0)
-		return error;
-
-	if ((error = git_config_entries_iterator_new(iter, entries)) < 0)
+	if ((error = config_refresh(backend)) < 0 ||
+	    (error = git_config_entries_dup(&entries, bh->entries)) < 0 ||
+	    (error = git_config_entries_iterator_new(iter, entries)) < 0)
 		goto out;
 
 out:
diff --git a/tests/config/stress.c b/tests/config/stress.c
index 4fb0f3b..4ee234f 100644
--- a/tests/config/stress.c
+++ b/tests/config/stress.c
@@ -131,3 +131,48 @@ void test_config_stress__quick_write(void)
 	git_config_free(config_r);
 	git_config_free(config_w);
 }
+
+static int foreach_cb(const git_config_entry *entry, void *payload)
+{
+	if (!strcmp(entry->name, "key.value")) {
+		*(char **)payload = git__strdup(entry->value);
+		return 0;
+	}
+	return -1;
+}
+
+void test_config_stress__foreach_refreshes(void)
+{
+	git_config *config_w, *config_r;
+	char *value = NULL;
+
+	cl_git_pass(git_config_open_ondisk(&config_w, "./cfg"));
+	cl_git_pass(git_config_open_ondisk(&config_r, "./cfg"));
+
+	cl_git_pass(git_config_set_string(config_w, "key.value", "1"));
+	cl_git_pass(git_config_foreach_match(config_r, "key.value", foreach_cb, &value));
+
+	cl_assert_equal_s(value, "1");
+
+	git_config_free(config_r);
+	git_config_free(config_w);
+	git__free(value);
+}
+
+void test_config_stress__foreach_refreshes_snapshot(void)
+{
+	git_config *config, *snapshot;
+	char *value = NULL;
+
+	cl_git_pass(git_config_open_ondisk(&config, "./cfg"));
+
+	cl_git_pass(git_config_set_string(config, "key.value", "1"));
+	cl_git_pass(git_config_snapshot(&snapshot, config));
+	cl_git_pass(git_config_foreach_match(snapshot, "key.value", foreach_cb, &value));
+
+	cl_assert_equal_s(value, "1");
+
+	git_config_free(snapshot);
+	git_config_free(config);
+	git__free(value);
+}