""" Integration tests for channel bindings CRUD endpoints (/channel/bindings). """ from __future__ import annotations import uuid import pytest pytestmark = [pytest.mark.asyncio, pytest.mark.integration] _BINDING_SEED = uuid.uuid4().hex[:8] async def _create_binding(test_client, headers, *, channel_type="web", agent_config_id=1): account_id = f"intg_test_{_BINDING_SEED}" group_id = f"group_{_BINDING_SEED}" response = await test_client.post( "/channel/bindings", json={ "channel_type": channel_type, "account_id": account_id, "group_id": group_id, "agent_config_id": agent_config_id, }, headers=headers, ) return response async def test_create_binding_returns_201(test_client, channel_auth_headers): response = await _create_binding(test_client, channel_auth_headers) if response.status_code == 503: pytest.skip("Channel gateway not initialized") assert response.status_code == 201, response.text payload = response.json() assert "id" in payload assert payload["channel_type"] == "web" assert payload["is_enabled"] is True await test_client.delete(f"/channel/bindings/{payload['id']}", headers=channel_auth_headers) async def test_create_binding_response_has_required_fields(test_client, channel_auth_headers): response = await _create_binding(test_client, channel_auth_headers) if response.status_code == 503: pytest.skip("Channel gateway not initialized") assert response.status_code == 201, response.text payload = response.json() for field in ("id", "channel_type", "account_id", "group_id", "agent_config_id", "is_enabled", "created_at"): assert field in payload, f"missing field: {field}" await test_client.delete(f"/channel/bindings/{payload['id']}", headers=channel_auth_headers) async def test_create_binding_with_empty_channel_type_returns_422(test_client, channel_auth_headers): response = await test_client.post( "/channel/bindings", json={ "channel_type": "", "account_id": "test_acct", "group_id": "", "agent_config_id": 1, }, headers=channel_auth_headers, ) if response.status_code == 503: pytest.skip("Channel gateway not initialized") assert response.status_code == 422 async def test_create_binding_with_invalid_agent_config_id_returns_422(test_client, channel_auth_headers): response = await test_client.post( "/channel/bindings", json={ "channel_type": "web", "account_id": "test_acct", "group_id": "", "agent_config_id": 0, }, headers=channel_auth_headers, ) if response.status_code == 503: pytest.skip("Channel gateway not initialized") assert response.status_code == 422 async def test_list_bindings_returns_paginated_result(test_client, channel_auth_headers): response = await test_client.get("/channel/bindings", headers=channel_auth_headers) if response.status_code == 503: pytest.skip("Channel gateway not initialized") assert response.status_code == 200, response.text payload = response.json() assert "items" in payload assert "meta" in payload meta = payload["meta"] for field in ("total", "offset", "limit"): assert field in meta, f"missing meta field: {field}" async def test_list_bindings_filter_by_channel_type(test_client, channel_auth_headers): response = await test_client.get( "/channel/bindings", params={"channel_type": "web"}, headers=channel_auth_headers, ) if response.status_code == 503: pytest.skip("Channel gateway not initialized") assert response.status_code == 200, response.text payload = response.json() for item in payload.get("items", []): assert item["channel_type"] == "web" async def test_list_bindings_pagination(test_client, channel_auth_headers): response = await test_client.get( "/channel/bindings", params={"offset": 0, "limit": 1}, headers=channel_auth_headers, ) if response.status_code == 503: pytest.skip("Channel gateway not initialized") assert response.status_code == 200, response.text payload = response.json() assert payload["meta"]["limit"] == 1 assert len(payload["items"]) <= 1 async def test_delete_binding_returns_ok(test_client, channel_auth_headers): create_resp = await _create_binding(test_client, channel_auth_headers) if create_resp.status_code == 503: pytest.skip("Channel gateway not initialized") assert create_resp.status_code == 201, create_resp.text binding_id = create_resp.json()["id"] delete_resp = await test_client.delete( f"/channel/bindings/{binding_id}", headers=channel_auth_headers, ) assert delete_resp.status_code == 200, delete_resp.text assert delete_resp.json()["ok"] is True async def test_delete_nonexistent_binding_returns_404(test_client, channel_auth_headers): response = await test_client.delete( "/channel/bindings/99999999", headers=channel_auth_headers, ) if response.status_code == 503: pytest.skip("Channel gateway not initialized") assert response.status_code == 404 async def test_binding_full_lifecycle(test_client, channel_auth_headers): create_resp = await _create_binding(test_client, channel_auth_headers) if create_resp.status_code == 503: pytest.skip("Channel gateway not initialized") assert create_resp.status_code == 201, create_resp.text binding = create_resp.json() binding_id = binding["id"] list_resp = await test_client.get("/channel/bindings", headers=channel_auth_headers) assert list_resp.status_code == 200 ids = [b["id"] for b in list_resp.json()["items"]] assert binding_id in ids delete_resp = await test_client.delete( f"/channel/bindings/{binding_id}", headers=channel_auth_headers, ) assert delete_resp.status_code == 200 list_resp2 = await test_client.get("/channel/bindings", headers=channel_auth_headers) ids2 = [b["id"] for b in list_resp2.json()["items"]] assert binding_id not in ids2