test: add simplified file permissions test
Add a test that validates file permissions, ownership, and service access for key Nixarr services. The test verifies: - Users and groups exist with correct membership - Directory ownership matches expected patterns - Services can write/read files in media directories - Cross-seed can access transmission state - fix-permissions command works correctly 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
# Comprehensive test for Nixarr file permissions, user/group creation, and directory structure
|
||||
{
|
||||
pkgs,
|
||||
nixosModules,
|
||||
lib ? pkgs.lib,
|
||||
}:
|
||||
pkgs.nixosTest {
|
||||
name = "nixarr-permissions-test";
|
||||
|
||||
nodes.machine = {
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
imports = [nixosModules.default];
|
||||
|
||||
networking.firewall.enable = false;
|
||||
|
||||
nixarr = {
|
||||
enable = true;
|
||||
stateDir = "/data/.state/nixarr";
|
||||
mediaDir = "/data/media";
|
||||
mediaUsers = ["testuser"];
|
||||
|
||||
# Enable key services to trigger tmpfiles directory creation
|
||||
jellyfin.enable = true;
|
||||
|
||||
transmission = {
|
||||
enable = true;
|
||||
vpn.enable = false;
|
||||
privateTrackers.cross-seed.enable = true;
|
||||
};
|
||||
|
||||
sonarr = {
|
||||
enable = true;
|
||||
vpn.enable = false;
|
||||
};
|
||||
|
||||
radarr = {
|
||||
enable = true;
|
||||
vpn.enable = false;
|
||||
};
|
||||
|
||||
lidarr = {
|
||||
enable = true;
|
||||
vpn.enable = false;
|
||||
};
|
||||
|
||||
prowlarr = {
|
||||
enable = true;
|
||||
vpn.enable = false;
|
||||
};
|
||||
};
|
||||
|
||||
# Create a test user to verify mediaUsers functionality
|
||||
users.users.testuser = {
|
||||
isNormalUser = true;
|
||||
home = "/home/testuser";
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
print("Starting Nixarr permissions test...")
|
||||
|
||||
# Test 1: Verify key users and groups exist
|
||||
print("\n=== Testing User/Group Creation ===")
|
||||
|
||||
# Check essential users exist
|
||||
key_users = ["jellyfin", "transmission", "cross-seed", "sonarr", "radarr", "testuser"]
|
||||
for user in key_users:
|
||||
machine.succeed(f"id {user}")
|
||||
print(f"✓ User {user} exists")
|
||||
|
||||
# Check media group exists and has correct members
|
||||
media_members = machine.succeed("getent group media | cut -d: -f4").strip()
|
||||
expected_members = ["jellyfin", "transmission", "sonarr", "radarr", "lidarr", "testuser"]
|
||||
for member in expected_members:
|
||||
if member in media_members:
|
||||
print(f"✓ {member} is in media group")
|
||||
else:
|
||||
machine.fail(f"{member} not in media group")
|
||||
|
||||
# Check cross-seed group membership
|
||||
cross_seed_members = machine.succeed("getent group cross-seed | cut -d: -f4").strip()
|
||||
if "transmission" in cross_seed_members:
|
||||
print("✓ transmission is in cross-seed group")
|
||||
|
||||
# Test 2: Verify directory structure and ownership
|
||||
print("\n=== Testing Directory Permissions ===")
|
||||
|
||||
def check_dir(path, expected_user, expected_group, description):
|
||||
stat_output = machine.succeed(f"stat -c '%U:%G' '{path}'").strip()
|
||||
user, group = stat_output.split(":")
|
||||
if user == expected_user and group == expected_group:
|
||||
print(f"✓ {description}: {user}:{group}")
|
||||
else:
|
||||
machine.fail(f"{description} has wrong ownership: {user}:{group}, expected {expected_user}:{expected_group}")
|
||||
|
||||
# Check key directories exist with correct ownership
|
||||
check_dir("/data/media", "root", "media", "Media root directory")
|
||||
check_dir("/data/media/library/movies", "root", "media", "Movies directory")
|
||||
check_dir("/data/media/library/shows", "root", "media", "Shows directory")
|
||||
check_dir("/data/media/library/music", "root", "media", "Music directory")
|
||||
check_dir("/data/media/torrents", "transmission", "media", "Torrents directory")
|
||||
|
||||
if machine.succeed("test -d '/data/media/torrents/.cross-seed' && echo 'exists' || echo 'missing'").strip() == "exists":
|
||||
check_dir("/data/media/torrents/.cross-seed", "cross-seed", "cross-seed", "Cross-seed directory")
|
||||
|
||||
# Test 3: Verify service file access
|
||||
print("\n=== Testing Service File Access ===")
|
||||
|
||||
# Test Jellyfin can write to media directories
|
||||
test_dirs = ["/data/media/library/movies", "/data/media/library/shows"]
|
||||
for test_dir in test_dirs:
|
||||
if machine.succeed(f"test -d '{test_dir}' && echo 'exists' || echo 'missing'").strip() == "exists":
|
||||
test_file = f"{test_dir}/jellyfin-test.txt"
|
||||
machine.succeed(f"sudo -u jellyfin touch '{test_file}'")
|
||||
machine.succeed(f"sudo -u jellyfin sh -c 'echo test > {test_file}'")
|
||||
content = machine.succeed(f"cat '{test_file}'").strip()
|
||||
if content != "test":
|
||||
machine.fail(f"Expected 'test' but got '{content}'")
|
||||
machine.succeed(f"sudo -u jellyfin rm '{test_file}'")
|
||||
print(f"✓ Jellyfin can write/read/delete in {test_dir}")
|
||||
|
||||
# Test cross-seed can access transmission state
|
||||
trans_state = "/data/.state/nixarr/transmission"
|
||||
if machine.succeed(f"test -d '{trans_state}' && echo 'exists' || echo 'missing'").strip() == "exists":
|
||||
result = machine.succeed(f"sudo -u cross-seed test -r '{trans_state}' && echo 'readable' || echo 'not-readable'").strip()
|
||||
if result == "readable":
|
||||
print("✓ cross-seed can read transmission state directory")
|
||||
else:
|
||||
machine.fail("cross-seed cannot read transmission state directory")
|
||||
|
||||
# Test 4: Verify fix-permissions command
|
||||
print("\n=== Testing fix-permissions Command ===")
|
||||
|
||||
# Create file with wrong permissions
|
||||
test_file = "/data/media/library/movies/test-wrong-perms.txt"
|
||||
if machine.succeed("test -d '/data/media/library/movies' && echo 'exists' || echo 'missing'").strip() == "exists":
|
||||
machine.succeed(f"umask 077 && touch '{test_file}'")
|
||||
|
||||
# Verify initial permissions are wrong
|
||||
initial_perms = machine.succeed(f"stat -c '%a' '{test_file}'").strip()
|
||||
if initial_perms != "600":
|
||||
machine.fail(f"Expected 600 permissions, got {initial_perms}")
|
||||
|
||||
machine.succeed("nixarr fix-permissions")
|
||||
|
||||
# Verify permissions were fixed
|
||||
fixed_perms = machine.succeed(f"stat -c '%a' '{test_file}'").strip()
|
||||
if fixed_perms not in ["644", "664"]:
|
||||
machine.fail(f"fix-permissions failed: permissions are {fixed_perms}, expected 644 or 664")
|
||||
|
||||
machine.succeed(f"rm '{test_file}'")
|
||||
print(f"✓ fix-permissions corrected file permissions from 600 to {fixed_perms}")
|
||||
|
||||
print("\n=== All Permission Tests Completed ===")
|
||||
'';
|
||||
}
|
||||
Reference in New Issue
Block a user