Skip to content

Commit

Permalink
tests/document-fuse: Move to the pytest harness
Browse files Browse the repository at this point in the history
The pytest harness already knows how to set up all the portal bits and
pieces so we can drop the shell script and the dbus service activation
configuration.
  • Loading branch information
swick committed Dec 5, 2024
1 parent 9d1da98 commit 7f0634a
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 163 deletions.
2 changes: 1 addition & 1 deletion tests/.mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ check_untyped_defs=True
files=.
exclude = (?x)(
templates/.*.py # template files are a bit special
|test-document-fuse.py$ # has issues with typing
|test_document_fuse.py$ # has issues with typing
)

[mypy-gi.*]
Expand Down
3 changes: 3 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ but should not normally be set on production systems:
reliable are skipped.
Set this for automated QA testing, leave it unset during development.

* `XDP_TEST_RUN_LONG`: If set (to any value), some tests will run more
iterations or otherwise test more thoroughly.

* `XDP_VALIDATE_ICON_INSECURE`: If set (to any value), x-d-p doesn't
sandbox the icon validator using **bwrap**(1), even if sandboxed
validation was enabled at compile time.
Expand Down
4 changes: 4 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ def is_in_container() -> bool:
)


def run_long_tests() -> bool:
return os.environ.get("XDP_TEST_RUN_LONG") is not None


def wait(ms: int):
"""
Waits for the specified amount of milliseconds.
Expand Down
11 changes: 1 addition & 10 deletions tests/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -212,15 +212,6 @@ foreach p : portal_limited
)
endforeach

if enable_installed_tests
install_data(
'session.conf.in',
'test-document-fuse.sh',
'test-document-fuse.py',
install_dir: installed_tests_dir
)
endif

test_permission_store = executable(
'test-permission-store',
'test-permission-store.c',
Expand Down Expand Up @@ -315,6 +306,7 @@ if enable_pytest
'test_background.py',
'test_camera.py',
'test_clipboard.py',
'test_document_fuse.py',
'test_email.py',
'test_filechooser.py',
'test_globalshortcuts.py',
Expand Down Expand Up @@ -356,7 +348,6 @@ if enable_installed_tests
testfiles = [
'testdb',
'test-doc-portal',
'test-document-fuse.sh',
'test-permission-store',
'test-xdp-utils',
]
Expand Down
103 changes: 0 additions & 103 deletions tests/test-document-fuse.sh

This file was deleted.

148 changes: 99 additions & 49 deletions tests/test-document-fuse.py → tests/test_document_fuse.py
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,69 +1,43 @@
#!/usr/bin/env python3

# Copyright © 2020 Red Hat, Inc
# Copyright © 2023 GNOME Foundation Inc.
#
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# 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 <http://www.gnu.org/licenses/>.
#
# Authors:
# Alexander Larsson <[email protected]>
# Hubert Figuière <[email protected]>
# This file is formatted with Python Black

import argparse
import tests as xdp

import pytest
import errno
import os
import random
import stat
import sys

import multiprocessing as mp
import traceback
import subprocess
from gi.repository import Gio, GLib


@pytest.fixture
def app_id():
return None


def filename_to_ay(filename):
return list(filename.encode("utf-8")) + [0]


running_count = {}

app_prefix = "org.test."
dir_prefix = "dir"
ensure_no_remaining = True

parser = argparse.ArgumentParser()
parser.add_argument("--verbose", "-v", action="count")
parser.add_argument("--iterations", type=int, default=3)
parser.add_argument("--prefix")
args = parser.parse_args(sys.argv[1:])

if args.prefix:
app_prefix = app_prefix + args.prefix + "."
dir_prefix = dir_prefix + "-" + args.prefix + "-"
ensure_no_remaining = False
running_count = {}


def log(str):
if args.prefix:
print("%s: %s" % (args.prefix, str), file=sys.stderr)
else:
print(str, file=sys.stderr)
print(str, file=sys.stderr)


def logv(str):
if args.verbose:
log(str)
log(str)


def get_a_count(counter):
Expand Down Expand Up @@ -103,7 +77,6 @@ def appendFdContent(fd, content):
os.write(fd, bytes(content, "utf-8"))


TEST_DATA_DIR = os.environ["TEST_DATA_DIR"]
DOCUMENT_ADD_FLAGS_REUSE_EXISTING = 1 << 0
DOCUMENT_ADD_FLAGS_PERSISTENT = 1 << 1
DOCUMENT_ADD_FLAGS_AS_NEEDED_BY_APP = 1 << 2
Expand Down Expand Up @@ -1010,7 +983,7 @@ def create_app_by_lookup(portal):

def ensure_real_dir(create_hidden_file=True):
count = get_a_count("doc")
dir = TEST_DATA_DIR + "/" + dir_prefix + str(count)
dir = os.environ["TMPDIR"] + "/" + dir_prefix + str(count)
os.makedirs(dir)
if create_hidden_file:
setFileContent(dir + "/cant-see-this-file", "s3krit")
Expand Down Expand Up @@ -1208,7 +1181,17 @@ def file_transfer_portal_test():
log("File transfer tests ok")


try:
def run_test(iterations, prefix=None, do_ensure_no_remaining=True):
global app_prefix
global dir_prefix
global ensure_no_remaining

if prefix:
app_prefix = app_prefix + prefix + "."
dir_prefix = dir_prefix + "-" + prefix + "-"

ensure_no_remaining = do_ensure_no_remaining

log("Connecting to portal")
doc_portal = DocPortal()

Expand Down Expand Up @@ -1241,15 +1224,82 @@ def file_transfer_portal_test():
add_an_app(doc_portal, 6)
verify_fs_layout(doc_portal)

for i in range(args.iterations):
for i in range(iterations):
log("Checking permissions, pass %d" % (i + 1))
check_perms(doc_portal)
verify_fs_layout(doc_portal)

log("fuse tests ok")
file_transfer_portal_test()

sys.exit(0)
except Exception as e:
log("fuse tests failed: %s" % e)
sys.exit(1)

class Process(mp.Process):
def __init__(self, *args, **kwargs):
mp.Process.__init__(self, *args, **kwargs)
self._pconn, self._cconn = mp.Pipe()
self._exception = None

def run(self):
try:
mp.Process.run(self)
self._cconn.send(None)
except Exception as e:
tb = traceback.format_exc()
self._cconn.send((e, tb))

@property
def exception(self):
if self._pconn.poll():
self._exception = self._pconn.recv()
return self._exception


class TestDocumentFuse:
def parallel(self, test_function, parallel_tests, parallel_iterations):
procs = []
for i in range(parallel_tests):
p = Process(
target=test_function, args=(parallel_iterations, f"c{i}", False)
)
p.start()
procs.append(p)

for p in procs:
p.join()

if p.exception:
error, traceback = p.exception
raise error

def test_single_thread(self, portals, xdg_document_portal, dbus_con):
run_test(3)

def test_multi_thread(self, portals, xdg_document_portal, dbus_con):
if xdp.run_long_tests():
return self.parallel(run_test, 20, 10)
if xdp.is_in_ci():
return self.parallel(run_test, 5, 3)
self.parallel(run_test, 10, 5)


def run_bash(cmd):
proc = subprocess.Popen(
cmd, stdout=None, stderr=None, shell=True, universal_newlines=True
)
_ = proc.communicate()
return proc.returncode == 0


if not run_bash("fusermount3 --version"):
pytest.skip("no fusermount3", allow_module_level=True)

if not run_bash("capsh --print | grep -q 'Bounding set.*[^a-z]cap_sys_admin'"):
pytest.skip(
"No cap_sys_admin in bounding set, can't use FUSE", allow_module_level=True
)

if not run_bash("[ -w /dev/fuse ]"):
pytest.skip("no write access to /dev/fuse", allow_module_level=True)

if not run_bash("[ -e /etc/mtab ]"):
pytest.skip("no /etc/mtab", allow_module_level=True)

0 comments on commit 7f0634a

Please sign in to comment.