commit: 43e2ea97f397a796d3a4fa9e35bbf1cd5336ceff
Author: Michał Górny <mgorny <AT> gentoo <DOT> org>
AuthorDate: Sat Dec 13 15:13:25 2025 +0000
Commit: Michał Górny <mgorny <AT> gentoo <DOT> org>
CommitDate: Sat Dec 13 15:13:25 2025 +0000
URL: https://gitweb.gentoo.org/proj/steve.git/commit/?id=43e2ea97
Add initial tests
Signed-off-by: Michał Górny <mgorny <AT> gentoo.org>
.gitignore | 1 +
meson.build | 30 +++++++++++++++++++++++-------
meson.options | 4 ++++
test/conftest.py | 42 ++++++++++++++++++++++++++++++++++++++++++
test/test_steve.py | 19 +++++++++++++++++++
5 files changed, 89 insertions(+), 7 deletions(-)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..04a41a2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+**.pyc
diff --git a/meson.build b/meson.build
index c00d515..db20496 100644
--- a/meson.build
+++ b/meson.build
@@ -7,17 +7,33 @@ project('steve', 'cpp',
version = meson.project_version()
if get_option('client')
- executable('stevie', ['stevie.cxx'],
- cpp_args : [f'-DSTEVE_VERSION="@version@"'],
- install : true)
+ executable(
+ 'stevie',
+ ['stevie.cxx'],
+ cpp_args : [f'-DSTEVE_VERSION="@version@"'],
+ install : true)
endif
if get_option('server')
fuse3 = dependency('fuse3')
libevent = dependency('libevent', version: '>= 2')
- executable('steve', ['steve.cxx'],
- cpp_args : [f'-DSTEVE_VERSION="@version@"'],
- dependencies: [fuse3, libevent],
- install : true)
+ steve = executable(
+ 'steve',
+ ['steve.cxx'],
+ cpp_args : [f'-DSTEVE_VERSION="@version@"'],
+ dependencies: [fuse3, libevent],
+ install : true)
+
+ if get_option('test')
+ pytest = find_program('pytest')
+ source_root = meson.source_root()
+ test('pytest',
+ pytest,
+ args : [f'@source_root@/test'],
+ env : {
+ 'PYTEST_DISABLE_PLUGIN_AUTOLOAD': '1',
+ 'STEVE': steve.path(),
+ })
+ endif
endif
diff --git a/meson.options b/meson.options
index 8a312bf..af22b97 100644
--- a/meson.options
+++ b/meson.options
@@ -6,3 +6,7 @@ option('server',
type: 'boolean',
value: true,
description: 'Build the server')
+option('test',
+ type: 'boolean',
+ value: false,
+ description: 'Enable testing (requires pytest)')
diff --git a/test/conftest.py b/test/conftest.py
new file mode 100644
index 0000000..894f265
--- /dev/null
+++ b/test/conftest.py
@@ -0,0 +1,42 @@
+from __future__ import annotations
+
+import os
+import subprocess
+import time
+from pathlib import Path
+
+import pytest
+
+
+class Steve:
+ dev_name: str | None = None
+ dev_path: str | None = None
+ subprocess: subprocess.Popen | None = None
+ retval: int | None = None
+
+ def start(self, args: list[str]) -> None:
+ self.dev_name = f"steve.test.{os.getpid()}"
+ self.dev_path = Path(f"/dev/{self.dev_name}")
+ self.subprocess = subprocess.Popen(
+ [os.environ.get("STEVE", "steve"), "--dev-name", self.dev_name,
*args]
+ )
+
+ # wait for device to appear
+ for attempt in range(15):
+ if self.dev_path.exists():
+ break
+ time.sleep(0.1 * attempt)
+ else:
+ raise RuntimeError("Steve failed to start")
+
+ def terminate(self) -> None:
+ if self.subprocess is not None:
+ self.subprocess.terminate()
+ self.retval = self.subprocess.wait()
+
+
[email protected]
+def steve() -> Steve:
+ steve = Steve()
+ yield steve
+ steve.terminate()
diff --git a/test/test_steve.py b/test/test_steve.py
new file mode 100644
index 0000000..3612f4c
--- /dev/null
+++ b/test/test_steve.py
@@ -0,0 +1,19 @@
+import os
+
+
+def test_basic(steve):
+ steve.start(["-j", "5"])
+ with steve.dev_path.open("r+b") as f:
+ tokens = f.read(5)
+ assert len(tokens) == 5
+ f.write(tokens)
+
+
+def test_too_many(steve):
+ steve.start(["-j", "5"])
+ with steve.dev_path.open("r+b") as f:
+ os.set_blocking(f.fileno(), False)
+ tokens = f.read(6)
+ assert len(tokens) == 5
+ assert f.read(1) is None
+ f.write(tokens)