|
4ce269c…
|
ragelink
|
1 |
import pytest |
|
4ce269c…
|
ragelink
|
2 |
from django.contrib.auth.models import Group, Permission, User |
|
4ce269c…
|
ragelink
|
3 |
|
|
4ce269c…
|
ragelink
|
4 |
from organization.models import Organization, OrganizationMember, Team |
|
4ce269c…
|
ragelink
|
5 |
from pages.models import Page |
|
4ce269c…
|
ragelink
|
6 |
from projects.models import Project, ProjectTeam |
|
313537c…
|
ragelink
|
7 |
|
|
313537c…
|
ragelink
|
8 |
|
|
313537c…
|
ragelink
|
9 |
@pytest.fixture(autouse=True) |
|
313537c…
|
ragelink
|
10 |
def _fossil_data_dir(tmp_path, settings): |
|
313537c…
|
ragelink
|
11 |
"""Point FOSSIL_DATA_DIR to a temp directory so tests don't need /data/repos.""" |
|
313537c…
|
ragelink
|
12 |
data_dir = tmp_path / "fossil-repos" |
|
313537c…
|
ragelink
|
13 |
data_dir.mkdir() |
|
313537c…
|
ragelink
|
14 |
# Override the constance default via Django's CONSTANCE_CONFIG setting |
|
313537c…
|
ragelink
|
15 |
settings.CONSTANCE_CONFIG = { |
|
313537c…
|
ragelink
|
16 |
**settings.CONSTANCE_CONFIG, |
|
313537c…
|
ragelink
|
17 |
"FOSSIL_DATA_DIR": (str(data_dir), "Directory where .fossil repository files are stored"), |
|
313537c…
|
ragelink
|
18 |
} |
|
313537c…
|
ragelink
|
19 |
# Also set via constance DB backend if already cached |
|
313537c…
|
ragelink
|
20 |
try: |
|
313537c…
|
ragelink
|
21 |
from constance import config |
|
313537c…
|
ragelink
|
22 |
|
|
313537c…
|
ragelink
|
23 |
config.FOSSIL_DATA_DIR = str(data_dir) |
|
313537c…
|
ragelink
|
24 |
except Exception: |
|
313537c…
|
ragelink
|
25 |
pass |
|
c588255…
|
ragelink
|
26 |
|
|
c588255…
|
ragelink
|
27 |
|
|
4ce269c…
|
ragelink
|
28 |
@pytest.fixture |
|
4ce269c…
|
ragelink
|
29 |
def admin_user(db): |
|
4ce269c…
|
ragelink
|
30 |
user = User.objects.create_superuser(username="admin", email="[email protected]", password="testpass123") |
|
4ce269c…
|
ragelink
|
31 |
return user |
|
4ce269c…
|
ragelink
|
32 |
|
|
4ce269c…
|
ragelink
|
33 |
|
|
4ce269c…
|
ragelink
|
34 |
@pytest.fixture |
|
4ce269c…
|
ragelink
|
35 |
def viewer_user(db): |
|
4ce269c…
|
ragelink
|
36 |
user = User.objects.create_user(username="viewer", email="[email protected]", password="testpass123") |
|
4ce269c…
|
ragelink
|
37 |
group, _ = Group.objects.get_or_create(name="Viewers") |
|
4ce269c…
|
ragelink
|
38 |
view_perms = Permission.objects.filter( |
|
c588255…
|
ragelink
|
39 |
content_type__app_label__in=["organization", "projects", "pages"], |
|
4ce269c…
|
ragelink
|
40 |
codename__startswith="view_", |
|
4ce269c…
|
ragelink
|
41 |
) |
|
4ce269c…
|
ragelink
|
42 |
group.permissions.set(view_perms) |
|
4ce269c…
|
ragelink
|
43 |
user.groups.add(group) |
|
4ce269c…
|
ragelink
|
44 |
return user |
|
4ce269c…
|
ragelink
|
45 |
|
|
4ce269c…
|
ragelink
|
46 |
|
|
4ce269c…
|
ragelink
|
47 |
@pytest.fixture |
|
4ce269c…
|
ragelink
|
48 |
def no_perm_user(db): |
|
4ce269c…
|
ragelink
|
49 |
return User.objects.create_user(username="noperm", email="[email protected]", password="testpass123") |
|
4ce269c…
|
ragelink
|
50 |
|
|
4ce269c…
|
ragelink
|
51 |
|
|
4ce269c…
|
ragelink
|
52 |
@pytest.fixture |
|
4ce269c…
|
ragelink
|
53 |
def org(db, admin_user): |
|
4ce269c…
|
ragelink
|
54 |
org = Organization.objects.create(name="Test Org", created_by=admin_user) |
|
4ce269c…
|
ragelink
|
55 |
OrganizationMember.objects.create(member=admin_user, organization=org) |
|
4ce269c…
|
ragelink
|
56 |
return org |
|
4ce269c…
|
ragelink
|
57 |
|
|
4ce269c…
|
ragelink
|
58 |
|
|
4ce269c…
|
ragelink
|
59 |
@pytest.fixture |
|
4ce269c…
|
ragelink
|
60 |
def sample_team(db, org, admin_user): |
|
4ce269c…
|
ragelink
|
61 |
team = Team.objects.create(name="Core Devs", organization=org, created_by=admin_user) |
|
4ce269c…
|
ragelink
|
62 |
team.members.add(admin_user) |
|
4ce269c…
|
ragelink
|
63 |
return team |
|
4ce269c…
|
ragelink
|
64 |
|
|
4ce269c…
|
ragelink
|
65 |
|
|
4ce269c…
|
ragelink
|
66 |
@pytest.fixture |
|
4ce269c…
|
ragelink
|
67 |
def sample_project(db, org, admin_user, sample_team): |
|
4ce269c…
|
ragelink
|
68 |
project = Project.objects.create(name="Frontend App", organization=org, visibility="private", created_by=admin_user) |
|
4ce269c…
|
ragelink
|
69 |
ProjectTeam.objects.create(project=project, team=sample_team, role="write", created_by=admin_user) |
|
4ce269c…
|
ragelink
|
70 |
return project |
|
4ce269c…
|
ragelink
|
71 |
|
|
4ce269c…
|
ragelink
|
72 |
|
|
4ce269c…
|
ragelink
|
73 |
@pytest.fixture |
|
4ce269c…
|
ragelink
|
74 |
def sample_page(db, org, admin_user): |
|
4ce269c…
|
ragelink
|
75 |
return Page.objects.create( |
|
4ce269c…
|
ragelink
|
76 |
name="Getting Started", |
|
4ce269c…
|
ragelink
|
77 |
content="# Getting Started\n\nWelcome to the docs.", |
|
4ce269c…
|
ragelink
|
78 |
organization=org, |
|
4ce269c…
|
ragelink
|
79 |
created_by=admin_user, |
|
4ce269c…
|
ragelink
|
80 |
) |
|
4ce269c…
|
ragelink
|
81 |
|
|
4ce269c…
|
ragelink
|
82 |
|
|
4ce269c…
|
ragelink
|
83 |
@pytest.fixture |
|
4ce269c…
|
ragelink
|
84 |
def fossil_repo(db, sample_project, admin_user, tmp_path): |
|
4ce269c…
|
ragelink
|
85 |
"""Create a FossilRepository with a real .fossil file for testing.""" |
|
4ce269c…
|
ragelink
|
86 |
import shutil |
|
4ce269c…
|
ragelink
|
87 |
|
|
4ce269c…
|
ragelink
|
88 |
from fossil.models import FossilRepository |
|
4ce269c…
|
ragelink
|
89 |
|
|
4ce269c…
|
ragelink
|
90 |
# Copy a test repo to tmp_path |
|
4ce269c…
|
ragelink
|
91 |
src = "/tmp/fossil-setup/frontend-app.fossil" |
|
4ce269c…
|
ragelink
|
92 |
dest = tmp_path / "test-project.fossil" |
|
4ce269c…
|
ragelink
|
93 |
shutil.copy2(src, dest) |
|
4ce269c…
|
ragelink
|
94 |
|
|
4ce269c…
|
ragelink
|
95 |
# Override FOSSIL_DATA_DIR for this test |
|
4ce269c…
|
ragelink
|
96 |
|
|
4ce269c…
|
ragelink
|
97 |
repo = FossilRepository.objects.create( |
|
4ce269c…
|
ragelink
|
98 |
project=sample_project, |
|
4ce269c…
|
ragelink
|
99 |
filename="test-project.fossil", |
|
4ce269c…
|
ragelink
|
100 |
created_by=admin_user, |
|
4ce269c…
|
ragelink
|
101 |
) |
|
4ce269c…
|
ragelink
|
102 |
# Patch the full_path property to point to our tmp file |
|
4ce269c…
|
ragelink
|
103 |
repo._test_path = dest |
|
4ce269c…
|
ragelink
|
104 |
return repo |
|
4ce269c…
|
ragelink
|
105 |
|
|
4ce269c…
|
ragelink
|
106 |
|
|
4ce269c…
|
ragelink
|
107 |
@pytest.fixture |
|
4ce269c…
|
ragelink
|
108 |
def admin_client(client, admin_user): |
|
4ce269c…
|
ragelink
|
109 |
client.login(username="admin", password="testpass123") |
|
4ce269c…
|
ragelink
|
110 |
return client |
|
4ce269c…
|
ragelink
|
111 |
|
|
4ce269c…
|
ragelink
|
112 |
|
|
4ce269c…
|
ragelink
|
113 |
@pytest.fixture |
|
4ce269c…
|
ragelink
|
114 |
def viewer_client(client, viewer_user): |
|
4ce269c…
|
ragelink
|
115 |
client.login(username="viewer", password="testpass123") |
|
4ce269c…
|
ragelink
|
116 |
return client |
|
4ce269c…
|
ragelink
|
117 |
|
|
4ce269c…
|
ragelink
|
118 |
|
|
4ce269c…
|
ragelink
|
119 |
@pytest.fixture |
|
4ce269c…
|
ragelink
|
120 |
def no_perm_client(client, no_perm_user): |
|
4ce269c…
|
ragelink
|
121 |
client.login(username="noperm", password="testpass123") |
|
4ce269c…
|
ragelink
|
122 |
return client |