[OND211-2329]: Added tests for update team API.
This commit is contained in:
parent
4c8ea1d21a
commit
b54a6ace78
2 changed files with 377 additions and 0 deletions
|
|
@ -505,6 +505,34 @@ def accept_team_invitation(
|
||||||
return res.json()
|
return res.json()
|
||||||
|
|
||||||
|
|
||||||
|
def update_team(
|
||||||
|
auth: Union[AuthBase, str, None],
|
||||||
|
tenant_id: str,
|
||||||
|
payload: Optional[Dict[str, Any]] = None,
|
||||||
|
*,
|
||||||
|
headers: Dict[str, str] = HEADERS,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""Update a team (tenant).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
auth: Authentication object (AuthBase subclass), token string, or None.
|
||||||
|
tenant_id: The team ID to update.
|
||||||
|
payload: Optional JSON payload containing update data (e.g., name, llm_id, embd_id, credit).
|
||||||
|
headers: Optional HTTP headers. Defaults to HEADERS.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
JSON response as a dictionary containing the updated team data.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
requests.RequestException: If the HTTP request fails.
|
||||||
|
"""
|
||||||
|
url: str = f"{HOST_ADDRESS}{TEAM_API_URL}/{tenant_id}"
|
||||||
|
res: requests.Response = requests.put(
|
||||||
|
url=url, headers=headers, auth=auth, json=payload
|
||||||
|
)
|
||||||
|
return res.json()
|
||||||
|
|
||||||
|
|
||||||
# DEPARTMENT MANAGEMENT
|
# DEPARTMENT MANAGEMENT
|
||||||
DEPARTMENT_API_URL: str = f"/{VERSION}/department"
|
DEPARTMENT_API_URL: str = f"/{VERSION}/department"
|
||||||
GROUP_API_URL: str = f"/{VERSION}/group"
|
GROUP_API_URL: str = f"/{VERSION}/group"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,349 @@
|
||||||
|
#
|
||||||
|
# Copyright 2025 The InfiniFlow Authors. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import time
|
||||||
|
import uuid
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from common import (
|
||||||
|
add_users_to_team,
|
||||||
|
create_team,
|
||||||
|
create_user,
|
||||||
|
encrypt_password,
|
||||||
|
login_as_user,
|
||||||
|
update_team,
|
||||||
|
)
|
||||||
|
from configs import INVALID_API_TOKEN
|
||||||
|
from libs.auth import RAGFlowWebApiAuth
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Test Classes
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.p1
|
||||||
|
class TestAuthorization:
|
||||||
|
"""Tests for authentication behavior when updating teams."""
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("invalid_auth", "expected_code", "expected_message"),
|
||||||
|
[
|
||||||
|
(None, 401, "Unauthorized"),
|
||||||
|
(RAGFlowWebApiAuth(INVALID_API_TOKEN), 401, "Unauthorized"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_invalid_auth(
|
||||||
|
self,
|
||||||
|
invalid_auth: RAGFlowWebApiAuth | None,
|
||||||
|
expected_code: int,
|
||||||
|
expected_message: str,
|
||||||
|
web_api_auth: RAGFlowWebApiAuth,
|
||||||
|
) -> None:
|
||||||
|
"""Test updating team with invalid or missing authentication."""
|
||||||
|
# Create a team first
|
||||||
|
team_name: str = f"Test Team {uuid.uuid4().hex[:8]}"
|
||||||
|
team_payload: dict[str, str] = {"name": team_name}
|
||||||
|
team_res: dict[str, Any] = create_team(web_api_auth, team_payload)
|
||||||
|
if team_res["code"] != 0:
|
||||||
|
pytest.skip("Team creation failed, skipping auth test")
|
||||||
|
|
||||||
|
tenant_id: str = team_res["data"]["id"]
|
||||||
|
|
||||||
|
# Try to update team with invalid auth
|
||||||
|
update_payload: dict[str, str] = {"name": "Updated Name"}
|
||||||
|
res: dict[str, Any] = update_team(invalid_auth, tenant_id, update_payload)
|
||||||
|
assert res["code"] == expected_code, res
|
||||||
|
if expected_message:
|
||||||
|
assert expected_message in res["message"]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.p1
|
||||||
|
class TestUpdateTeam:
|
||||||
|
"""Comprehensive tests for team update API."""
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def test_team(self, web_api_auth: RAGFlowWebApiAuth) -> dict[str, Any]:
|
||||||
|
"""Create a test team for use in tests."""
|
||||||
|
team_payload: dict[str, str] = {"name": f"Test Team {uuid.uuid4().hex[:8]}"}
|
||||||
|
res: dict[str, Any] = create_team(web_api_auth, team_payload)
|
||||||
|
assert res["code"] == 0
|
||||||
|
return res["data"]
|
||||||
|
|
||||||
|
@pytest.mark.p1
|
||||||
|
def test_update_team_name(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test updating a team's name."""
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
|
||||||
|
# Update the team name
|
||||||
|
new_name: str = f"Updated Team {uuid.uuid4().hex[:8]}"
|
||||||
|
update_payload: dict[str, str] = {"name": new_name}
|
||||||
|
update_res: dict[str, Any] = update_team(web_api_auth, tenant_id, update_payload)
|
||||||
|
assert update_res["code"] == 0, update_res
|
||||||
|
assert "data" in update_res
|
||||||
|
assert update_res["data"]["name"] == new_name
|
||||||
|
assert update_res["data"]["id"] == tenant_id
|
||||||
|
|
||||||
|
@pytest.mark.p1
|
||||||
|
def test_update_team_name_empty(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test updating a team with empty name (should fail)."""
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
|
||||||
|
# Try to update with empty name
|
||||||
|
update_payload: dict[str, str] = {"name": ""}
|
||||||
|
res: dict[str, Any] = update_team(web_api_auth, tenant_id, update_payload)
|
||||||
|
assert res["code"] != 0, "Should fail for empty name"
|
||||||
|
assert "empty" in res["message"].lower() or "cannot be empty" in res["message"].lower()
|
||||||
|
|
||||||
|
@pytest.mark.p1
|
||||||
|
def test_update_team_name_too_long(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test updating a team with name exceeding 100 characters."""
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
|
||||||
|
# Try to update with name too long
|
||||||
|
long_name: str = "A" * 101
|
||||||
|
update_payload: dict[str, str] = {"name": long_name}
|
||||||
|
res: dict[str, Any] = update_team(web_api_auth, tenant_id, update_payload)
|
||||||
|
assert res["code"] != 0, "Should fail for name too long"
|
||||||
|
assert "100" in res["message"] or "length" in res["message"].lower()
|
||||||
|
|
||||||
|
@pytest.mark.p1
|
||||||
|
def test_update_team_credit(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test updating a team's credit."""
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
|
||||||
|
# Update the team credit
|
||||||
|
new_credit: int = 1000
|
||||||
|
update_payload: dict[str, int] = {"credit": new_credit}
|
||||||
|
update_res: dict[str, Any] = update_team(web_api_auth, tenant_id, update_payload)
|
||||||
|
assert update_res["code"] == 0, update_res
|
||||||
|
assert "data" in update_res
|
||||||
|
assert update_res["data"]["credit"] == new_credit
|
||||||
|
|
||||||
|
@pytest.mark.p1
|
||||||
|
def test_update_team_credit_negative(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test updating a team with negative credit (should fail)."""
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
|
||||||
|
# Try to update with negative credit
|
||||||
|
update_payload: dict[str, int] = {"credit": -1}
|
||||||
|
res: dict[str, Any] = update_team(web_api_auth, tenant_id, update_payload)
|
||||||
|
assert res["code"] != 0, "Should fail for negative credit"
|
||||||
|
assert "non-negative" in res["message"].lower() or "negative" in res["message"].lower()
|
||||||
|
|
||||||
|
@pytest.mark.p1
|
||||||
|
def test_update_team_invalid_tenant_id(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth
|
||||||
|
) -> None:
|
||||||
|
"""Test updating a non-existent team."""
|
||||||
|
invalid_id: str = f"invalid_{uuid.uuid4().hex[:8]}"
|
||||||
|
update_payload: dict[str, str] = {"name": "Updated Name"}
|
||||||
|
res: dict[str, Any] = update_team(web_api_auth, invalid_id, update_payload)
|
||||||
|
assert res["code"] != 0, "Should fail for invalid team ID"
|
||||||
|
# API may check permissions first, so either "not found" or permission error is valid
|
||||||
|
assert "not found" in res["message"].lower() or "owner" in res["message"].lower() or "admin" in res["message"].lower()
|
||||||
|
|
||||||
|
@pytest.mark.p1
|
||||||
|
def test_update_team_not_owner_or_admin(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test updating a team when user is not owner or admin."""
|
||||||
|
# Create a new user with encrypted password
|
||||||
|
email: str = f"testuser_{uuid.uuid4().hex[:8]}@example.com"
|
||||||
|
password = "TestPassword123!"
|
||||||
|
encrypted_password = encrypt_password(password)
|
||||||
|
user_payload: dict[str, str] = {
|
||||||
|
"email": email,
|
||||||
|
"password": encrypted_password,
|
||||||
|
"nickname": "Test User",
|
||||||
|
}
|
||||||
|
user_res: dict[str, Any] = create_user(web_api_auth, user_payload)
|
||||||
|
if user_res["code"] != 0:
|
||||||
|
pytest.skip("User creation failed")
|
||||||
|
|
||||||
|
# Add user to team as normal member
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
add_payload: dict[str, list[str]] = {"users": [email]}
|
||||||
|
add_users_to_team(web_api_auth, tenant_id, add_payload)
|
||||||
|
|
||||||
|
# Small delay to ensure user is fully created
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
# Login as the new user (normal member, not admin/owner)
|
||||||
|
new_user_auth: RAGFlowWebApiAuth = login_as_user(email, password)
|
||||||
|
|
||||||
|
# Try to update team (user is member but not admin/owner)
|
||||||
|
update_payload: dict[str, str] = {"name": "Updated Name"}
|
||||||
|
res: dict[str, Any] = update_team(new_user_auth, tenant_id, update_payload)
|
||||||
|
assert res["code"] == 108 # PERMISSION_ERROR
|
||||||
|
assert "owner" in res["message"].lower() or "admin" in res["message"].lower()
|
||||||
|
|
||||||
|
@pytest.mark.p1
|
||||||
|
def test_update_team_response_structure(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test that team update returns the expected response structure."""
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
|
||||||
|
update_payload: dict[str, str] = {"name": f"Updated Team {uuid.uuid4().hex[:8]}"}
|
||||||
|
res: dict[str, Any] = update_team(web_api_auth, tenant_id, update_payload)
|
||||||
|
assert res["code"] == 0
|
||||||
|
assert "data" in res
|
||||||
|
assert isinstance(res["data"], dict)
|
||||||
|
assert "id" in res["data"]
|
||||||
|
assert "name" in res["data"]
|
||||||
|
assert "message" in res
|
||||||
|
assert "updated successfully" in res["message"].lower()
|
||||||
|
|
||||||
|
@pytest.mark.p1
|
||||||
|
def test_update_team_no_fields_provided(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test updating a team with no fields provided."""
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
|
||||||
|
# Try to update with empty payload
|
||||||
|
update_payload: dict[str, Any] = {}
|
||||||
|
res: dict[str, Any] = update_team(web_api_auth, tenant_id, update_payload)
|
||||||
|
assert res["code"] != 0, "Should fail when no fields provided"
|
||||||
|
assert "no fields" in res["message"].lower() or "required" in res["message"].lower()
|
||||||
|
|
||||||
|
@pytest.mark.p1
|
||||||
|
def test_update_team_missing_request_body(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test updating a team without request body."""
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
|
||||||
|
# Try to update without payload (None)
|
||||||
|
res: dict[str, Any] = update_team(web_api_auth, tenant_id, None)
|
||||||
|
assert res["code"] != 0, "Should fail when request body is missing"
|
||||||
|
assert "required" in res["message"].lower() or "body" in res["message"].lower()
|
||||||
|
|
||||||
|
@pytest.mark.p2
|
||||||
|
def test_update_team_multiple_fields(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test updating multiple team fields at once."""
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
|
||||||
|
# Update multiple fields
|
||||||
|
new_name: str = f"Multi Update Team {uuid.uuid4().hex[:8]}"
|
||||||
|
new_credit: int = 2000
|
||||||
|
update_payload: dict[str, Any] = {
|
||||||
|
"name": new_name,
|
||||||
|
"credit": new_credit,
|
||||||
|
}
|
||||||
|
update_res: dict[str, Any] = update_team(web_api_auth, tenant_id, update_payload)
|
||||||
|
assert update_res["code"] == 0, update_res
|
||||||
|
assert update_res["data"]["name"] == new_name
|
||||||
|
assert update_res["data"]["credit"] == new_credit
|
||||||
|
|
||||||
|
@pytest.mark.p2
|
||||||
|
def test_update_team_whitespace_name(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test updating a team with whitespace-only name."""
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
|
||||||
|
# Try to update with whitespace-only name
|
||||||
|
update_payload: dict[str, str] = {"name": " "}
|
||||||
|
res: dict[str, Any] = update_team(web_api_auth, tenant_id, update_payload)
|
||||||
|
assert res["code"] != 0, "Should fail for whitespace-only name"
|
||||||
|
assert "empty" in res["message"].lower() or "cannot be empty" in res["message"].lower()
|
||||||
|
|
||||||
|
@pytest.mark.p2
|
||||||
|
def test_update_team_special_characters_name(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test updating a team with special characters in name."""
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
|
||||||
|
# Update with special characters
|
||||||
|
new_name: str = f"Team-{uuid.uuid4().hex[:8]}_Test!"
|
||||||
|
update_payload: dict[str, str] = {"name": new_name}
|
||||||
|
res: dict[str, Any] = update_team(web_api_auth, tenant_id, update_payload)
|
||||||
|
# Should succeed if special chars are allowed
|
||||||
|
assert res["code"] in (0, 101)
|
||||||
|
|
||||||
|
@pytest.mark.p2
|
||||||
|
def test_update_team_unicode_name(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test updating a team with unicode characters in name."""
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
|
||||||
|
# Update with unicode name
|
||||||
|
new_name: str = f"团队{uuid.uuid4().hex[:8]}"
|
||||||
|
update_payload: dict[str, str] = {"name": new_name}
|
||||||
|
res: dict[str, Any] = update_team(web_api_auth, tenant_id, update_payload)
|
||||||
|
# Should succeed if unicode is supported
|
||||||
|
assert res["code"] in (0, 101)
|
||||||
|
|
||||||
|
@pytest.mark.p2
|
||||||
|
def test_update_team_credit_zero(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test updating a team with zero credit (should succeed)."""
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
|
||||||
|
# Update with zero credit
|
||||||
|
update_payload: dict[str, int] = {"credit": 0}
|
||||||
|
res: dict[str, Any] = update_team(web_api_auth, tenant_id, update_payload)
|
||||||
|
assert res["code"] == 0, res
|
||||||
|
assert res["data"]["credit"] == 0
|
||||||
|
|
||||||
|
@pytest.mark.p2
|
||||||
|
def test_update_team_credit_large_value(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test updating a team with a large credit value."""
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
|
||||||
|
# Update with large credit value
|
||||||
|
large_credit: int = 999999
|
||||||
|
update_payload: dict[str, int] = {"credit": large_credit}
|
||||||
|
res: dict[str, Any] = update_team(web_api_auth, tenant_id, update_payload)
|
||||||
|
assert res["code"] == 0, res
|
||||||
|
assert res["data"]["credit"] == large_credit
|
||||||
|
|
||||||
|
@pytest.mark.p2
|
||||||
|
def test_update_team_credit_non_integer(
|
||||||
|
self, web_api_auth: RAGFlowWebApiAuth, test_team: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
|
"""Test updating a team with non-integer credit (should fail)."""
|
||||||
|
tenant_id: str = test_team["id"]
|
||||||
|
|
||||||
|
# Try to update with non-integer credit
|
||||||
|
update_payload: dict[str, str] = {"credit": "not_a_number"}
|
||||||
|
res: dict[str, Any] = update_team(web_api_auth, tenant_id, update_payload)
|
||||||
|
# API might accept it and convert, or reject it
|
||||||
|
# This test documents the behavior
|
||||||
|
assert res["code"] in (0, 101, 102)
|
||||||
|
|
||||||
Loading…
Add table
Reference in a new issue