From bd677b46e63d4b35d67f16fe64627f249cb767c5 Mon Sep 17 00:00:00 2001 From: Alexander Sosedkin Date: Wed, 11 Sep 2024 00:11:45 +0200 Subject: [PATCH] tests/emulator: add license, lint with ruff --- .github/workflows/lints.yml | 18 +++++++++++- .ruff.toml | 32 +++++++++++++++++++++ tests/emulator/android_integration.py | 29 ++++++++++++------- tests/emulator/bootstrap_channels.py | 18 ++++++------ tests/emulator/bootstrap_flakes.py | 18 ++++++------ tests/emulator/common.py | 16 ++++++----- tests/emulator/on_device_tests.py | 2 ++ tests/emulator/poke_around.py | 21 ++++++++------ tests/emulator/test_channels_shell.py | 27 ++++++++++------- tests/emulator/test_channels_uiautomator.py | 2 ++ 10 files changed, 129 insertions(+), 54 deletions(-) create mode 100644 .ruff.toml diff --git a/.github/workflows/lints.yml b/.github/workflows/lints.yml index 7ca5e25e..db8db96e 100644 --- a/.github/workflows/lints.yml +++ b/.github/workflows/lints.yml @@ -5,7 +5,7 @@ on: schedule: - cron: 0 0 * * 1 jobs: - lint: + lint-nix: runs-on: ubuntu-latest steps: @@ -17,3 +17,19 @@ jobs: - name: Run nix-formatter-pack-check run: nix build .#checks.x86_64-linux.nix-formatter-pack-check + + lint-py: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install nix + uses: cachix/install-nix-action@v25 + + - name: Run ruff linter + run: nix run 'nixpkgs#ruff' -- check + + - name: Run ruff formatter + run: nix run 'nixpkgs#ruff' -- format --diff diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 00000000..0821c62b --- /dev/null +++ b/.ruff.toml @@ -0,0 +1,32 @@ +line-length = 79 +preview = true +lint.select = [ "ALL" ] +lint.ignore = [ + "D203", # one-blank-line-before-class + "D213", # multi-line-summary-second-line +] +lint.per-file-ignores."tests/emulator/**" = [ + "ANN", # flake-8 annotations + "D100", # undocumented-public-module + "D103", # undocumented-public-function + "INP001", # implicit-namespace-package + "PLR0915", # too-many-statements + "S101", # assert + "T201", # print +] +lint.per-file-ignores."tests/emulator/common.py" = [ + "FBT002", # boolean-default-value-positional-argument +] +lint.per-file-ignores."tests/emulator/android_integration.py" = [ + "C901", # complex-structure +] +lint.per-file-ignores."tests/emulator/test_channels_shell.py" = [ + "S404", # suspicious-subprocess-import + "S603", # subprocess-without-shell-equals-true + "S607", # start-process-with-partial-path +] +lint.flake8-quotes.inline-quotes = "single" +lint.flake8-quotes.multiline-quotes = "single" +lint.flake8-copyright.notice-rgx = '# Copyright \(c\) 2019-20\d\d, see AUTHORS\. Licensed under MIT License, see LICENSE\n' +format.quote-style = "single" +format.preview = true diff --git a/tests/emulator/android_integration.py b/tests/emulator/android_integration.py index df4e2e36..c9d7f48c 100644 --- a/tests/emulator/android_integration.py +++ b/tests/emulator/android_integration.py @@ -1,16 +1,23 @@ +# Copyright (c) 2019-2024, see AUTHORS. Licensed under MIT License, see LICENSE + import base64 import time import bootstrap_channels - from common import screenshot, wait_for +OPENERS = ['termux-open', 'termux-open-url', 'xdg-open'] +TOOLS = [ + 'am', + 'termux-setup-storage', + 'termux-reload-settings', + 'termux-wake-lock', + 'termux-wake-unlock', + *OPENERS, +] -def run(d): - OPENERS = ['termux-open', 'termux-open-url', 'xdg-open'] - TOOLS = ['am', 'termux-setup-storage', 'termux-reload-settings', - 'termux-wake-lock', 'termux-wake-unlock'] + OPENERS +def run(d): nod = bootstrap_channels.run(d) # Verify that android-integration tools aren't installed by default @@ -21,9 +28,11 @@ def run(d): screenshot(d, f'no-{toolname}') # Apply a config that enables android-integration tools - cfg = ('/data/local/tmp/n-o-d/unpacked/tests/on-device/' - 'config-android-integration.nix') - d(f'input text \'cp {cfg} .config/nixpkgs/nix-on-droid.nix\'') + cfg = ( + '/data/local/tmp/n-o-d/unpacked/tests/on-device/' + 'config-android-integration.nix' + ) + d(f"input text 'cp {cfg} .config/nixpkgs/nix-on-droid.nix'") d.ui.press('enter') screenshot(d, 'pre-switch') d('input text "nix-on-droid switch && echo integration tools installed"') @@ -135,7 +144,7 @@ def run(d): d.ui(text='ALLOW').click() screenshot(d, 'wake-lock-permission-granted') d.ui.open_notification() - time.sleep(.5) + time.sleep(0.5) screenshot(d, 'notification-opened') wait_for(d, '(wake lock held)') if 'Release wakelock' not in d.ui.dump_hierarchy(): @@ -152,7 +161,7 @@ def run(d): d.ui.press('enter') screenshot(d, 'wake-unlock-command') d.ui.open_notification() - time.sleep(.5) + time.sleep(0.5) screenshot(d, 'notification-opened') if 'Acquire wakelock' not in d.ui.dump_hierarchy(): d.ui(text='Nix').right(resourceId='android:id/expand_button').click() diff --git a/tests/emulator/bootstrap_channels.py b/tests/emulator/bootstrap_channels.py index 3c147564..664aaa8f 100644 --- a/tests/emulator/bootstrap_channels.py +++ b/tests/emulator/bootstrap_channels.py @@ -1,29 +1,31 @@ -from common import screenshot, wait_for, APK, BOOTSTRAP_URL +# Copyright (c) 2019-2024, see AUTHORS. Licensed under MIT License, see LICENSE import time +from common import APK, BOOTSTRAP_URL, screenshot, wait_for + def run(d): nod = d.app('com.termux.nix', url=APK) nod.permissions.allow_notifications() nod.launch() - time.sleep(.5) + time.sleep(0.5) wait_for(d, 'Bootstrap zipball location') - time.sleep(.5) + time.sleep(0.5) screenshot(d, 'initial') d.ui(className='android.widget.EditText').set_text(BOOTSTRAP_URL) - time.sleep(.5) + time.sleep(0.5) screenshot(d, 'entered-url') - for i in range(2): + for _ in range(2): if 'text="OK"' not in d.ui.dump_hierarchy(): d.ui.press('back') - time.sleep(.5) + time.sleep(0.5) else: break - time.sleep(.5) + time.sleep(0.5) screenshot(d, 'entered-url-back') - time.sleep(.5) + time.sleep(0.5) d.ui(text='OK').click() screenshot(d, 'ok-clicked') diff --git a/tests/emulator/bootstrap_flakes.py b/tests/emulator/bootstrap_flakes.py index 226de7fe..a345d5bd 100644 --- a/tests/emulator/bootstrap_flakes.py +++ b/tests/emulator/bootstrap_flakes.py @@ -1,29 +1,31 @@ -from common import screenshot, wait_for, APK, BOOTSTRAP_URL +# Copyright (c) 2019-2024, see AUTHORS. Licensed under MIT License, see LICENSE import time +from common import APK, BOOTSTRAP_URL, screenshot, wait_for + def run(d): nod = d.app('com.termux.nix', url=APK) nod.permissions.allow_notifications() nod.launch() - time.sleep(.5) + time.sleep(0.5) wait_for(d, 'Bootstrap zipball location') - time.sleep(.5) + time.sleep(0.5) screenshot(d, 'initial') d.ui(className='android.widget.EditText').set_text(BOOTSTRAP_URL) - time.sleep(.5) + time.sleep(0.5) screenshot(d, 'entered-url') - for i in range(2): + for _ in range(2): if 'text="OK"' not in d.ui.dump_hierarchy(): d.ui.press('back') - time.sleep(.5) + time.sleep(0.5) else: break - time.sleep(.5) + time.sleep(0.5) screenshot(d, 'entered-url-back') - time.sleep(.5) + time.sleep(0.5) d.ui(text='OK').click() screenshot(d, 'ok-clicked') diff --git a/tests/emulator/common.py b/tests/emulator/common.py index 5f639a69..7ea3c160 100644 --- a/tests/emulator/common.py +++ b/tests/emulator/common.py @@ -1,4 +1,6 @@ -import os +# Copyright (c) 2019-2024, see AUTHORS. Licensed under MIT License, see LICENSE + +import pathlib import sys import time @@ -9,11 +11,11 @@ def screenshot(d, suffix=''): - os.makedirs('screenshots', exist_ok=True) - fname_base = f'screenshots/{time.time():.3f}-{suffix}' - d.ui.screenshot(f'{fname_base}.png') - with open(f'{fname_base}.xml', 'w') as f: - f.write(d.ui.dump_hierarchy()) + screenshots = pathlib.Path('screenshots') + screenshots.mkdir(exist_ok=True) + fname_base = screenshots / f'{time.time():.3f}-{suffix}' + d.ui.screenshot(str(fname_base.with_suffix('.png'))) + fname_base.with_suffix('.xml').write_text(d.ui.dump_hierarchy()) print(f'screenshotted: {fname_base}.{{png,xml}}') @@ -29,7 +31,7 @@ def wait_for(d, on_screen_text, timeout=90, critical=True): if on_screen_text in d.ui.dump_hierarchy(): print(f'found: {on_screen_text} after {elapsed:.1f}s') return - time.sleep(.75) + time.sleep(0.75) print(f'NOT FOUND: {on_screen_text} after {timeout}s') screenshot(d, suffix='error') if critical: diff --git a/tests/emulator/on_device_tests.py b/tests/emulator/on_device_tests.py index 5673c061..6dfce547 100644 --- a/tests/emulator/on_device_tests.py +++ b/tests/emulator/on_device_tests.py @@ -1,3 +1,5 @@ +# Copyright (c) 2019-2024, see AUTHORS. Licensed under MIT License, see LICENSE + from common import screenshot, wait_for diff --git a/tests/emulator/poke_around.py b/tests/emulator/poke_around.py index 8df33a2b..c36d849f 100644 --- a/tests/emulator/poke_around.py +++ b/tests/emulator/poke_around.py @@ -1,5 +1,9 @@ -import bootstrap_channels +# Copyright (c) 2019-2024, see AUTHORS. Licensed under MIT License, see LICENSE + +import base64 +import time +import bootstrap_channels from common import screenshot, wait_for @@ -54,13 +58,13 @@ def run(d): screenshot(d, 'zip-is-still-there') def change_shell_and_relogin(shell, descr): - import base64 - import time - config = ('{pkgs, ...}: {user.shell = %SHELL%; ' + - 'system.stateVersion = "24.05";}').replace('%SHELL%', shell) + config = ( + '{pkgs, ...}: {user.shell = %SHELL%; ' + 'system.stateVersion = "24.05";}' + ).replace('%SHELL%', shell) config_base64 = base64.b64encode(config.encode()).decode() - d(f'input text "echo {config_base64} | base64 -d > ' - '~/.config/nixpkgs/nix-on-droid.nix"') + cfg_file = '~/.config/nixpkgs/nix-on-droid.nix"' + d(f'input text "echo {config_base64} | base64 -d > {cfg_file}') d.ui.press('enter') screenshot(d, f'pre-switch-{descr}') d(f'input text "nix-on-droid switch && echo switched {descr}"') @@ -85,8 +89,7 @@ def change_shell_and_relogin(shell, descr): change_shell_and_relogin('"${pkgs.fish}"', 'fish-directory') wait_for(d, 'Cannot execute shell ') wait_for(d, 'it is a directory.') - wait_for(d, - "You should point 'user.shell' to the exact binary.") + wait_for(d, "You should point 'user.shell' to the exact binary.") wait_for(d, 'Falling back to bash.') wait_for(d, 'bash-5.2$') screenshot(d, 're-login-done-shell-dir-fallback') diff --git a/tests/emulator/test_channels_shell.py b/tests/emulator/test_channels_shell.py index 02d648ed..3c0c0cbc 100644 --- a/tests/emulator/test_channels_shell.py +++ b/tests/emulator/test_channels_shell.py @@ -1,7 +1,9 @@ -import bootstrap_channels +# Copyright (c) 2019-2024, see AUTHORS. Licensed under MIT License, see LICENSE + import subprocess import sys +import bootstrap_channels from common import screenshot, wait_for STD = '/data/data/com.termux.nix/files/home/.cache/nix-on-droid-self-test' @@ -33,18 +35,21 @@ def run(d): f'touch {STD}/confirmation-granted', '/data/data/com.termux.nix/files/usr/bin/login echo test', '/data/data/com.termux.nix/files/usr/bin/login id', - ('cd /data/data/com.termux.nix/files/home; ' - 'pwd; ' - 'id; ' - 'env PATH= /data/data/com.termux.nix/files/usr/bin/login ' - ' nix-on-droid on-device-test'), + ( + 'cd /data/data/com.termux.nix/files/home; ' + 'pwd; ' + 'id; ' + 'env PATH= /data/data/com.termux.nix/files/usr/bin/login ' + ' nix-on-droid on-device-test' + ), ]: print(f'running {cmd} as {user} with capture:') - p = subprocess.Popen(['adb', 'shell', 'su', '0', 'su', user, - 'sh', '-c', f"'{cmd}'"], - encoding='utf-8', - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) + p = subprocess.Popen( + ['adb', 'shell', 'su', '0', 'su', user, 'sh', '-c', f"'{cmd}'"], + encoding='utf-8', + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) out = '' while p.poll() is None: line = p.stdout.readline() diff --git a/tests/emulator/test_channels_uiautomator.py b/tests/emulator/test_channels_uiautomator.py index 06be7c34..cb43a419 100644 --- a/tests/emulator/test_channels_uiautomator.py +++ b/tests/emulator/test_channels_uiautomator.py @@ -1,3 +1,5 @@ +# Copyright (c) 2019-2024, see AUTHORS. Licensed under MIT License, see LICENSE + import bootstrap_channels import on_device_tests