/ tests / integration / test_validate_endpoint.py
test_validate_endpoint.py
  1  """
  2  Integration tests for the FastAPI /validate/kind-2003 endpoint.
  3  
  4  These tests use FastAPI's TestClient to test the actual validation endpoint
  5  with real rule execution (subprocess calls).
  6  
  7  IMPORTANT: The validate endpoint uses PUT method (not POST) as defined in main.py.
  8  IMPORTANT: The Nip35Kind2003Event Pydantic model validates event structure strictly.
  9  """
 10  
 11  import pytest
 12  
 13  
 14  def create_valid_nip35_event():
 15      """Create a valid NIP-35 event that passes Pydantic validation."""
 16      return {
 17          "id": "0000000000000000000000000000000000000000000000000000000000000001",
 18          "pubkey": "0000000000000000000000000000000000000000000000000000000000000002",
 19          "created_at": 1234567890,
 20          "kind": 2003,
 21          "tags": [
 22              ["title", "Test Torrent"],
 23              ["x", "abc123abc123abc123abc123abc123abc123abc1"],  # 40-char hex btih
 24              ["file", "test.mkv", "1073741824"],  # name, size in bytes
 25          ],
 26          "content": "Test torrent description",
 27          "sig": "0" * 128,  # 128-char hex signature (64 bytes)
 28      }
 29  
 30  
 31  @pytest.mark.integration
 32  @pytest.mark.slow
 33  def test_validate_accepts_valid_event():
 34      """Test that validate endpoint accepts a valid NIP-35 event."""
 35      try:
 36          from fastapi.testclient import TestClient
 37  
 38          from main import app
 39      except Exception as e:
 40          pytest.skip(f"Failed to import app (venv generation issue?): {e}")
 41  
 42      client = TestClient(app)
 43      event = create_valid_nip35_event()
 44  
 45      response = client.put("/validate/kind-2003", json=event)
 46  
 47      assert response.status_code == 200
 48      data = response.json()
 49      assert "passed" in data
 50      assert "rules" in data
 51      assert isinstance(data["passed"], bool)
 52      assert isinstance(data["rules"], dict)
 53  
 54  
 55  @pytest.mark.integration
 56  @pytest.mark.slow
 57  def test_validate_returns_rule_results():
 58      """Test that validate endpoint returns rule IDs and results."""
 59      try:
 60          from fastapi.testclient import TestClient
 61  
 62          from main import app
 63      except Exception as e:
 64          pytest.skip(f"Failed to import app (venv generation issue?): {e}")
 65  
 66      client = TestClient(app)
 67      event = create_valid_nip35_event()
 68  
 69      response = client.put("/validate/kind-2003", json=event)
 70  
 71      assert response.status_code == 200
 72      data = response.json()
 73  
 74      # Should have rules in response (at least the 3 POC rules if enabled)
 75      # Rules format: {"D-SCHEMA-03": {"passed": true/false}, ...}
 76      if len(data["rules"]) > 0:
 77          # Check that each rule has expected structure
 78          for _rule_id, rule_result in data["rules"].items():
 79              assert isinstance(rule_result, dict)
 80              # Rule should have either "passed" (deterministic) or "score" (probabilistic)
 81              assert "passed" in rule_result or "score" in rule_result
 82  
 83  
 84  @pytest.mark.integration
 85  def test_validate_rejects_invalid_event_format():
 86      """Test that validate endpoint rejects malformed JSON."""
 87      try:
 88          from fastapi.testclient import TestClient
 89  
 90          from main import app
 91      except Exception as e:
 92          pytest.skip(f"Failed to import app (venv generation issue?): {e}")
 93  
 94      client = TestClient(app)
 95  
 96      # Send invalid JSON (missing required fields)
 97      response = client.put("/validate/kind-2003", json={"invalid": "data"})
 98  
 99      # Should return 422 Unprocessable Entity (Pydantic validation error)
100      assert response.status_code == 422
101  
102  
103  @pytest.mark.integration
104  def test_validate_rejects_wrong_kind():
105      """Test that validate endpoint rejects events with wrong kind."""
106      try:
107          from fastapi.testclient import TestClient
108  
109          from main import app
110      except Exception as e:
111          pytest.skip(f"Failed to import app (venv generation issue?): {e}")
112  
113      client = TestClient(app)
114      event = create_valid_nip35_event()
115      event["kind"] = 1  # Wrong kind (should be 2003)
116  
117      response = client.put("/validate/kind-2003", json=event)
118  
119      # Should return 422 Unprocessable Entity (kind must be 2003)
120      assert response.status_code == 422
121  
122  
123  @pytest.mark.integration
124  def test_validate_rejects_missing_required_tags():
125      """Test that validate endpoint rejects events without required tags."""
126      try:
127          from fastapi.testclient import TestClient
128  
129          from main import app
130      except Exception as e:
131          pytest.skip(f"Failed to import app (venv generation issue?): {e}")
132  
133      client = TestClient(app)
134  
135      # Event missing title tag (remove it from valid event)
136      event = create_valid_nip35_event()
137      # Remove title tag from tags list
138      event["tags"] = [
139          tag for tag in event["tags"] if tag[0] != "title"
140      ]
141  
142      response = client.put("/validate/kind-2003", json=event)
143  
144      # Should return 422 Unprocessable Entity (missing title tag)
145      assert response.status_code == 422
146      # Error message should mention title or missing
147      error_detail = response.json().get("detail", "")
148      assert "title" in str(error_detail).lower() or "missing" in str(error_detail).lower()