test: Add test for update-portal monitoring

We add socat to the test runtime, and then we use that to run a
test app outside the sandbox as if it was inside.

The testcase connects creates a monitor and ensure we properly get signals
for updates.
This commit is contained in:
Alexander Larsson 2019-09-27 16:39:58 +02:00 committed by Alexander Larsson
parent 82328bee85
commit c15c1946ff
8 changed files with 295 additions and 5 deletions

1
.gitignore vendored
View File

@ -58,6 +58,7 @@ common/flatpak-enum-types.c
common/flatpak-enum-types.h
test-libflatpak
httpcache
test-update-portal
revokefs-fuse
revokefs-demo
Flatpak-1.0.*

View File

@ -1,4 +1,4 @@
[D-BUS Service]
Name=org.freedesktop.portal.Flatpak
Exec=@libexecdir@/flatpak-portal
Exec=@libexecdir@/flatpak-portal@extraargs@
SystemdService=flatpak-portal.service

View File

@ -35,6 +35,7 @@ TEST_MATRIX_DIST= \
tests/test-unsigned-summaries.sh \
tests/test-update-remote-configuration.sh \
tests/test-override.sh \
tests/test-update-portal.sh \
$(NULL)
TEST_MATRIX_EXTRA_DIST= \
tests/test-run.sh \

View File

@ -62,19 +62,31 @@ testcommon_SOURCES = tests/testcommon.c
tests_httpcache_CFLAGS = $(AM_CFLAGS) $(BASE_CFLAGS) $(OSTREE_CFLAGS) $(SOUP_CFLAGS) $(JSON_CFLAGS) $(APPSTREAM_GLIB_CFLAGS) \
-DFLATPAK_COMPILATION \
-DLOCALEDIR=\"$(localedir)\"
-DLOCALEDIR=\"$(localedir)\"
tests_httpcache_LDADD = $(AM_LDADD) $(BASE_LIBS) $(OSTREE_LIBS) $(SOUP_LIBS) $(JSON_LIBS) $(APPSTREAM_GLIB_LIBS) \
libflatpak-common.la libflatpak-common-base.la libglnx.la
tests_test_update_portal_CFLAGS = $(AM_CFLAGS) $(BASE_CFLAGS) \
-DFLATPAK_COMPILATION \
-DLOCALEDIR=\"$(localedir)\"
tests_test_update_portal_LDADD = $(AM_LDADD) $(BASE_LIBS)
tests_test_update_portal_SOURCES = \
tests/test-update-portal.c \
portal/flatpak-portal-dbus.c
tests/services/org.freedesktop.Flatpak.service: session-helper/org.freedesktop.Flatpak.service.in
mkdir -p tests/services
$(AM_V_GEN) $(SED) -e "s|\@libexecdir\@|$(abs_top_builddir)|" $< > $@
tests/services/org.freedesktop.portal.Flatpak.service: portal/org.freedesktop.portal.Flatpak.service.in
mkdir -p tests/services
$(AM_V_GEN) $(SED) -e "s|\@libexecdir\@|$(abs_top_builddir)|" -e "s|\@extraargs\@| --poll-timeout=1|" $< > $@
tests/services/org.freedesktop.Flatpak.SystemHelper.service: system-helper/org.freedesktop.Flatpak.SystemHelper.service.in
mkdir -p tests/services
$(AM_V_GEN) $(SED) -e "s|\@libexecdir\@|$(abs_top_builddir)|" -e "s|\@extraargs\@| --session --no-idle-exit|" $< > $@
tests/libtest.sh: tests/services/org.freedesktop.Flatpak.service tests/services/org.freedesktop.Flatpak.SystemHelper.service
tests/libtest.sh: tests/services/org.freedesktop.Flatpak.service tests/services/org.freedesktop.Flatpak.SystemHelper.service tests/services/org.freedesktop.portal.Flatpak.service
install-test-data-hook:
if ENABLE_INSTALLED_TESTS
@ -143,6 +155,7 @@ TEST_MATRIX_SOURCE = \
tests/test-update-remote-configuration.sh \
tests/test-override.sh \
tests/test-p2p-security.sh{user,collections+system,collections} \
tests/test-update-portal.sh \
$(NULL)
update-test-matrix:
@ -167,7 +180,7 @@ dist_test_scripts = ${TEST_MATRIX_DIST}
dist_installed_test_extra_scripts += ${TEST_MATRIX_EXTRA_DIST}
test_programs = testlibrary testcommon
test_extra_programs = tests/httpcache
test_extra_programs = tests/httpcache tests/test-update-portal
@VALGRIND_CHECK_RULES@
VALGRIND_SUPPRESSIONS_FILES=tests/flatpak.supp tests/glib.supp

