[WEB-5044] fix: ruff lint and format errors (#7868)
* fix: lint errors * fix: file formatting * fix: code refactor
This commit is contained in:
parent
1fb22bd252
commit
9237f568dd
261 changed files with 2199 additions and 6378 deletions
|
|
@ -103,9 +103,7 @@ class TestLabelListCreateAPIEndpoint:
|
|||
assert created_label.external_source == "github"
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_create_label_duplicate_external_id(
|
||||
self, api_key_client, workspace, project
|
||||
):
|
||||
def test_create_label_duplicate_external_id(self, api_key_client, workspace, project):
|
||||
"""Test creating label with duplicate external ID"""
|
||||
url = self.get_label_url(workspace.slug, project.id)
|
||||
|
||||
|
|
@ -131,19 +129,13 @@ class TestLabelListCreateAPIEndpoint:
|
|||
assert "same external id" in response.data["error"]
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_list_labels_success(
|
||||
self, api_key_client, workspace, project, create_label
|
||||
):
|
||||
def test_list_labels_success(self, api_key_client, workspace, project, create_label):
|
||||
"""Test successful label listing"""
|
||||
url = self.get_label_url(workspace.slug, project.id)
|
||||
|
||||
# Create additional labels
|
||||
Label.objects.create(
|
||||
name="Label 2", project=project, workspace=workspace, color="#00FF00"
|
||||
)
|
||||
Label.objects.create(
|
||||
name="Label 3", project=project, workspace=workspace, color="#0000FF"
|
||||
)
|
||||
Label.objects.create(name="Label 2", project=project, workspace=workspace, color="#00FF00")
|
||||
Label.objects.create(name="Label 3", project=project, workspace=workspace, color="#0000FF")
|
||||
|
||||
response = api_key_client.get(url)
|
||||
|
||||
|
|
@ -184,9 +176,7 @@ class TestLabelDetailAPIEndpoint:
|
|||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_update_label_success(
|
||||
self, api_key_client, workspace, project, create_label
|
||||
):
|
||||
def test_update_label_success(self, api_key_client, workspace, project, create_label):
|
||||
"""Test successful label update"""
|
||||
url = self.get_label_detail_url(workspace.slug, project.id, create_label.id)
|
||||
|
||||
|
|
@ -202,9 +192,7 @@ class TestLabelDetailAPIEndpoint:
|
|||
assert create_label.name == update_data["name"]
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_update_label_invalid_data(
|
||||
self, api_key_client, workspace, project, create_label
|
||||
):
|
||||
def test_update_label_invalid_data(self, api_key_client, workspace, project, create_label):
|
||||
"""Test label update with invalid data"""
|
||||
url = self.get_label_detail_url(workspace.slug, project.id, create_label.id)
|
||||
|
||||
|
|
@ -215,9 +203,7 @@ class TestLabelDetailAPIEndpoint:
|
|||
assert response.status_code in [status.HTTP_400_BAD_REQUEST, status.HTTP_200_OK]
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_delete_label_success(
|
||||
self, api_key_client, workspace, project, create_label
|
||||
):
|
||||
def test_delete_label_success(self, api_key_client, workspace, project, create_label):
|
||||
"""Test successful label deletion"""
|
||||
url = self.get_label_detail_url(workspace.slug, project.id, create_label.id)
|
||||
|
||||
|
|
|
|||
|
|
@ -14,9 +14,7 @@ class TestApiTokenEndpoint:
|
|||
|
||||
# POST /user/api-tokens/ tests
|
||||
@pytest.mark.django_db
|
||||
def test_create_api_token_success(
|
||||
self, session_client, create_user, api_token_data
|
||||
):
|
||||
def test_create_api_token_success(self, session_client, create_user, api_token_data):
|
||||
"""Test successful API token creation"""
|
||||
# Arrange
|
||||
session_client.force_authenticate(user=create_user)
|
||||
|
|
@ -38,9 +36,7 @@ class TestApiTokenEndpoint:
|
|||
assert token.label == api_token_data["label"]
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_create_api_token_for_bot_user(
|
||||
self, session_client, create_bot_user, api_token_data
|
||||
):
|
||||
def test_create_api_token_for_bot_user(self, session_client, create_bot_user, api_token_data):
|
||||
"""Test API token creation for bot user"""
|
||||
# Arrange
|
||||
session_client.force_authenticate(user=create_bot_user)
|
||||
|
|
@ -111,9 +107,7 @@ class TestApiTokenEndpoint:
|
|||
APIToken.objects.create(label="Token 1", user=create_user, user_type=0)
|
||||
APIToken.objects.create(label="Token 2", user=create_user, user_type=0)
|
||||
# Create a service token (should be excluded)
|
||||
APIToken.objects.create(
|
||||
label="Service Token", user=create_user, user_type=0, is_service=True
|
||||
)
|
||||
APIToken.objects.create(label="Service Token", user=create_user, user_type=0, is_service=True)
|
||||
url = reverse("api-tokens")
|
||||
|
||||
# Act
|
||||
|
|
@ -140,9 +134,7 @@ class TestApiTokenEndpoint:
|
|||
|
||||
# GET /user/api-tokens/<pk>/ tests
|
||||
@pytest.mark.django_db
|
||||
def test_get_specific_api_token(
|
||||
self, session_client, create_user, create_api_token_for_user
|
||||
):
|
||||
def test_get_specific_api_token(self, session_client, create_user, create_api_token_for_user):
|
||||
"""Test retrieving a specific API token"""
|
||||
# Arrange
|
||||
session_client.force_authenticate(user=create_user)
|
||||
|
|
@ -155,9 +147,7 @@ class TestApiTokenEndpoint:
|
|||
assert response.status_code == status.HTTP_200_OK
|
||||
assert str(response.data["id"]) == str(create_api_token_for_user.pk)
|
||||
assert response.data["label"] == create_api_token_for_user.label
|
||||
assert (
|
||||
"token" not in response.data
|
||||
) # Token should not be visible in read serializer
|
||||
assert "token" not in response.data # Token should not be visible in read serializer
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_nonexistent_api_token(self, session_client, create_user):
|
||||
|
|
@ -182,9 +172,7 @@ class TestApiTokenEndpoint:
|
|||
unique_email = f"other-{unique_id}@plane.so"
|
||||
unique_username = f"other_user_{unique_id}"
|
||||
other_user = User.objects.create(email=unique_email, username=unique_username)
|
||||
other_token = APIToken.objects.create(
|
||||
label="Other Token", user=other_user, user_type=0
|
||||
)
|
||||
other_token = APIToken.objects.create(label="Other Token", user=other_user, user_type=0)
|
||||
session_client.force_authenticate(user=create_user)
|
||||
url = reverse("api-tokens", kwargs={"pk": other_token.pk})
|
||||
|
||||
|
|
@ -196,9 +184,7 @@ class TestApiTokenEndpoint:
|
|||
|
||||
# DELETE /user/api-tokens/<pk>/ tests
|
||||
@pytest.mark.django_db
|
||||
def test_delete_api_token_success(
|
||||
self, session_client, create_user, create_api_token_for_user
|
||||
):
|
||||
def test_delete_api_token_success(self, session_client, create_user, create_api_token_for_user):
|
||||
"""Test successful API token deletion"""
|
||||
# Arrange
|
||||
session_client.force_authenticate(user=create_user)
|
||||
|
|
@ -234,9 +220,7 @@ class TestApiTokenEndpoint:
|
|||
unique_email = f"delete-other-{unique_id}@plane.so"
|
||||
unique_username = f"delete_other_user_{unique_id}"
|
||||
other_user = User.objects.create(email=unique_email, username=unique_username)
|
||||
other_token = APIToken.objects.create(
|
||||
label="Other Token", user=other_user, user_type=0
|
||||
)
|
||||
other_token = APIToken.objects.create(label="Other Token", user=other_user, user_type=0)
|
||||
session_client.force_authenticate(user=create_user)
|
||||
url = reverse("api-tokens", kwargs={"pk": other_token.pk})
|
||||
|
||||
|
|
@ -252,9 +236,7 @@ class TestApiTokenEndpoint:
|
|||
def test_delete_service_api_token_forbidden(self, session_client, create_user):
|
||||
"""Test deleting a service API token (should fail)"""
|
||||
# Arrange
|
||||
service_token = APIToken.objects.create(
|
||||
label="Service Token", user=create_user, user_type=0, is_service=True
|
||||
)
|
||||
service_token = APIToken.objects.create(label="Service Token", user=create_user, user_type=0, is_service=True)
|
||||
session_client.force_authenticate(user=create_user)
|
||||
url = reverse("api-tokens", kwargs={"pk": service_token.pk})
|
||||
|
||||
|
|
@ -268,9 +250,7 @@ class TestApiTokenEndpoint:
|
|||
|
||||
# PATCH /user/api-tokens/<pk>/ tests
|
||||
@pytest.mark.django_db
|
||||
def test_patch_api_token_success(
|
||||
self, session_client, create_user, create_api_token_for_user
|
||||
):
|
||||
def test_patch_api_token_success(self, session_client, create_user, create_api_token_for_user):
|
||||
"""Test successful API token update"""
|
||||
# Arrange
|
||||
session_client.force_authenticate(user=create_user)
|
||||
|
|
@ -294,9 +274,7 @@ class TestApiTokenEndpoint:
|
|||
assert create_api_token_for_user.description == update_data["description"]
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_patch_api_token_partial_update(
|
||||
self, session_client, create_user, create_api_token_for_user
|
||||
):
|
||||
def test_patch_api_token_partial_update(self, session_client, create_user, create_api_token_for_user):
|
||||
"""Test partial API token update"""
|
||||
# Arrange
|
||||
session_client.force_authenticate(user=create_user)
|
||||
|
|
@ -336,9 +314,7 @@ class TestApiTokenEndpoint:
|
|||
unique_email = f"patch-other-{unique_id}@plane.so"
|
||||
unique_username = f"patch_other_user_{unique_id}"
|
||||
other_user = User.objects.create(email=unique_email, username=unique_username)
|
||||
other_token = APIToken.objects.create(
|
||||
label="Other Token", user=other_user, user_type=0
|
||||
)
|
||||
other_token = APIToken.objects.create(label="Other Token", user=other_user, user_type=0)
|
||||
session_client.force_authenticate(user=create_user)
|
||||
url = reverse("api-tokens", kwargs={"pk": other_token.pk})
|
||||
update_data = {"label": "Hacked Label"}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,7 @@ from plane.license.models import Instance
|
|||
@pytest.fixture
|
||||
def setup_instance(db):
|
||||
"""Create and configure an instance for authentication tests"""
|
||||
instance_id = (
|
||||
uuid.uuid4() if not Instance.objects.exists() else Instance.objects.first().id
|
||||
)
|
||||
instance_id = uuid.uuid4() if not Instance.objects.exists() else Instance.objects.first().id
|
||||
|
||||
# Create or update instance with all required fields
|
||||
instance, _ = Instance.objects.update_or_create(
|
||||
|
|
@ -38,9 +36,7 @@ def setup_instance(db):
|
|||
@pytest.fixture
|
||||
def django_client():
|
||||
"""Return a Django test client with User-Agent header for handling redirects"""
|
||||
client = Client(
|
||||
HTTP_USER_AGENT="Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1"
|
||||
)
|
||||
client = Client(HTTP_USER_AGENT="Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1")
|
||||
return client
|
||||
|
||||
|
||||
|
|
@ -83,9 +79,7 @@ class TestMagicLinkGenerate:
|
|||
|
||||
@pytest.mark.django_db
|
||||
@patch("plane.bgtasks.magic_link_code_task.magic_link.delay")
|
||||
def test_magic_generate(
|
||||
self, mock_magic_link, api_client, setup_user, setup_instance
|
||||
):
|
||||
def test_magic_generate(self, mock_magic_link, api_client, setup_user, setup_instance):
|
||||
"""Test successful magic link generation"""
|
||||
url = reverse("magic-generate")
|
||||
|
||||
|
|
@ -103,9 +97,7 @@ class TestMagicLinkGenerate:
|
|||
|
||||
@pytest.mark.django_db
|
||||
@patch("plane.bgtasks.magic_link_code_task.magic_link.delay")
|
||||
def test_max_generate_attempt(
|
||||
self, mock_magic_link, api_client, setup_user, setup_instance
|
||||
):
|
||||
def test_max_generate_attempt(self, mock_magic_link, api_client, setup_user, setup_instance):
|
||||
"""Test exceeding maximum magic link generation attempts"""
|
||||
url = reverse("magic-generate")
|
||||
|
||||
|
|
@ -145,9 +137,7 @@ class TestSignInEndpoint:
|
|||
def test_email_validity(self, django_client, setup_user, setup_instance):
|
||||
"""Test sign-in with invalid email format"""
|
||||
url = reverse("sign-in")
|
||||
response = django_client.post(
|
||||
url, {"email": "useremail.com", "password": "user@123"}, follow=True
|
||||
)
|
||||
response = django_client.post(url, {"email": "useremail.com", "password": "user@123"}, follow=True)
|
||||
|
||||
# Check redirect contains error code
|
||||
assert "INVALID_EMAIL_SIGN_IN" in response.redirect_chain[-1][0]
|
||||
|
|
@ -156,9 +146,7 @@ class TestSignInEndpoint:
|
|||
def test_user_exists(self, django_client, setup_user, setup_instance):
|
||||
"""Test sign-in with non-existent user"""
|
||||
url = reverse("sign-in")
|
||||
response = django_client.post(
|
||||
url, {"email": "user@email.so", "password": "user123"}, follow=True
|
||||
)
|
||||
response = django_client.post(url, {"email": "user@email.so", "password": "user123"}, follow=True)
|
||||
|
||||
# Check redirect contains error code
|
||||
assert "USER_DOES_NOT_EXIST" in response.redirect_chain[-1][0]
|
||||
|
|
@ -167,9 +155,7 @@ class TestSignInEndpoint:
|
|||
def test_password_validity(self, django_client, setup_user, setup_instance):
|
||||
"""Test sign-in with incorrect password"""
|
||||
url = reverse("sign-in")
|
||||
response = django_client.post(
|
||||
url, {"email": "user@plane.so", "password": "user123"}, follow=True
|
||||
)
|
||||
response = django_client.post(url, {"email": "user@plane.so", "password": "user123"}, follow=True)
|
||||
|
||||
# Check for the specific authentication error in the URL
|
||||
redirect_urls = [url for url, _ in response.redirect_chain]
|
||||
|
|
@ -184,9 +170,7 @@ class TestSignInEndpoint:
|
|||
url = reverse("sign-in")
|
||||
|
||||
# First make the request without following redirects
|
||||
response = django_client.post(
|
||||
url, {"email": "user@plane.so", "password": "user@123"}, follow=False
|
||||
)
|
||||
response = django_client.post(url, {"email": "user@plane.so", "password": "user@123"}, follow=False)
|
||||
|
||||
# Check that the initial response is a redirect (302) without error code
|
||||
assert response.status_code == 302
|
||||
|
|
@ -243,27 +227,20 @@ class TestMagicSignIn:
|
|||
assert "MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED" in response.redirect_chain[-1][0]
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_expired_invalid_magic_link(
|
||||
self, django_client, setup_user, setup_instance
|
||||
):
|
||||
def test_expired_invalid_magic_link(self, django_client, setup_user, setup_instance):
|
||||
"""Test magic link sign-in with expired/invalid link"""
|
||||
ri = redis_instance()
|
||||
ri.delete("magic_user@plane.so")
|
||||
|
||||
url = reverse("magic-sign-in")
|
||||
response = django_client.post(
|
||||
url, {"email": "user@plane.so", "code": "xxxx-xxxxx-xxxx"}, follow=False
|
||||
)
|
||||
response = django_client.post(url, {"email": "user@plane.so", "code": "xxxx-xxxxx-xxxx"}, follow=False)
|
||||
|
||||
# Check that we get a redirect
|
||||
assert response.status_code == 302
|
||||
|
||||
# The actual error code is EXPIRED_MAGIC_CODE_SIGN_IN (when key doesn't exist)
|
||||
# or INVALID_MAGIC_CODE_SIGN_IN (when key exists but code doesn't match)
|
||||
assert (
|
||||
"EXPIRED_MAGIC_CODE_SIGN_IN" in response.url
|
||||
or "INVALID_MAGIC_CODE_SIGN_IN" in response.url
|
||||
)
|
||||
assert "EXPIRED_MAGIC_CODE_SIGN_IN" in response.url or "INVALID_MAGIC_CODE_SIGN_IN" in response.url
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_user_does_not_exist(self, django_client, setup_instance):
|
||||
|
|
@ -280,9 +257,7 @@ class TestMagicSignIn:
|
|||
|
||||
@pytest.mark.django_db
|
||||
@patch("plane.bgtasks.magic_link_code_task.magic_link.delay")
|
||||
def test_magic_code_sign_in(
|
||||
self, mock_magic_link, django_client, api_client, setup_user, setup_instance
|
||||
):
|
||||
def test_magic_code_sign_in(self, mock_magic_link, django_client, api_client, setup_user, setup_instance):
|
||||
"""Test successful magic link sign-in process"""
|
||||
# First generate a magic link token
|
||||
gen_url = reverse("magic-generate")
|
||||
|
|
@ -298,9 +273,7 @@ class TestMagicSignIn:
|
|||
|
||||
# Use Django client to test the redirect flow without following redirects
|
||||
url = reverse("magic-sign-in")
|
||||
response = django_client.post(
|
||||
url, {"email": "user@plane.so", "code": token}, follow=False
|
||||
)
|
||||
response = django_client.post(url, {"email": "user@plane.so", "code": token}, follow=False)
|
||||
|
||||
# Check that the initial response is a redirect without error code
|
||||
assert response.status_code == 302
|
||||
|
|
@ -311,9 +284,7 @@ class TestMagicSignIn:
|
|||
|
||||
@pytest.mark.django_db
|
||||
@patch("plane.bgtasks.magic_link_code_task.magic_link.delay")
|
||||
def test_magic_sign_in_with_next_path(
|
||||
self, mock_magic_link, django_client, api_client, setup_user, setup_instance
|
||||
):
|
||||
def test_magic_sign_in_with_next_path(self, mock_magic_link, django_client, api_client, setup_user, setup_instance):
|
||||
"""Test magic sign-in with next_path parameter"""
|
||||
# First generate a magic link token
|
||||
gen_url = reverse("magic-generate")
|
||||
|
|
@ -367,9 +338,7 @@ class TestMagicSignUp:
|
|||
User.objects.create(email="existing@plane.so")
|
||||
|
||||
url = reverse("magic-sign-up")
|
||||
response = django_client.post(
|
||||
url, {"email": "existing@plane.so", "code": "xxxx-xxxxx-xxxx"}, follow=True
|
||||
)
|
||||
response = django_client.post(url, {"email": "existing@plane.so", "code": "xxxx-xxxxx-xxxx"}, follow=True)
|
||||
|
||||
# Check redirect contains error code
|
||||
assert "USER_ALREADY_EXIST" in response.redirect_chain[-1][0]
|
||||
|
|
@ -378,25 +347,18 @@ class TestMagicSignUp:
|
|||
def test_expired_invalid_magic_link(self, django_client, setup_instance):
|
||||
"""Test magic link sign-up with expired/invalid link"""
|
||||
url = reverse("magic-sign-up")
|
||||
response = django_client.post(
|
||||
url, {"email": "new@plane.so", "code": "xxxx-xxxxx-xxxx"}, follow=False
|
||||
)
|
||||
response = django_client.post(url, {"email": "new@plane.so", "code": "xxxx-xxxxx-xxxx"}, follow=False)
|
||||
|
||||
# Check that we get a redirect
|
||||
assert response.status_code == 302
|
||||
|
||||
# The actual error code is EXPIRED_MAGIC_CODE_SIGN_UP (when key doesn't exist)
|
||||
# or INVALID_MAGIC_CODE_SIGN_UP (when key exists but code doesn't match)
|
||||
assert (
|
||||
"EXPIRED_MAGIC_CODE_SIGN_UP" in response.url
|
||||
or "INVALID_MAGIC_CODE_SIGN_UP" in response.url
|
||||
)
|
||||
assert "EXPIRED_MAGIC_CODE_SIGN_UP" in response.url or "INVALID_MAGIC_CODE_SIGN_UP" in response.url
|
||||
|
||||
@pytest.mark.django_db
|
||||
@patch("plane.bgtasks.magic_link_code_task.magic_link.delay")
|
||||
def test_magic_code_sign_up(
|
||||
self, mock_magic_link, django_client, api_client, setup_instance
|
||||
):
|
||||
def test_magic_code_sign_up(self, mock_magic_link, django_client, api_client, setup_instance):
|
||||
"""Test successful magic link sign-up process"""
|
||||
email = "newuser@plane.so"
|
||||
|
||||
|
|
@ -414,9 +376,7 @@ class TestMagicSignUp:
|
|||
|
||||
# Use Django client to test the redirect flow without following redirects
|
||||
url = reverse("magic-sign-up")
|
||||
response = django_client.post(
|
||||
url, {"email": email, "code": token}, follow=False
|
||||
)
|
||||
response = django_client.post(url, {"email": email, "code": token}, follow=False)
|
||||
|
||||
# Check that the initial response is a redirect without error code
|
||||
assert response.status_code == 302
|
||||
|
|
@ -430,9 +390,7 @@ class TestMagicSignUp:
|
|||
|
||||
@pytest.mark.django_db
|
||||
@patch("plane.bgtasks.magic_link_code_task.magic_link.delay")
|
||||
def test_magic_sign_up_with_next_path(
|
||||
self, mock_magic_link, django_client, api_client, setup_instance
|
||||
):
|
||||
def test_magic_sign_up_with_next_path(self, mock_magic_link, django_client, api_client, setup_instance):
|
||||
"""Test magic sign-up with next_path parameter"""
|
||||
email = "newuser2@plane.so"
|
||||
|
||||
|
|
@ -451,9 +409,7 @@ class TestMagicSignUp:
|
|||
# Use Django client to test the redirect flow without following redirects
|
||||
url = reverse("magic-sign-up")
|
||||
next_path = "onboarding"
|
||||
response = django_client.post(
|
||||
url, {"email": email, "code": token, "next_path": next_path}, follow=False
|
||||
)
|
||||
response = django_client.post(url, {"email": email, "code": token, "next_path": next_path}, follow=False)
|
||||
|
||||
# Check that the initial response is a redirect without error code
|
||||
assert response.status_code == 302
|
||||
|
|
|
|||
|
|
@ -14,9 +14,7 @@ from plane.db.models import (
|
|||
|
||||
|
||||
class TestProjectBase:
|
||||
def get_project_url(
|
||||
self, workspace_slug: str, pk: uuid.UUID = None, details: bool = False
|
||||
) -> str:
|
||||
def get_project_url(self, workspace_slug: str, pk: uuid.UUID = None, details: bool = False) -> str:
|
||||
"""
|
||||
Constructs the project endpoint URL for the given workspace as reverse() is
|
||||
unreliable due to duplicate 'name' values in URL patterns ('api' and 'app').
|
||||
|
|
@ -80,9 +78,7 @@ class TestProjectAPIPost(TestProjectBase):
|
|||
|
||||
# Check if the member is created with the correct role
|
||||
assert ProjectMember.objects.count() == 1
|
||||
project_member = ProjectMember.objects.filter(
|
||||
project=project, member=user
|
||||
).first()
|
||||
project_member = ProjectMember.objects.filter(project=project, member=user).first()
|
||||
assert project_member.role == 20 # Administrator
|
||||
assert project_member.is_active is True
|
||||
|
||||
|
|
@ -97,19 +93,13 @@ class TestProjectAPIPost(TestProjectBase):
|
|||
assert set(state_names) == set(expected_states)
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_create_project_with_project_lead(
|
||||
self, session_client, workspace, create_user
|
||||
):
|
||||
def test_create_project_with_project_lead(self, session_client, workspace, create_user):
|
||||
"""Test creating project with a different project lead"""
|
||||
# Create another user to be project lead
|
||||
project_lead = User.objects.create_user(
|
||||
email="lead@example.com", username="projectlead"
|
||||
)
|
||||
project_lead = User.objects.create_user(email="lead@example.com", username="projectlead")
|
||||
|
||||
# Add project lead to workspace
|
||||
WorkspaceMember.objects.create(
|
||||
workspace=workspace, member=project_lead, role=15
|
||||
)
|
||||
WorkspaceMember.objects.create(workspace=workspace, member=project_lead, role=15)
|
||||
|
||||
url = self.get_project_url(workspace.slug)
|
||||
project_data = {
|
||||
|
|
@ -132,9 +122,7 @@ class TestProjectAPIPost(TestProjectBase):
|
|||
@pytest.mark.django_db
|
||||
def test_create_project_guest_forbidden(self, session_client, workspace):
|
||||
"""Test that guests cannot create projects"""
|
||||
guest_user = User.objects.create_user(
|
||||
email="guest@example.com", username="guest"
|
||||
)
|
||||
guest_user = User.objects.create_user(email="guest@example.com", username="guest")
|
||||
WorkspaceMember.objects.create(workspace=workspace, member=guest_user, role=5)
|
||||
|
||||
session_client.force_authenticate(user=guest_user)
|
||||
|
|
@ -164,14 +152,10 @@ class TestProjectAPIPost(TestProjectBase):
|
|||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_create_project_duplicate_name(
|
||||
self, session_client, workspace, create_user
|
||||
):
|
||||
def test_create_project_duplicate_name(self, session_client, workspace, create_user):
|
||||
"""Test creating project with duplicate name"""
|
||||
# Create first project
|
||||
Project.objects.create(
|
||||
name="Duplicate Name", identifier="DN1", workspace=workspace
|
||||
)
|
||||
Project.objects.create(name="Duplicate Name", identifier="DN1", workspace=workspace)
|
||||
|
||||
url = self.get_project_url(workspace.slug)
|
||||
project_data = {
|
||||
|
|
@ -184,13 +168,9 @@ class TestProjectAPIPost(TestProjectBase):
|
|||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_create_project_duplicate_identifier(
|
||||
self, session_client, workspace, create_user
|
||||
):
|
||||
def test_create_project_duplicate_identifier(self, session_client, workspace, create_user):
|
||||
"""Test creating project with duplicate identifier"""
|
||||
Project.objects.create(
|
||||
name="First Project", identifier="DUP", workspace=workspace
|
||||
)
|
||||
Project.objects.create(name="First Project", identifier="DUP", workspace=workspace)
|
||||
|
||||
url = self.get_project_url(workspace.slug)
|
||||
project_data = {
|
||||
|
|
@ -203,9 +183,7 @@ class TestProjectAPIPost(TestProjectBase):
|
|||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_create_project_missing_required_fields(
|
||||
self, session_client, workspace, create_user
|
||||
):
|
||||
def test_create_project_missing_required_fields(self, session_client, workspace, create_user):
|
||||
"""Test validation with missing required fields"""
|
||||
url = self.get_project_url(workspace.slug)
|
||||
|
||||
|
|
@ -214,15 +192,11 @@ class TestProjectAPIPost(TestProjectBase):
|
|||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
# Test missing identifier
|
||||
response = session_client.post(
|
||||
url, {"name": "Missing Identifier"}, format="json"
|
||||
)
|
||||
response = session_client.post(url, {"name": "Missing Identifier"}, format="json")
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_create_project_with_all_optional_fields(
|
||||
self, session_client, workspace, create_user
|
||||
):
|
||||
def test_create_project_with_all_optional_fields(self, session_client, workspace, create_user):
|
||||
"""Test creating project with all optional fields"""
|
||||
url = self.get_project_url(workspace.slug)
|
||||
project_data = {
|
||||
|
|
@ -256,19 +230,13 @@ class TestProjectAPIGet(TestProjectBase):
|
|||
"""Test project GET operations"""
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_list_projects_authenticated_admin(
|
||||
self, session_client, workspace, create_user
|
||||
):
|
||||
def test_list_projects_authenticated_admin(self, session_client, workspace, create_user):
|
||||
"""Test listing projects as workspace admin"""
|
||||
# Create a project
|
||||
project = Project.objects.create(
|
||||
name="Test Project", identifier="TP", workspace=workspace
|
||||
)
|
||||
project = Project.objects.create(name="Test Project", identifier="TP", workspace=workspace)
|
||||
|
||||
# Add user as project member
|
||||
ProjectMember.objects.create(
|
||||
project=project, member=create_user, role=20, is_active=True
|
||||
)
|
||||
ProjectMember.objects.create(project=project, member=create_user, role=20, is_active=True)
|
||||
|
||||
url = self.get_project_url(workspace.slug)
|
||||
response = session_client.get(url)
|
||||
|
|
@ -283,24 +251,16 @@ class TestProjectAPIGet(TestProjectBase):
|
|||
def test_list_projects_authenticated_guest(self, session_client, workspace):
|
||||
"""Test listing projects as workspace guest"""
|
||||
# Create a guest user
|
||||
guest_user = User.objects.create_user(
|
||||
email="guest@example.com", username="guest"
|
||||
)
|
||||
WorkspaceMember.objects.create(
|
||||
workspace=workspace, member=guest_user, role=5, is_active=True
|
||||
)
|
||||
guest_user = User.objects.create_user(email="guest@example.com", username="guest")
|
||||
WorkspaceMember.objects.create(workspace=workspace, member=guest_user, role=5, is_active=True)
|
||||
|
||||
# Create projects
|
||||
project1 = Project.objects.create(
|
||||
name="Project 1", identifier="P1", workspace=workspace
|
||||
)
|
||||
project1 = Project.objects.create(name="Project 1", identifier="P1", workspace=workspace)
|
||||
|
||||
Project.objects.create(name="Project 2", identifier="P2", workspace=workspace)
|
||||
|
||||
# Add guest to only one project
|
||||
ProjectMember.objects.create(
|
||||
project=project1, member=guest_user, role=10, is_active=True
|
||||
)
|
||||
ProjectMember.objects.create(project=project1, member=guest_user, role=10, is_active=True)
|
||||
|
||||
session_client.force_authenticate(user=guest_user)
|
||||
|
||||
|
|
@ -333,9 +293,7 @@ class TestProjectAPIGet(TestProjectBase):
|
|||
)
|
||||
|
||||
# Add user as project member
|
||||
ProjectMember.objects.create(
|
||||
project=project, member=create_user, role=20, is_active=True
|
||||
)
|
||||
ProjectMember.objects.create(project=project, member=create_user, role=20, is_active=True)
|
||||
|
||||
url = self.get_project_url(workspace.slug, details=True)
|
||||
response = session_client.get(url)
|
||||
|
|
@ -358,9 +316,7 @@ class TestProjectAPIGet(TestProjectBase):
|
|||
)
|
||||
|
||||
# Add user as project member
|
||||
ProjectMember.objects.create(
|
||||
project=project, member=create_user, role=20, is_active=True
|
||||
)
|
||||
ProjectMember.objects.create(project=project, member=create_user, role=20, is_active=True)
|
||||
|
||||
url = self.get_project_url(workspace.slug, pk=project.id)
|
||||
response = session_client.get(url)
|
||||
|
|
@ -392,9 +348,7 @@ class TestProjectAPIGet(TestProjectBase):
|
|||
)
|
||||
|
||||
# Add user as project member
|
||||
ProjectMember.objects.create(
|
||||
project=project, member=create_user, role=20, is_active=True
|
||||
)
|
||||
ProjectMember.objects.create(project=project, member=create_user, role=20, is_active=True)
|
||||
|
||||
url = self.get_project_url(workspace.slug, pk=project.id)
|
||||
response = session_client.get(url)
|
||||
|
|
@ -407,9 +361,7 @@ class TestProjectAPIPatchDelete(TestProjectBase):
|
|||
"""Test project PATCH, and DELETE operations"""
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_partial_update_project_success(
|
||||
self, session_client, workspace, create_user
|
||||
):
|
||||
def test_partial_update_project_success(self, session_client, workspace, create_user):
|
||||
"""Test successful partial update of project"""
|
||||
# Create a project
|
||||
project = Project.objects.create(
|
||||
|
|
@ -420,9 +372,7 @@ class TestProjectAPIPatchDelete(TestProjectBase):
|
|||
)
|
||||
|
||||
# Add user as project administrator
|
||||
ProjectMember.objects.create(
|
||||
project=project, member=create_user, role=20, is_active=True
|
||||
)
|
||||
ProjectMember.objects.create(project=project, member=create_user, role=20, is_active=True)
|
||||
|
||||
url = self.get_project_url(workspace.slug, pk=project.id)
|
||||
update_data = {
|
||||
|
|
@ -444,25 +394,15 @@ class TestProjectAPIPatchDelete(TestProjectBase):
|
|||
assert project.module_view is False
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_partial_update_project_forbidden_non_admin(
|
||||
self, session_client, workspace
|
||||
):
|
||||
def test_partial_update_project_forbidden_non_admin(self, session_client, workspace):
|
||||
"""Test that non-admin project members cannot update project"""
|
||||
# Create a project
|
||||
project = Project.objects.create(
|
||||
name="Protected Project", identifier="PP", workspace=workspace
|
||||
)
|
||||
project = Project.objects.create(name="Protected Project", identifier="PP", workspace=workspace)
|
||||
|
||||
# Create a member user (not admin)
|
||||
member_user = User.objects.create_user(
|
||||
email="member@example.com", username="member"
|
||||
)
|
||||
WorkspaceMember.objects.create(
|
||||
workspace=workspace, member=member_user, role=15, is_active=True
|
||||
)
|
||||
ProjectMember.objects.create(
|
||||
project=project, member=member_user, role=15, is_active=True
|
||||
)
|
||||
member_user = User.objects.create_user(email="member@example.com", username="member")
|
||||
WorkspaceMember.objects.create(workspace=workspace, member=member_user, role=15, is_active=True)
|
||||
ProjectMember.objects.create(project=project, member=member_user, role=15, is_active=True)
|
||||
|
||||
session_client.force_authenticate(user=member_user)
|
||||
|
||||
|
|
@ -474,19 +414,13 @@ class TestProjectAPIPatchDelete(TestProjectBase):
|
|||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_partial_update_duplicate_name_conflict(
|
||||
self, session_client, workspace, create_user
|
||||
):
|
||||
def test_partial_update_duplicate_name_conflict(self, session_client, workspace, create_user):
|
||||
"""Test updating project with duplicate name returns conflict"""
|
||||
# Create two projects
|
||||
Project.objects.create(name="Project One", identifier="P1", workspace=workspace)
|
||||
project2 = Project.objects.create(
|
||||
name="Project Two", identifier="P2", workspace=workspace
|
||||
)
|
||||
project2 = Project.objects.create(name="Project Two", identifier="P2", workspace=workspace)
|
||||
|
||||
ProjectMember.objects.create(
|
||||
project=project2, member=create_user, role=20, is_active=True
|
||||
)
|
||||
ProjectMember.objects.create(project=project2, member=create_user, role=20, is_active=True)
|
||||
|
||||
url = self.get_project_url(workspace.slug, pk=project2.id)
|
||||
update_data = {"name": "Project One"} # Duplicate name
|
||||
|
|
@ -496,19 +430,13 @@ class TestProjectAPIPatchDelete(TestProjectBase):
|
|||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_partial_update_duplicate_identifier_conflict(
|
||||
self, session_client, workspace, create_user
|
||||
):
|
||||
def test_partial_update_duplicate_identifier_conflict(self, session_client, workspace, create_user):
|
||||
"""Test updating project with duplicate identifier returns conflict"""
|
||||
# Create two projects
|
||||
Project.objects.create(name="Project One", identifier="P1", workspace=workspace)
|
||||
project2 = Project.objects.create(
|
||||
name="Project Two", identifier="P2", workspace=workspace
|
||||
)
|
||||
project2 = Project.objects.create(name="Project Two", identifier="P2", workspace=workspace)
|
||||
|
||||
ProjectMember.objects.create(
|
||||
project=project2, member=create_user, role=20, is_active=True
|
||||
)
|
||||
ProjectMember.objects.create(project=project2, member=create_user, role=20, is_active=True)
|
||||
|
||||
url = self.get_project_url(workspace.slug, pk=project2.id)
|
||||
update_data = {"identifier": "P1"} # Duplicate identifier
|
||||
|
|
@ -520,13 +448,9 @@ class TestProjectAPIPatchDelete(TestProjectBase):
|
|||
@pytest.mark.django_db
|
||||
def test_partial_update_invalid_data(self, session_client, workspace, create_user):
|
||||
"""Test partial update with invalid data"""
|
||||
project = Project.objects.create(
|
||||
name="Valid Project", identifier="VP", workspace=workspace
|
||||
)
|
||||
project = Project.objects.create(name="Valid Project", identifier="VP", workspace=workspace)
|
||||
|
||||
ProjectMember.objects.create(
|
||||
project=project, member=create_user, role=20, is_active=True
|
||||
)
|
||||
ProjectMember.objects.create(project=project, member=create_user, role=20, is_active=True)
|
||||
|
||||
url = self.get_project_url(workspace.slug, pk=project.id)
|
||||
update_data = {"name": ""}
|
||||
|
|
@ -536,17 +460,11 @@ class TestProjectAPIPatchDelete(TestProjectBase):
|
|||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_delete_project_success_project_admin(
|
||||
self, session_client, workspace, create_user
|
||||
):
|
||||
def test_delete_project_success_project_admin(self, session_client, workspace, create_user):
|
||||
"""Test successful project deletion by project admin"""
|
||||
project = Project.objects.create(
|
||||
name="Delete Me", identifier="DM", workspace=workspace
|
||||
)
|
||||
project = Project.objects.create(name="Delete Me", identifier="DM", workspace=workspace)
|
||||
|
||||
ProjectMember.objects.create(
|
||||
project=project, member=create_user, role=20, is_active=True
|
||||
)
|
||||
ProjectMember.objects.create(project=project, member=create_user, role=20, is_active=True)
|
||||
|
||||
url = self.get_project_url(workspace.slug, pk=project.id)
|
||||
response = session_client.delete(url)
|
||||
|
|
@ -558,16 +476,10 @@ class TestProjectAPIPatchDelete(TestProjectBase):
|
|||
def test_delete_project_success_workspace_admin(self, session_client, workspace):
|
||||
"""Test successful project deletion by workspace admin"""
|
||||
# Create workspace admin user
|
||||
workspace_admin = User.objects.create_user(
|
||||
email="admin@example.com", username="admin"
|
||||
)
|
||||
WorkspaceMember.objects.create(
|
||||
workspace=workspace, member=workspace_admin, role=20, is_active=True
|
||||
)
|
||||
workspace_admin = User.objects.create_user(email="admin@example.com", username="admin")
|
||||
WorkspaceMember.objects.create(workspace=workspace, member=workspace_admin, role=20, is_active=True)
|
||||
|
||||
project = Project.objects.create(
|
||||
name="Delete Me", identifier="DM", workspace=workspace
|
||||
)
|
||||
project = Project.objects.create(name="Delete Me", identifier="DM", workspace=workspace)
|
||||
|
||||
session_client.force_authenticate(user=workspace_admin)
|
||||
|
||||
|
|
@ -581,20 +493,12 @@ class TestProjectAPIPatchDelete(TestProjectBase):
|
|||
def test_delete_project_forbidden_non_admin(self, session_client, workspace):
|
||||
"""Test that non-admin users cannot delete projects"""
|
||||
# Create a member user (not admin)
|
||||
member_user = User.objects.create_user(
|
||||
email="member@example.com", username="member"
|
||||
)
|
||||
WorkspaceMember.objects.create(
|
||||
workspace=workspace, member=member_user, role=15, is_active=True
|
||||
)
|
||||
member_user = User.objects.create_user(email="member@example.com", username="member")
|
||||
WorkspaceMember.objects.create(workspace=workspace, member=member_user, role=15, is_active=True)
|
||||
|
||||
project = Project.objects.create(
|
||||
name="Protected Project", identifier="PP", workspace=workspace
|
||||
)
|
||||
project = Project.objects.create(name="Protected Project", identifier="PP", workspace=workspace)
|
||||
|
||||
ProjectMember.objects.create(
|
||||
project=project, member=member_user, role=15, is_active=True
|
||||
)
|
||||
ProjectMember.objects.create(project=project, member=member_user, role=15, is_active=True)
|
||||
|
||||
session_client.force_authenticate(user=member_user)
|
||||
|
||||
|
|
@ -607,9 +511,7 @@ class TestProjectAPIPatchDelete(TestProjectBase):
|
|||
@pytest.mark.django_db
|
||||
def test_delete_project_unauthenticated(self, client, workspace):
|
||||
"""Test unauthenticated project deletion"""
|
||||
project = Project.objects.create(
|
||||
name="Protected Project", identifier="PP", workspace=workspace
|
||||
)
|
||||
project = Project.objects.create(name="Protected Project", identifier="PP", workspace=workspace)
|
||||
|
||||
url = self.get_project_url(workspace.slug, pk=project.id)
|
||||
response = client.delete(url)
|
||||
|
|
|
|||
|
|
@ -21,9 +21,7 @@ class TestWorkspaceAPI:
|
|||
|
||||
@pytest.mark.django_db
|
||||
@patch("plane.bgtasks.workspace_seed_task.workspace_seed.delay")
|
||||
def test_create_workspace_valid_data(
|
||||
self, mock_workspace_seed, session_client, create_user
|
||||
):
|
||||
def test_create_workspace_valid_data(self, mock_workspace_seed, session_client, create_user):
|
||||
"""Test creating a workspace with valid data"""
|
||||
url = reverse("workspace")
|
||||
user = create_user # Use the create_user fixture directly as it returns a user object
|
||||
|
|
@ -49,9 +47,7 @@ class TestWorkspaceAPI:
|
|||
|
||||
# Check other values
|
||||
workspace = Workspace.objects.get(slug=workspace_data["slug"])
|
||||
workspace_member = WorkspaceMember.objects.filter(
|
||||
workspace=workspace, member=user
|
||||
).first()
|
||||
workspace_member = WorkspaceMember.objects.filter(workspace=workspace, member=user).first()
|
||||
assert workspace.owner == user
|
||||
assert workspace_member.role == 20
|
||||
|
||||
|
|
@ -68,9 +64,7 @@ class TestWorkspaceAPI:
|
|||
session_client.post(url, {"name": "Plane", "slug": "pla-ne"}, format="json")
|
||||
|
||||
# Try to create a workspace with the same slug
|
||||
response = session_client.post(
|
||||
url, {"name": "Plane", "slug": "pla-ne"}, format="json"
|
||||
)
|
||||
response = session_client.post(url, {"name": "Plane", "slug": "pla-ne"}, format="json")
|
||||
|
||||
# The API returns 400 BAD REQUEST for duplicate slugs, not 409 CONFLICT
|
||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue