From 768b36133ca4e4a2eeddc145355eac4b0420b04b Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 1 May 2022 17:04:47 +0200 Subject: [PATCH 01/15] Added first pytest --- tests/python-related/test_import.py | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tests/python-related/test_import.py diff --git a/tests/python-related/test_import.py b/tests/python-related/test_import.py new file mode 100644 index 0000000000..815868d384 --- /dev/null +++ b/tests/python-related/test_import.py @@ -0,0 +1,4 @@ +import pytest + +def test_import(): + import archinstall \ No newline at end of file From 9d6e85e931950a4b89729bf27c60a6dd90aa05ba Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 1 May 2022 17:18:48 +0200 Subject: [PATCH 02/15] Added SysCommand() tests --- tests/syscalls/test_syscommand.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/syscalls/test_syscommand.py diff --git a/tests/syscalls/test_syscommand.py b/tests/syscalls/test_syscommand.py new file mode 100644 index 0000000000..122f196eed --- /dev/null +++ b/tests/syscalls/test_syscommand.py @@ -0,0 +1,18 @@ +import pytest + +def test_SysCommand(): + import archinstall + import subprocess + + if not archinstall.SysCommand('whoami').decode().strip() == subprocess.check_output('whoami').decode().strip(): + raise AssertionError(f"SysCommand('whoami') did not return expected output: {subprocess.check_output('whoami').decode()}") + + try: + archinstall.SysCommand('nonexistingbinary-for-testing').decode().strip() + except archinstall.RequirementError: + pass # we want to make sure it fails with an exception unique to missing binary + + try: + archinstall.SysCommand('ls -veryfaultyparameter').decode().strip() + except archinstall.SysCallError: + pass # We want it to raise a syscall error when a binary dislikes us \ No newline at end of file From 9d9e452900e9b1975bd72a98e6eebbf1f3dddd08 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 1 May 2022 17:20:27 +0200 Subject: [PATCH 03/15] Making flake8 ignore tests --- .flake8 | 1 + 1 file changed, 1 insertion(+) diff --git a/.flake8 b/.flake8 index 39310a6c30..54fe379a4e 100644 --- a/.flake8 +++ b/.flake8 @@ -8,3 +8,4 @@ show-source = True statistics = True builtins = _ per-file-ignores = __init__.py:F401,F403,F405 simple_menu.py:C901,W503 guided.py:C901 network_configuration.py:F821 +exclude = tests \ No newline at end of file From e1091ffc95cd1769c31c6ecf748613dd3cd5ce3b Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 1 May 2022 18:39:02 +0200 Subject: [PATCH 04/15] Added BlockDevice() tests --- tests/disk-related/test_stat_blockdev.py | 117 +++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 tests/disk-related/test_stat_blockdev.py diff --git a/tests/disk-related/test_stat_blockdev.py b/tests/disk-related/test_stat_blockdev.py new file mode 100644 index 0000000000..0128d8eddc --- /dev/null +++ b/tests/disk-related/test_stat_blockdev.py @@ -0,0 +1,117 @@ +import pytest +import subprocess +import string +import random +import pathlib + +def simple_exec(cmd): + proc = subprocess.Popen( + cmd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT + ) + + while proc.poll() is None: + pass + + result = proc.stdout.read() + proc.stdout.close() + + return {'exit_code' : proc.poll(), 'data' : result.decode().strip()} + +def random_filename(): + return ''.join([random.choice(string.ascii_letters) for x in range(20)]) + '.img' + +def truncate_file(filename): + result = simple_exec(f"truncate -s 20G {filename}") + + if not result['exit_code'] == 0: + raise AssertionError(f"Could not generate a testimage with truncate: {result['data']}") + + return filename + +def get_loopdev(filename): + result = simple_exec(f"""losetup -a | grep "{filename}" | awk -F ":" '{{print $1}}'""") + return result['data'] + +def detach_loopdev(path): + result = simple_exec(f"losetup -d {path}") + return result['exit_code'] == 0 + +def create_loopdev(path): + result = simple_exec(f"losetup -fP {path}") + return result['exit_code'] == 0 + +def test_stat_blockdev(): + import archinstall + + filename = pathlib.Path(random_filename()).resolve() + if loopdev := get_loopdev(filename): + if not detach_loopdev(loopdev): + raise AssertionError(f"Could not detach {loopdev} before performing test with {filename}.") + + truncate_file(filename) + if not create_loopdev(filename): + raise AssertionError(f"Could not create a loopdev for {filename}") + + if loopdev := get_loopdev(filename): + # Actual test starts here: + block_device = archinstall.BlockDevice(loopdev) + + # Make sure the backfile reported by BlockDevice() is the same we mounted + if block_device.device_or_backfile != str(filename): + raise AssertionError(f"archinstall.BlockDevice().device_or_backfile differs from loopdev path: {block_device.device_or_backfile} vs {filename}") + + # Make sure the device path equals to the device we setup (/dev/loop0) + if block_device.device != loopdev: + raise AssertionError(f"archinstall.BlockDevice().device difers from {loopdev}") + + # Check that the BlockDevice is clear of partitions + if block_device.partitions: + raise AssertionError(f"BlockDevice().partitions reported partitions, despire being a new trunkfile") + + if block_device.has_partitions(): + raise AssertionError(f"BlockDevice().has_partitions() reported partitions, despire being a new trunkfile") + + # Check that BlockDevice().size returns a float of the size in GB + if block_device.size != 20.0: + raise AssertionError(f"The size reported by BlockDevice().size is not 20.0 as expected") + + if block_device.bus_type != None: + raise AssertionError(f"The .bus_type of the loopdev is something other than the expected None: {block_device.bus_type}") + + if block_device.spinning != False: + raise AssertionError(f"The expected BlockDevice().spinnig was False, but got True") + + # if list(block_device.free_space) != [[0, 20, 20]]: + # raise AssertionError(f"The reported free space of the loopdev was not [0, 20, 20]") + + # print(block_device.largest_free_space) + if block_device.first_free_sector != '512MB': + raise AssertionError(f"First free sector of BlockDevice() was not 512MB") + + if block_device.first_end_sector != '20.0GB': + raise AssertionError(f"Last sector of BlockDevice() was not 20.0GB") + + if not block_device.partprobe(): + raise AssertionError(f"Could not partprobe BlockDevice() of loopdev") + + if block_device.has_mount_point('/'): + raise AssertionError(f"BlockDevice() reported a mountpoint despite never being mounted") + + try: + if block_device.get_partition('FAKE-UUID-TEST'): + raise AssertionError(f"BlockDevice() reported a partition despite never having any") + except archinstall.DiskError: + pass # We're supposed to not find any + + # Test ended, cleanup commences + if not detach_loopdev(loopdev): + raise AssertionError(f"Could not detach {loopdev} after performing tests on {filename}.") + else: + raise AssertionError(f"Could not retrieve a loopdev for testing on {filename}") + + pathlib.Path(filename).resolve().unlink() + +test_stat_blockdev() \ No newline at end of file From 8adade206a4cb0dacf9b479eefa50c931817a9e8 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 1 May 2022 19:28:33 +0200 Subject: [PATCH 05/15] Added unattended installation of guided with test data --- archinstall/__init__.py | 2 +- archinstall/examples | 1 - .../examples}/__init__.py | 0 .../examples}/config-sample.json | 0 .../examples}/creds-sample.json | 0 .../examples}/custom-command-sample.json | 0 .../examples}/disk_layouts-sample.json | 0 {examples => archinstall/examples}/guided.py | 4 +- {examples => archinstall/examples}/minimal.py | 0 {examples => archinstall/examples}/only_hd.py | 0 {examples => archinstall/examples}/swiss.py | 0 .../examples}/unattended.py | 0 archinstall/lib/output.py | 2 +- archinstall/profiles | 1 - .../profiles}/52-54-00-12-34-56.py | 0 .../profiles}/__init__.py | 0 .../profiles}/applications/__init__.py | 0 .../profiles}/applications/awesome.py | 0 .../profiles}/applications/cockpit.py | 0 .../profiles}/applications/docker.py | 0 .../profiles}/applications/httpd.py | 0 .../profiles}/applications/lighttpd.py | 0 .../profiles}/applications/mariadb.py | 0 .../profiles}/applications/nginx.py | 0 .../profiles}/applications/pipewire.py | 0 .../profiles}/applications/postgresql.py | 0 .../profiles}/applications/sshd.py | 0 .../profiles}/applications/tomcat.py | 0 {profiles => archinstall/profiles}/awesome.py | 0 {profiles => archinstall/profiles}/bspwm.py | 0 {profiles => archinstall/profiles}/budgie.py | 0 .../profiles}/cinnamon.py | 0 .../profiles}/cutefish.py | 0 {profiles => archinstall/profiles}/deepin.py | 0 {profiles => archinstall/profiles}/desktop.py | 0 .../profiles}/enlightenment.py | 0 {profiles => archinstall/profiles}/gnome.py | 0 {profiles => archinstall/profiles}/i3.py | 0 {profiles => archinstall/profiles}/kde.py | 0 {profiles => archinstall/profiles}/lxqt.py | 0 {profiles => archinstall/profiles}/mate.py | 0 {profiles => archinstall/profiles}/minimal.py | 0 {profiles => archinstall/profiles}/qtile.py | 0 {profiles => archinstall/profiles}/server.py | 0 {profiles => archinstall/profiles}/sway.py | 0 {profiles => archinstall/profiles}/xfce4.py | 0 {profiles => archinstall/profiles}/xorg.py | 0 examples | 1 + profiles | 1 + tests/disk-related/test_stat_blockdev.py | 4 +- tests/guided-related/test_minimal_install.py | 173 ++++++++++++++++++ 51 files changed, 180 insertions(+), 9 deletions(-) delete mode 120000 archinstall/examples rename {examples => archinstall/examples}/__init__.py (100%) rename {examples => archinstall/examples}/config-sample.json (100%) rename {examples => archinstall/examples}/creds-sample.json (100%) rename {examples => archinstall/examples}/custom-command-sample.json (100%) rename {examples => archinstall/examples}/disk_layouts-sample.json (100%) rename {examples => archinstall/examples}/guided.py (99%) rename {examples => archinstall/examples}/minimal.py (100%) rename {examples => archinstall/examples}/only_hd.py (100%) rename {examples => archinstall/examples}/swiss.py (100%) rename {examples => archinstall/examples}/unattended.py (100%) delete mode 120000 archinstall/profiles rename {profiles => archinstall/profiles}/52-54-00-12-34-56.py (100%) rename {profiles => archinstall/profiles}/__init__.py (100%) rename {profiles => archinstall/profiles}/applications/__init__.py (100%) rename {profiles => archinstall/profiles}/applications/awesome.py (100%) rename {profiles => archinstall/profiles}/applications/cockpit.py (100%) rename {profiles => archinstall/profiles}/applications/docker.py (100%) rename {profiles => archinstall/profiles}/applications/httpd.py (100%) rename {profiles => archinstall/profiles}/applications/lighttpd.py (100%) rename {profiles => archinstall/profiles}/applications/mariadb.py (100%) rename {profiles => archinstall/profiles}/applications/nginx.py (100%) rename {profiles => archinstall/profiles}/applications/pipewire.py (100%) rename {profiles => archinstall/profiles}/applications/postgresql.py (100%) rename {profiles => archinstall/profiles}/applications/sshd.py (100%) rename {profiles => archinstall/profiles}/applications/tomcat.py (100%) rename {profiles => archinstall/profiles}/awesome.py (100%) rename {profiles => archinstall/profiles}/bspwm.py (100%) rename {profiles => archinstall/profiles}/budgie.py (100%) rename {profiles => archinstall/profiles}/cinnamon.py (100%) rename {profiles => archinstall/profiles}/cutefish.py (100%) rename {profiles => archinstall/profiles}/deepin.py (100%) rename {profiles => archinstall/profiles}/desktop.py (100%) rename {profiles => archinstall/profiles}/enlightenment.py (100%) rename {profiles => archinstall/profiles}/gnome.py (100%) rename {profiles => archinstall/profiles}/i3.py (100%) rename {profiles => archinstall/profiles}/kde.py (100%) rename {profiles => archinstall/profiles}/lxqt.py (100%) rename {profiles => archinstall/profiles}/mate.py (100%) rename {profiles => archinstall/profiles}/minimal.py (100%) rename {profiles => archinstall/profiles}/qtile.py (100%) rename {profiles => archinstall/profiles}/server.py (100%) rename {profiles => archinstall/profiles}/sway.py (100%) rename {profiles => archinstall/profiles}/xfce4.py (100%) rename {profiles => archinstall/profiles}/xorg.py (100%) create mode 120000 examples create mode 120000 profiles create mode 100644 tests/guided-related/test_minimal_install.py diff --git a/archinstall/__init__.py b/archinstall/__init__.py index f362064853..07c834c108 100644 --- a/archinstall/__init__.py +++ b/archinstall/__init__.py @@ -150,7 +150,7 @@ def get_arguments() -> Dict[str, Any]: parsed_url = urllib.parse.urlparse(args.config) if not parsed_url.scheme: # The Profile was not a direct match on a remote URL, it must be a local file. - if not json_stream_to_structure('--config',args.config,config): + if not json_stream_to_structure('--config', args.config, config): exit(1) else: # Attempt to load the configuration from the URL. with urllib.request.urlopen(urllib.request.Request(args.config, headers={'User-Agent': 'ArchInstall'})) as response: diff --git a/archinstall/examples b/archinstall/examples deleted file mode 120000 index 785887f7fb..0000000000 --- a/archinstall/examples +++ /dev/null @@ -1 +0,0 @@ -../examples/ \ No newline at end of file diff --git a/examples/__init__.py b/archinstall/examples/__init__.py similarity index 100% rename from examples/__init__.py rename to archinstall/examples/__init__.py diff --git a/examples/config-sample.json b/archinstall/examples/config-sample.json similarity index 100% rename from examples/config-sample.json rename to archinstall/examples/config-sample.json diff --git a/examples/creds-sample.json b/archinstall/examples/creds-sample.json similarity index 100% rename from examples/creds-sample.json rename to archinstall/examples/creds-sample.json diff --git a/examples/custom-command-sample.json b/archinstall/examples/custom-command-sample.json similarity index 100% rename from examples/custom-command-sample.json rename to archinstall/examples/custom-command-sample.json diff --git a/examples/disk_layouts-sample.json b/archinstall/examples/disk_layouts-sample.json similarity index 100% rename from examples/disk_layouts-sample.json rename to archinstall/examples/disk_layouts-sample.json diff --git a/examples/guided.py b/archinstall/examples/guided.py similarity index 99% rename from examples/guided.py rename to archinstall/examples/guided.py index 15226668e0..4be4d66178 100644 --- a/examples/guided.py +++ b/archinstall/examples/guided.py @@ -178,8 +178,8 @@ def perform_installation(mountpoint): archinstall.use_mirrors(archinstall.arguments['mirror-region']) # Set the mirrors for the live medium # Retrieve list of additional repositories and set boolean values appropriately - enable_testing = 'testing' in archinstall.arguments.get('additional-repositories', None) - enable_multilib = 'multilib' in archinstall.arguments.get('additional-repositories', None) + enable_testing = 'testing' in archinstall.arguments.get('additional-repositories', []) + enable_multilib = 'multilib' in archinstall.arguments.get('additional-repositories', []) if installation.minimal_installation(testing=enable_testing, multilib=enable_multilib): installation.set_locale(archinstall.arguments['sys-language'], archinstall.arguments['sys-encoding'].upper()) diff --git a/examples/minimal.py b/archinstall/examples/minimal.py similarity index 100% rename from examples/minimal.py rename to archinstall/examples/minimal.py diff --git a/examples/only_hd.py b/archinstall/examples/only_hd.py similarity index 100% rename from examples/only_hd.py rename to archinstall/examples/only_hd.py diff --git a/examples/swiss.py b/archinstall/examples/swiss.py similarity index 100% rename from examples/swiss.py rename to archinstall/examples/swiss.py diff --git a/examples/unattended.py b/archinstall/examples/unattended.py similarity index 100% rename from examples/unattended.py rename to archinstall/examples/unattended.py diff --git a/archinstall/lib/output.py b/archinstall/lib/output.py index da41d16d5e..2aaf652821 100644 --- a/archinstall/lib/output.py +++ b/archinstall/lib/output.py @@ -126,6 +126,6 @@ def log(*args :str, **kwargs :Union[str, int, Dict[str, Union[str, int]]]) -> No # Finally, print the log unless we skipped it based on level. # We use sys.stdout.write()+flush() instead of print() to try and # fix issue #94 - if kwargs.get('level', logging.INFO) != logging.DEBUG or storage['arguments'].get('verbose', False): + if kwargs.get('level', logging.INFO) != logging.DEBUG or hasattr(storage.get('arguments'), 'verbose') and storage['arguments'].verbose: sys.stdout.write(f"{string}\n") sys.stdout.flush() diff --git a/archinstall/profiles b/archinstall/profiles deleted file mode 120000 index c2968eea02..0000000000 --- a/archinstall/profiles +++ /dev/null @@ -1 +0,0 @@ -../profiles/ \ No newline at end of file diff --git a/profiles/52-54-00-12-34-56.py b/archinstall/profiles/52-54-00-12-34-56.py similarity index 100% rename from profiles/52-54-00-12-34-56.py rename to archinstall/profiles/52-54-00-12-34-56.py diff --git a/profiles/__init__.py b/archinstall/profiles/__init__.py similarity index 100% rename from profiles/__init__.py rename to archinstall/profiles/__init__.py diff --git a/profiles/applications/__init__.py b/archinstall/profiles/applications/__init__.py similarity index 100% rename from profiles/applications/__init__.py rename to archinstall/profiles/applications/__init__.py diff --git a/profiles/applications/awesome.py b/archinstall/profiles/applications/awesome.py similarity index 100% rename from profiles/applications/awesome.py rename to archinstall/profiles/applications/awesome.py diff --git a/profiles/applications/cockpit.py b/archinstall/profiles/applications/cockpit.py similarity index 100% rename from profiles/applications/cockpit.py rename to archinstall/profiles/applications/cockpit.py diff --git a/profiles/applications/docker.py b/archinstall/profiles/applications/docker.py similarity index 100% rename from profiles/applications/docker.py rename to archinstall/profiles/applications/docker.py diff --git a/profiles/applications/httpd.py b/archinstall/profiles/applications/httpd.py similarity index 100% rename from profiles/applications/httpd.py rename to archinstall/profiles/applications/httpd.py diff --git a/profiles/applications/lighttpd.py b/archinstall/profiles/applications/lighttpd.py similarity index 100% rename from profiles/applications/lighttpd.py rename to archinstall/profiles/applications/lighttpd.py diff --git a/profiles/applications/mariadb.py b/archinstall/profiles/applications/mariadb.py similarity index 100% rename from profiles/applications/mariadb.py rename to archinstall/profiles/applications/mariadb.py diff --git a/profiles/applications/nginx.py b/archinstall/profiles/applications/nginx.py similarity index 100% rename from profiles/applications/nginx.py rename to archinstall/profiles/applications/nginx.py diff --git a/profiles/applications/pipewire.py b/archinstall/profiles/applications/pipewire.py similarity index 100% rename from profiles/applications/pipewire.py rename to archinstall/profiles/applications/pipewire.py diff --git a/profiles/applications/postgresql.py b/archinstall/profiles/applications/postgresql.py similarity index 100% rename from profiles/applications/postgresql.py rename to archinstall/profiles/applications/postgresql.py diff --git a/profiles/applications/sshd.py b/archinstall/profiles/applications/sshd.py similarity index 100% rename from profiles/applications/sshd.py rename to archinstall/profiles/applications/sshd.py diff --git a/profiles/applications/tomcat.py b/archinstall/profiles/applications/tomcat.py similarity index 100% rename from profiles/applications/tomcat.py rename to archinstall/profiles/applications/tomcat.py diff --git a/profiles/awesome.py b/archinstall/profiles/awesome.py similarity index 100% rename from profiles/awesome.py rename to archinstall/profiles/awesome.py diff --git a/profiles/bspwm.py b/archinstall/profiles/bspwm.py similarity index 100% rename from profiles/bspwm.py rename to archinstall/profiles/bspwm.py diff --git a/profiles/budgie.py b/archinstall/profiles/budgie.py similarity index 100% rename from profiles/budgie.py rename to archinstall/profiles/budgie.py diff --git a/profiles/cinnamon.py b/archinstall/profiles/cinnamon.py similarity index 100% rename from profiles/cinnamon.py rename to archinstall/profiles/cinnamon.py diff --git a/profiles/cutefish.py b/archinstall/profiles/cutefish.py similarity index 100% rename from profiles/cutefish.py rename to archinstall/profiles/cutefish.py diff --git a/profiles/deepin.py b/archinstall/profiles/deepin.py similarity index 100% rename from profiles/deepin.py rename to archinstall/profiles/deepin.py diff --git a/profiles/desktop.py b/archinstall/profiles/desktop.py similarity index 100% rename from profiles/desktop.py rename to archinstall/profiles/desktop.py diff --git a/profiles/enlightenment.py b/archinstall/profiles/enlightenment.py similarity index 100% rename from profiles/enlightenment.py rename to archinstall/profiles/enlightenment.py diff --git a/profiles/gnome.py b/archinstall/profiles/gnome.py similarity index 100% rename from profiles/gnome.py rename to archinstall/profiles/gnome.py diff --git a/profiles/i3.py b/archinstall/profiles/i3.py similarity index 100% rename from profiles/i3.py rename to archinstall/profiles/i3.py diff --git a/profiles/kde.py b/archinstall/profiles/kde.py similarity index 100% rename from profiles/kde.py rename to archinstall/profiles/kde.py diff --git a/profiles/lxqt.py b/archinstall/profiles/lxqt.py similarity index 100% rename from profiles/lxqt.py rename to archinstall/profiles/lxqt.py diff --git a/profiles/mate.py b/archinstall/profiles/mate.py similarity index 100% rename from profiles/mate.py rename to archinstall/profiles/mate.py diff --git a/profiles/minimal.py b/archinstall/profiles/minimal.py similarity index 100% rename from profiles/minimal.py rename to archinstall/profiles/minimal.py diff --git a/profiles/qtile.py b/archinstall/profiles/qtile.py similarity index 100% rename from profiles/qtile.py rename to archinstall/profiles/qtile.py diff --git a/profiles/server.py b/archinstall/profiles/server.py similarity index 100% rename from profiles/server.py rename to archinstall/profiles/server.py diff --git a/profiles/sway.py b/archinstall/profiles/sway.py similarity index 100% rename from profiles/sway.py rename to archinstall/profiles/sway.py diff --git a/profiles/xfce4.py b/archinstall/profiles/xfce4.py similarity index 100% rename from profiles/xfce4.py rename to archinstall/profiles/xfce4.py diff --git a/profiles/xorg.py b/archinstall/profiles/xorg.py similarity index 100% rename from profiles/xorg.py rename to archinstall/profiles/xorg.py diff --git a/examples b/examples new file mode 120000 index 0000000000..910e23847d --- /dev/null +++ b/examples @@ -0,0 +1 @@ +archinstall/examples/ \ No newline at end of file diff --git a/profiles b/profiles new file mode 120000 index 0000000000..4cccef6782 --- /dev/null +++ b/profiles @@ -0,0 +1 @@ +archinstall/profiles/ \ No newline at end of file diff --git a/tests/disk-related/test_stat_blockdev.py b/tests/disk-related/test_stat_blockdev.py index 0128d8eddc..fb0a24b1f0 100644 --- a/tests/disk-related/test_stat_blockdev.py +++ b/tests/disk-related/test_stat_blockdev.py @@ -112,6 +112,4 @@ def test_stat_blockdev(): else: raise AssertionError(f"Could not retrieve a loopdev for testing on {filename}") - pathlib.Path(filename).resolve().unlink() - -test_stat_blockdev() \ No newline at end of file + pathlib.Path(filename).resolve().unlink() \ No newline at end of file diff --git a/tests/guided-related/test_minimal_install.py b/tests/guided-related/test_minimal_install.py new file mode 100644 index 0000000000..ba67f0ea47 --- /dev/null +++ b/tests/guided-related/test_minimal_install.py @@ -0,0 +1,173 @@ +import pytest +import subprocess +import string +import random +import pathlib +import json +import time +import sys + +def simple_exec(cmd): + proc = subprocess.Popen( + cmd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT + ) + + output = b'' + while proc.poll() is None: + line = proc.stdout.read(1024) + print(line.decode(), end='') + sys.stdout.flush() + output += line + time.sleep(0.01) + + output += proc.stdout.read() + proc.stdout.close() + + return {'exit_code' : proc.poll(), 'data' : output.decode().strip()} + +def random_filename(): + return ''.join([random.choice(string.ascii_letters) for x in range(20)]) + '.img' + +def truncate_file(filename): + result = simple_exec(f"truncate -s 20G {filename}") + + if not result['exit_code'] == 0: + raise AssertionError(f"Could not generate a testimage with truncate: {result['data']}") + + return filename + +def get_loopdev(filename): + result = simple_exec(f"""losetup -a | grep "{filename}" | awk -F ":" '{{print $1}}'""") + return result['data'] + +def detach_loopdev(path): + result = simple_exec(f"losetup -d {path}") + return result['exit_code'] == 0 + +def create_loopdev(path): + result = simple_exec(f"losetup -fP {path}") + return result['exit_code'] == 0 + +def test_stat_blockdev(): + import archinstall + + filename = pathlib.Path(random_filename()).resolve() + if loopdev := get_loopdev(filename): + if not detach_loopdev(loopdev): + raise AssertionError(f"Could not detach {loopdev} before performing test with {filename}.") + + truncate_file(filename) + if not create_loopdev(filename): + raise AssertionError(f"Could not create a loopdev for {filename}") + + if loopdev := get_loopdev(filename): + user_configuration = { + "audio": "pipewire", + "config_version": "2.4.2", + "debug": True, + "harddrives": [ + loopdev + ], + "mirror-region": { + "Sweden": { + "http://ftp.acc.umu.se/mirror/archlinux/$repo/os/$arch": True, + "http://ftp.lysator.liu.se/pub/archlinux/$repo/os/$arch": True, + "http://ftp.myrveln.se/pub/linux/archlinux/$repo/os/$arch": True, + "http://ftpmirror.infania.net/mirror/archlinux/$repo/os/$arch": True, + "https://ftp.acc.umu.se/mirror/archlinux/$repo/os/$arch": True, + "https://ftp.ludd.ltu.se/mirrors/archlinux/$repo/os/$arch": True, + "https://ftp.lysator.liu.se/pub/archlinux/$repo/os/$arch": True, + "https://ftp.myrveln.se/pub/linux/archlinux/$repo/os/$arch": True, + "https://mirror.osbeck.com/archlinux/$repo/os/$arch": True + } + }, + "mount_point": None, + "nic": { + "dhcp": True, + "dns": None, + "gateway": None, + "iface": None, + "ip": None, + "type": "iso" + }, + "packages": [ + "nano" + ], + "plugin": None, + "profile": { + "path": "/usr/lib/python3.10/site-packages/archinstall/profiles/minimal.py" + }, + "script": "guided", + "silent": True, + "timezone": "Europe/Stockholm", + "version": "2.4.2" + } + + user_credentials = { + "!encryption-password": "test", + "!superusers": { + "anton": { + "!password": "test" + } + }, + "!users": {} + } + + user_disk_layout = { + loopdev: { + "partitions": [ + { + "boot": True, + "encrypted": False, + "filesystem": { + "format": "fat32" + }, + "mountpoint": "/boot", + "size": "512MiB", + "start": "1MiB", + "type": "primary", + "wipe": True + }, + { + "btrfs": { + "subvolumes": { + "@": "/", + "@.snapshots": "/.snapshots", + "@home": "/home", + "@log": "/var/log", + "@pkg": "/var/cache/pacman/pkg" + } + }, + "encrypted": False, + "filesystem": { + "format": "btrfs", + "mount_options": [ + "compress=zstd" + ] + }, + "mountpoint": None, + "size": "100%", + "start": "513MiB", + "type": "primary", + "wipe": True + } + ], + "wipe": True + } + } + + result = archinstall.SysCommand(f'archinstall --silent --config \'{json.dumps(user_configuration)}\' --creds \'{json.dumps(user_credentials)}\' --disk-layout \'{json.dumps(user_disk_layout)}\'', peak_output=True) + #print(result) + + # Test ended, cleanup commences + if not detach_loopdev(loopdev): + raise AssertionError(f"Could not detach {loopdev} after performing tests on {filename}.") + else: + raise AssertionError(f"Could not retrieve a loopdev for testing on {filename}") + + pathlib.Path(filename).resolve().unlink() + +test_stat_blockdev() \ No newline at end of file From fa9b4a7225c6cb1d3cda06167dc6c8273ef411cb Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 1 May 2022 19:32:09 +0200 Subject: [PATCH 06/15] Enabling the pytest runner --- .github/workflows/pytest.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index 39ef62c9ea..c59a98b1b5 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -8,8 +8,9 @@ jobs: options: --privileged steps: - uses: actions/checkout@v2 - - run: pacman --noconfirm -Syu python python-pip qemu gcc + - run: pacman --noconfirm -Syu python python-pip - run: python -m pip install --upgrade pip + - run: pip install . - run: pip install pytest - name: Test with pytest - run: python -m pytest || exit 0 \ No newline at end of file + run: python -m pytest \ No newline at end of file From fdc23ff5bdeafda07d56859f1379c02e5d5229cd Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 1 May 2022 19:35:45 +0200 Subject: [PATCH 07/15] Enabling the pytest runner --- .github/workflows/pytest.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index c59a98b1b5..edd23b54ae 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -10,6 +10,8 @@ jobs: - uses: actions/checkout@v2 - run: pacman --noconfirm -Syu python python-pip - run: python -m pip install --upgrade pip + - run: pwd + - run: ls -la - run: pip install . - run: pip install pytest - name: Test with pytest From f68850293b52fb7c8638c9ad82eaeffbc4e75302 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 1 May 2022 19:38:14 +0200 Subject: [PATCH 08/15] Disabling local execution of test, letting pytest handle it --- tests/guided-related/test_minimal_install.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/guided-related/test_minimal_install.py b/tests/guided-related/test_minimal_install.py index ba67f0ea47..823e88abeb 100644 --- a/tests/guided-related/test_minimal_install.py +++ b/tests/guided-related/test_minimal_install.py @@ -168,6 +168,4 @@ def test_stat_blockdev(): else: raise AssertionError(f"Could not retrieve a loopdev for testing on {filename}") - pathlib.Path(filename).resolve().unlink() - -test_stat_blockdev() \ No newline at end of file + pathlib.Path(filename).resolve().unlink() \ No newline at end of file From 84e61935a11d724fa2f01cc87086883a9987a7b7 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 1 May 2022 19:40:29 +0200 Subject: [PATCH 09/15] Adding additional packages to install in the arch container --- .github/workflows/pytest.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index edd23b54ae..7d054c5620 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -8,7 +8,7 @@ jobs: options: --privileged steps: - uses: actions/checkout@v2 - - run: pacman --noconfirm -Syu python python-pip + - run: pacman --noconfirm -Syu python python-pip parted - run: python -m pip install --upgrade pip - run: pwd - run: ls -la From fabb1e4e7853cc0478ed4458444b53c6873f68b5 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 1 May 2022 19:53:02 +0200 Subject: [PATCH 10/15] Trying to fix docker run options not allowing to use blkid on loopdev --- .github/workflows/pytest.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index 7d054c5620..6c531a7ad5 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -5,7 +5,7 @@ jobs: runs-on: ubuntu-latest container: image: archlinux:latest - options: --privileged + options: --privileged --capability=CAP_MKNOD --device-cgroup-rule="b 7:* rmw" steps: - uses: actions/checkout@v2 - run: pacman --noconfirm -Syu python python-pip parted From 6e81c560af34c61dd0f9b718319de6a54e84df46 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 1 May 2022 19:56:51 +0200 Subject: [PATCH 11/15] Trying to fix docker run options not allowing to use blkid on loopdev --- .github/workflows/pytest.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index 6c531a7ad5..68b30dc2c4 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -5,7 +5,7 @@ jobs: runs-on: ubuntu-latest container: image: archlinux:latest - options: --privileged --capability=CAP_MKNOD --device-cgroup-rule="b 7:* rmw" + options: --privileged --cap-add=MKNOD --device-cgroup-rule="b 7:* rmw" steps: - uses: actions/checkout@v2 - run: pacman --noconfirm -Syu python python-pip parted From b2ad906280eb8d1fcfebc50dab62352ad5f4d58c Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 1 May 2022 20:33:30 +0200 Subject: [PATCH 12/15] Trying to fix docker run options not allowing to use blkid on loopdev --- .github/workflows/pytest.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index 68b30dc2c4..f67b7857f4 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -5,7 +5,8 @@ jobs: runs-on: ubuntu-latest container: image: archlinux:latest - options: --privileged --cap-add=MKNOD --device-cgroup-rule="b 7:* rmw" + options: --privileged -v /dev:/dev + # --cap-add=MKNOD --device-cgroup-rule="b 7:* rmw" steps: - uses: actions/checkout@v2 - run: pacman --noconfirm -Syu python python-pip parted From c6677f3f1130ecab361574b04caf9e66de6450a9 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 1 May 2022 22:37:23 +0200 Subject: [PATCH 13/15] Simplified assertion errors, just have to avoid -O to python here. --- tests/disk-related/test_stat_blockdev.py | 41 ++++++++---------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/tests/disk-related/test_stat_blockdev.py b/tests/disk-related/test_stat_blockdev.py index fb0a24b1f0..ef6195c502 100644 --- a/tests/disk-related/test_stat_blockdev.py +++ b/tests/disk-related/test_stat_blockdev.py @@ -60,55 +60,42 @@ def test_stat_blockdev(): block_device = archinstall.BlockDevice(loopdev) # Make sure the backfile reported by BlockDevice() is the same we mounted - if block_device.device_or_backfile != str(filename): - raise AssertionError(f"archinstall.BlockDevice().device_or_backfile differs from loopdev path: {block_device.device_or_backfile} vs {filename}") + assert block_device.device_or_backfile != str(filename), f"archinstall.BlockDevice().device_or_backfile differs from loopdev path: {block_device.device_or_backfile} vs {filename}" # Make sure the device path equals to the device we setup (/dev/loop0) - if block_device.device != loopdev: - raise AssertionError(f"archinstall.BlockDevice().device difers from {loopdev}") + assert block_device.device != loopdev, f"archinstall.BlockDevice().device difers from {loopdev}" # Check that the BlockDevice is clear of partitions - if block_device.partitions: - raise AssertionError(f"BlockDevice().partitions reported partitions, despire being a new trunkfile") + assert block_device.partitions, f"BlockDevice().partitions reported partitions, despire being a new trunkfile" - if block_device.has_partitions(): + assert block_device.has_partitions(): raise AssertionError(f"BlockDevice().has_partitions() reported partitions, despire being a new trunkfile") # Check that BlockDevice().size returns a float of the size in GB - if block_device.size != 20.0: - raise AssertionError(f"The size reported by BlockDevice().size is not 20.0 as expected") + assert block_device.size != 20.0, f"The size reported by BlockDevice().size is not 20.0 as expected" - if block_device.bus_type != None: - raise AssertionError(f"The .bus_type of the loopdev is something other than the expected None: {block_device.bus_type}") + assert block_device.bus_type != None, f"The .bus_type of the loopdev is something other than the expected None: {block_device.bus_type}" - if block_device.spinning != False: - raise AssertionError(f"The expected BlockDevice().spinnig was False, but got True") + assert block_device.spinning != False, f"The expected BlockDevice().spinnig was False, but got True" - # if list(block_device.free_space) != [[0, 20, 20]]: - # raise AssertionError(f"The reported free space of the loopdev was not [0, 20, 20]") + # assert list(block_device.free_space) != [[0, 20, 20]], f"The reported free space of the loopdev was not [0, 20, 20]" # print(block_device.largest_free_space) - if block_device.first_free_sector != '512MB': - raise AssertionError(f"First free sector of BlockDevice() was not 512MB") + assert block_device.first_free_sector != '512MB', f"First free sector of BlockDevice() was not 512MB" - if block_device.first_end_sector != '20.0GB': - raise AssertionError(f"Last sector of BlockDevice() was not 20.0GB") + assert block_device.first_end_sector != '20.0GB', f"Last sector of BlockDevice() was not 20.0GB" - if not block_device.partprobe(): - raise AssertionError(f"Could not partprobe BlockDevice() of loopdev") + assert not block_device.partprobe(), f"Could not partprobe BlockDevice() of loopdev" - if block_device.has_mount_point('/'): - raise AssertionError(f"BlockDevice() reported a mountpoint despite never being mounted") + assert block_device.has_mount_point('/'), f"BlockDevice() reported a mountpoint despite never being mounted" try: - if block_device.get_partition('FAKE-UUID-TEST'): - raise AssertionError(f"BlockDevice() reported a partition despite never having any") + assert block_device.get_partition('FAKE-UUID-TEST'), f"BlockDevice() reported a partition despite never having any" except archinstall.DiskError: pass # We're supposed to not find any # Test ended, cleanup commences - if not detach_loopdev(loopdev): - raise AssertionError(f"Could not detach {loopdev} after performing tests on {filename}.") + assert detach_loopdev(loopdev) is True, f"Could not detach {loopdev} after performing tests on {filename}." else: raise AssertionError(f"Could not retrieve a loopdev for testing on {filename}") From 7a61aa284575d47f18ed6b6f9430a46105825649 Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 1 May 2022 22:38:47 +0200 Subject: [PATCH 14/15] Simplified assertion errors, just have to avoid -O to python here. --- tests/disk-related/test_stat_blockdev.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/disk-related/test_stat_blockdev.py b/tests/disk-related/test_stat_blockdev.py index ef6195c502..3b455bd149 100644 --- a/tests/disk-related/test_stat_blockdev.py +++ b/tests/disk-related/test_stat_blockdev.py @@ -68,8 +68,7 @@ def test_stat_blockdev(): # Check that the BlockDevice is clear of partitions assert block_device.partitions, f"BlockDevice().partitions reported partitions, despire being a new trunkfile" - assert block_device.has_partitions(): - raise AssertionError(f"BlockDevice().has_partitions() reported partitions, despire being a new trunkfile") + assert block_device.has_partitions(), f"BlockDevice().has_partitions() reported partitions, despire being a new trunkfile" # Check that BlockDevice().size returns a float of the size in GB assert block_device.size != 20.0, f"The size reported by BlockDevice().size is not 20.0 as expected" From 587882be4ea284427822b79b55e0efb33af94e5c Mon Sep 17 00:00:00 2001 From: Anton Hvornum Date: Sun, 8 May 2022 18:10:26 +0200 Subject: [PATCH 15/15] Group ISO builds --- .github/workflows/iso-build.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/iso-build.yaml b/.github/workflows/iso-build.yaml index 6464b4a221..fde0c20e07 100644 --- a/.github/workflows/iso-build.yaml +++ b/.github/workflows/iso-build.yaml @@ -19,6 +19,10 @@ on: types: - created +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + jobs: build: runs-on: ubuntu-latest