View File

@ -335,6 +335,14 @@ run () {
}
run_with_sandboxed_bus () {
BUSSOCK=$(mktemp ${test_tmpdir}/bus.XXXXXX)
rm -rf ${BUSSOCK}
run --command=socat --filesystem=${test_tmpdir} org.test.Hello unix-listen:${BUSSOCK} unix-connect:/run/user/`id -u`/bus &
while [ ! -e ${BUSSOCK} ]; do sleep 1; done
DBUS_SESSION_BUS_ADDRESS="unix:path=${BUSSOCK}" "$@"
}
run_sh () {
ID=${1:-org.test.Hello}
shift

View File

@ -60,7 +60,7 @@ add_bin() {
fi
}
for i in $@ bash ls cat echo readlink; do
for i in $@ bash ls cat echo readlink socat; do
I=`which $i`
add_bin $I
done

198
tests/test-update-portal.c Normal file
View File

@ -0,0 +1,198 @@
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <gio/gio.h>
#include "portal/flatpak-portal-dbus.h"
GDBusConnection *connection;
const char *portal_name = "org.freedesktop.portal.Flatpak";
const char *portal_path = "/org/freedesktop/portal/Flatpak";
static PortalFlatpakUpdateMonitor *
create_monitor (PortalFlatpak *portal,
GCallback update_available_cb,
gpointer cb_data,
GError **error)
{
static int counter = 1;
PortalFlatpakUpdateMonitor *monitor;
g_autofree char *token = NULL;
g_autofree char *monitor_path = NULL;
g_autofree char *sender = NULL;
g_autofree char *monitor_handle = NULL;
char *s;
GVariantBuilder opt_builder;
sender = g_strdup (g_dbus_connection_get_unique_name (connection) + 1);
while ((s = strchr (sender, '.')) != NULL)
*s = '_';
token = g_strdup_printf ("test_token%d", counter++);
monitor_path = g_strdup_printf ("/org/freedesktop/portal/Flatpak/update_monitor/%s/%s", sender, token);
monitor = portal_flatpak_update_monitor_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE,
portal_name, monitor_path,
NULL, error);
if (monitor == NULL)
return NULL;
if (update_available_cb)
g_signal_connect (monitor, "update-available", update_available_cb, cb_data);
g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&opt_builder, "{sv}", "handle_token", g_variant_new_string (token));
if (!portal_flatpak_call_create_update_monitor_sync (portal,
g_variant_builder_end (&opt_builder),
&monitor_handle,
NULL, error))
return NULL;
return monitor;
}
static void
update_available (PortalFlatpakUpdateMonitor *object,
GVariant *arg_update_info,
gpointer user_data)
{
const char *running, *local, *remote;
g_variant_lookup (arg_update_info, "running-commit", "&s", &running);
g_variant_lookup (arg_update_info, "local-commit", "&s", &local);
g_variant_lookup (arg_update_info, "remote-commit", "&s", &remote);
g_print ("update_available running=%s local=%s remote=%s\n", running, local, remote);
}
static void
write_status (int res, int status_pipe)
{
char c = res;
write (status_pipe, &c, 1);
}
typedef int (*TestCallback) (PortalFlatpak *portal, int status_pipe);
static int
monitor_test (PortalFlatpak *portal, int status_pipe)
{
g_autoptr(GError) error = NULL;
PortalFlatpakUpdateMonitor *monitor;
GMainLoop *loop;
monitor = create_monitor (portal,
(GCallback)update_available, NULL,
&error);
if (monitor == NULL)
{
g_printerr ("Error creating monitor: %s\n", error->message);
return 1;
}
/* Return 0, to indicate we've successfully started monitor */
write_status (0, status_pipe);
g_print ("Entering main loop waiting for updates\n");
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
return 0;
}
static int
run_test (int status_pipe, const char *pidfile, TestCallback test)
{
g_autoptr(GError) error = NULL;
PortalFlatpak *portal;
g_autofree char *pid = NULL;
pid = g_strdup_printf ("%d", getpid ());
if (!g_file_set_contents (pidfile, pid, -1, &error))
{
g_printerr ("Error creating pidfile: %s\n", error->message);
return 1;
}
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
if (connection == NULL)
{
g_printerr ("Error connecting: %s\n", error->message);
return 1;
}
portal = portal_flatpak_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE,
portal_name, portal_path,
NULL, &error);
if (portal == NULL)
{
g_printerr ("Error creating proxy: %s\n", error->message);
return 1;
}
return test (portal, status_pipe);
}
int
main (int argc, char *argv[])
{
pid_t pid;
int pipes[2];
TestCallback test_callback;
if (argc < 2)
{
g_printerr ("No test command specified");
return 1;
}
if (strcmp (argv[1], "monitor") == 0)
test_callback = monitor_test;
else
{
g_printerr ("Unknown command %s specified", argv[1]);
return 1;
}
if (pipe (pipes) != 0)
{
perror ("pipe:");
return 1;
}
pid = fork();
if (pid == -1)
{
perror ("pipe:");
return 1;
}
if (pid != 0)
{
char c;
/* parent */
close (pipes[1]);
if (read (pipes[0], &c, 1) != 1)
return 1;
return c;
}
else
{
int res;
close (pipes[0]);
res = run_test (pipes[1], argc > 2 ? argv[2] : "pid.out", test_callback);
/* If this returned early we have some setup failure, report it */
write_status (res, pipes[1]);
exit (res);
}
}

