From 4206d681c5c52691dec0074e3f8c32dab1953a94 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 21 May 2021 17:41:31 +0100 Subject: [PATCH] test-context: Exercise some corner cases for merging filesystems Signed-off-by: Simon McVittie Co-authored-by: Alexander Larsson (cherry picked from commit fab0f8ed7c52fc58e6c550d123ede9621c760ca7) [smcv: Also backport the scaffolding to create this test-case] --- tests/Makefile.am.inc | 11 +- tests/test-context.c | 343 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 353 insertions(+), 1 deletion(-) create mode 100644 tests/test-context.c diff --git a/tests/Makefile.am.inc b/tests/Makefile.am.inc index 53d6403e4c..0fb650cb38 100644 --- a/tests/Makefile.am.inc +++ b/tests/Makefile.am.inc @@ -66,6 +66,10 @@ testcommon_LDADD = \ $(NULL) testcommon_SOURCES = tests/testcommon.c +test_context_CFLAGS = $(testcommon_CFLAGS) +test_context_LDADD = $(testcommon_LDADD) +test_context_SOURCES = tests/test-context.c + test_exports_CFLAGS = $(testcommon_CFLAGS) test_exports_LDADD = $(testcommon_LDADD) test_exports_SOURCES = tests/test-exports.c @@ -252,7 +256,12 @@ test_scripts = ${TEST_MATRIX} dist_test_scripts = ${TEST_MATRIX_DIST} dist_installed_test_extra_scripts += ${TEST_MATRIX_EXTRA_DIST} -test_programs = testlibrary testcommon test-exports +test_programs = \ + test-context \ + test-exports \ + testcommon \ + testlibrary \ + $(NULL) test_extra_programs = tests/httpcache tests/test-update-portal tests/test-portal-impl tests/test-authenticator tests/list-unused @VALGRIND_CHECK_RULES@ diff --git a/tests/test-context.c b/tests/test-context.c new file mode 100644 index 0000000000..c128a83fae --- /dev/null +++ b/tests/test-context.c @@ -0,0 +1,343 @@ +/* + * Copyright © 2021 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include + +#include +#include "flatpak.h" +#include "flatpak-context-private.h" +#include "flatpak-run-private.h" +#include "flatpak-utils-private.h" + +/* g_str_has_prefix as a GEqualFunc */ +static gboolean +str_has_prefix (gconstpointer candidate, + gconstpointer pattern) +{ + return g_str_has_prefix (candidate, pattern); +} + +static void context_parse_args (FlatpakContext *context, + ...) G_GNUC_NULL_TERMINATED; + +static void +context_parse_args (FlatpakContext *context, + ...) +{ + g_autoptr(GError) local_error = NULL; + g_autoptr(GOptionContext) oc = NULL; + g_autoptr(GOptionGroup) group = NULL; + g_autoptr(GPtrArray) args = g_ptr_array_new_with_free_func (g_free); + g_auto(GStrv) argv = NULL; + const char *arg; + va_list ap; + + g_ptr_array_add (args, g_strdup ("argv[0]")); + + va_start (ap, context); + + while ((arg = va_arg (ap, const char *)) != NULL) + g_ptr_array_add (args, g_strdup (arg)); + + va_end (ap); + + g_ptr_array_add (args, NULL); + argv = (GStrv) g_ptr_array_free (g_steal_pointer (&args), FALSE); + + oc = g_option_context_new (""); + group = flatpak_context_get_options (context); + g_option_context_add_group (oc, group); + g_option_context_parse_strv (oc, &argv, &local_error); + g_assert_no_error (local_error); +} + +static void +test_context_merge_fs (void) +{ + /* + * We want to arrive at the same result regardless of whether we: + * - start from lowest precedence, and successively merge higher + * precedences into it, discarding them when done; + * - successively merge highest precedence into second-highest, and + * then discard highest + */ + enum { LOWEST_FIRST, HIGHEST_FIRST, INVALID } merge_order; + + for (merge_order = LOWEST_FIRST; merge_order < INVALID; merge_order++) + { + g_autoptr(FlatpakContext) lowest = flatpak_context_new (); + g_autoptr(FlatpakContext) middle = flatpak_context_new (); + g_autoptr(FlatpakContext) highest = flatpak_context_new (); + gpointer value; + + context_parse_args (lowest, + "--filesystem=/one", + NULL); + context_parse_args (middle, + "--nofilesystem=host:reset", + "--filesystem=/two", + NULL); + context_parse_args (highest, + "--nofilesystem=host", + "--filesystem=/three", + NULL); + + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, NULL)); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/one", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/two", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/three", NULL, NULL)); + + g_assert_true (g_hash_table_lookup_extended (middle->filesystems, "host", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_true (g_hash_table_lookup_extended (middle->filesystems, "host-reset", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_false (g_hash_table_lookup_extended (middle->filesystems, "/one", NULL, NULL)); + g_assert_true (g_hash_table_lookup_extended (middle->filesystems, "/two", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_false (g_hash_table_lookup_extended (middle->filesystems, "/three", NULL, NULL)); + + g_assert_true (g_hash_table_lookup_extended (highest->filesystems, "host", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_false (g_hash_table_lookup_extended (highest->filesystems, "host-reset", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (highest->filesystems, "/one", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (highest->filesystems, "/two", NULL, NULL)); + g_assert_true (g_hash_table_lookup_extended (highest->filesystems, "/three", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + + if (merge_order == LOWEST_FIRST) + { + flatpak_context_merge (lowest, middle); + + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/one", NULL, NULL)); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/two", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/three", NULL, NULL)); + + flatpak_context_merge (lowest, highest); + } + else + { + flatpak_context_merge (middle, highest); + + g_assert_true (g_hash_table_lookup_extended (middle->filesystems, "host", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_true (g_hash_table_lookup_extended (middle->filesystems, "host-reset", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_false (g_hash_table_lookup_extended (middle->filesystems, "/one", NULL, NULL)); + g_assert_true (g_hash_table_lookup_extended (middle->filesystems, "/two", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_true (g_hash_table_lookup_extended (middle->filesystems, "/three", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + + flatpak_context_merge (lowest, middle); + } + + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/one", NULL, NULL)); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/two", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/three", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + } + + for (merge_order = LOWEST_FIRST; merge_order < INVALID; merge_order++) + { + g_autoptr(FlatpakContext) lowest = flatpak_context_new (); + g_autoptr(FlatpakContext) mid_low = flatpak_context_new (); + g_autoptr(FlatpakContext) mid_high = flatpak_context_new (); + g_autoptr(FlatpakContext) highest = flatpak_context_new (); + g_autoptr(GError) local_error = NULL; + g_autoptr(GKeyFile) metakey = g_key_file_new (); + g_autoptr(GPtrArray) args = g_ptr_array_new_with_free_func (g_free); + g_autofree char *filesystems = NULL; + gpointer value; + + context_parse_args (lowest, + "--filesystem=/one", + NULL); + context_parse_args (mid_low, + "--nofilesystem=host:reset", + "--filesystem=/two", + NULL); + context_parse_args (mid_high, + "--filesystem=host", + "--filesystem=/three", + NULL); + context_parse_args (highest, + "--nofilesystem=host", + "--filesystem=/four", + NULL); + + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, NULL)); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/one", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/two", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/three", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/four", NULL, NULL)); + + g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "host", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "host-reset", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_false (g_hash_table_lookup_extended (mid_low->filesystems, "/one", NULL, NULL)); + g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "/two", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_false (g_hash_table_lookup_extended (mid_low->filesystems, "/three", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (mid_low->filesystems, "/four", NULL, NULL)); + + g_assert_true (g_hash_table_lookup_extended (mid_high->filesystems, "host", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "host-reset", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "/one", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "/two", NULL, NULL)); + g_assert_true (g_hash_table_lookup_extended (mid_high->filesystems, "/three", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "/four", NULL, NULL)); + + g_assert_true (g_hash_table_lookup_extended (highest->filesystems, "host", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "host-reset", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (highest->filesystems, "/one", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (highest->filesystems, "/two", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (highest->filesystems, "/three", NULL, NULL)); + g_assert_true (g_hash_table_lookup_extended (highest->filesystems, "/four", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + + if (merge_order == LOWEST_FIRST) + { + flatpak_context_merge (lowest, mid_low); + + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/one", NULL, NULL)); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/two", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/three", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/four", NULL, NULL)); + + flatpak_context_merge (lowest, mid_high); + + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/one", NULL, NULL)); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/two", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/three", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/four", NULL, NULL)); + + flatpak_context_merge (lowest, highest); + } + else + { + flatpak_context_merge (mid_high, highest); + + g_assert_true (g_hash_table_lookup_extended (mid_high->filesystems, "host", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "host-reset", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "/one", NULL, NULL)); + g_assert_false (g_hash_table_lookup_extended (mid_high->filesystems, "/two", NULL, NULL)); + g_assert_true (g_hash_table_lookup_extended (mid_high->filesystems, "/three", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_true (g_hash_table_lookup_extended (mid_high->filesystems, "/four", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + + flatpak_context_merge (mid_low, mid_high); + + g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "host", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "host-reset", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_false (g_hash_table_lookup_extended (mid_low->filesystems, "/one", NULL, NULL)); + g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "/two", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "/three", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_true (g_hash_table_lookup_extended (mid_low->filesystems, "/four", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + + flatpak_context_merge (lowest, mid_low); + } + + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "host-reset", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_NONE); + g_assert_false (g_hash_table_lookup_extended (lowest->filesystems, "/one", NULL, NULL)); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/two", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/three", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + g_assert_true (g_hash_table_lookup_extended (lowest->filesystems, "/four", NULL, &value)); + g_assert_cmpint (GPOINTER_TO_INT (value), ==, FLATPAK_FILESYSTEM_MODE_READ_WRITE); + + flatpak_context_save_metadata (lowest, FALSE, metakey); + filesystems = g_key_file_get_value (metakey, + FLATPAK_METADATA_GROUP_CONTEXT, + FLATPAK_METADATA_KEY_FILESYSTEMS, + &local_error); + g_assert_no_error (local_error); + g_test_message ("%s=%s", FLATPAK_METADATA_KEY_FILESYSTEMS, filesystems); + /* !host:reset is serialized first */ + g_assert_true (g_str_has_prefix (filesystems, "!host:reset;")); + /* The rest are serialized in arbitrary order */ + g_assert_nonnull (strstr (filesystems, ";!host;")); + g_assert_null (strstr (filesystems, "/one")); + g_assert_nonnull (strstr (filesystems, ";/two;")); + g_assert_nonnull (strstr (filesystems, ";/three;")); + g_assert_nonnull (strstr (filesystems, ";/four;")); + + flatpak_context_to_args (lowest, args); + /* !host:reset is serialized first */ + g_assert_cmpuint (args->len, >, 0); + g_assert_cmpstr (g_ptr_array_index (args, 0), ==, + "--nofilesystem=host:reset"); + /* The rest are serialized in arbitrary order */ + g_assert_true (g_ptr_array_find_with_equal_func (args, "--nofilesystem=host", g_str_equal, NULL)); + g_assert_false (g_ptr_array_find_with_equal_func (args, "--filesystem=/one", str_has_prefix, NULL)); + g_assert_false (g_ptr_array_find_with_equal_func (args, "--nofilesystem=/one", str_has_prefix, NULL)); + g_assert_true (g_ptr_array_find_with_equal_func (args, "--filesystem=/two", g_str_equal, NULL)); + g_assert_true (g_ptr_array_find_with_equal_func (args, "--filesystem=/three", g_str_equal, NULL)); + g_assert_true (g_ptr_array_find_with_equal_func (args, "--filesystem=/four", g_str_equal, NULL)); + } +} + +int +main (int argc, char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/context/merge-fs", test_context_merge_fs); + + return g_test_run (); +}