69
tests/test-update-portal.sh Executable file
View File

@ -0,0 +1,69 @@
#!/bin/bash
#
# Copyright (C) 2019 Colin Walters <walters@verbum.org>
#
# This library 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 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, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
set -euo pipefail
. $(dirname $0)/libtest.sh
skip_without_bwrap
echo "1..1"
setup_repo
install_repo
run_with_sandboxed_bus ${test_builddir}/test-update-portal monitor monitor.pid > update-monitor.out
MONITOR_PID=$(cat monitor.pid)
OLD_COMMIT=$(cat repos/test/refs/heads/app/org.test.Hello/$ARCH/master)
make_updated_app
NEW_COMMIT=$(cat repos/test/refs/heads/app/org.test.Hello/$ARCH/master)
for i in {15..1}; do
if grep -q -e "update_available .* remote=${NEW_COMMIT}" update-monitor.out; then
assert_file_has_content update-monitor.out "running=${OLD_COMMIT} local=${OLD_COMMIT} remote=${NEW_COMMIT}"
echo found update ${NEW_COMMIT}
break
fi
if [ $i == 1 ]; then
assert_not_reached "Timed out when looking for update 1"
fi
sleep 1
done
make_updated_app test "" master UPDATE2
NEWER_COMMIT=$(cat repos/test/refs/heads/app/org.test.Hello/$ARCH/master)
for i in {15..1}; do
if grep -q -e "update_available .* remote=${NEWER_COMMIT}" update-monitor.out; then
assert_file_has_content update-monitor.out "running=${OLD_COMMIT} local=${OLD_COMMIT} remote=${NEWER_COMMIT}"
echo found update ${NEWER_COMMIT}
break
fi
if [ $i == 1 ]; then
assert_not_reached "Timed out when looking for update 2"
fi
sleep 1
done
# Make sure monitor is dead
kill -9 $MONITOR_PID
echo "ok monitor updates"