|
5 | 5 | Note: These tests rely on conftest.py for Pinecone/OpenAI/Redis mocking. |
6 | 6 | """ |
7 | 7 | import pytest |
8 | | -from unittest.mock import AsyncMock, patch, MagicMock |
| 8 | +from unittest.mock import patch, MagicMock |
9 | 9 | from datetime import datetime, timezone, timedelta |
10 | 10 | import json |
11 | 11 |
|
@@ -512,3 +512,170 @@ def test_expired_repo_allows_new_indexing( |
512 | 512 |
|
513 | 513 | assert response.status_code == 202 |
514 | 514 | assert response.json()["job_id"] == "idx_new123456" |
| 515 | + |
| 516 | + |
| 517 | +# ============================================================================= |
| 518 | +# STATUS ENDPOINT TESTS (GET /playground/index/{job_id}) |
| 519 | +# ============================================================================= |
| 520 | + |
| 521 | +class TestStatusEndpoint: |
| 522 | + """Tests for GET /playground/index/{job_id} status endpoint.""" |
| 523 | + |
| 524 | + @pytest.fixture |
| 525 | + def client(self): |
| 526 | + """Create test client.""" |
| 527 | + from fastapi.testclient import TestClient |
| 528 | + from main import app |
| 529 | + return TestClient(app) |
| 530 | + |
| 531 | + def test_invalid_job_id_format_returns_400(self, client): |
| 532 | + """Invalid job ID format returns 400.""" |
| 533 | + response = client.get("/api/v1/playground/index/invalid_format") |
| 534 | + assert response.status_code == 400 |
| 535 | + assert response.json()["detail"]["error"] == "invalid_job_id" |
| 536 | + |
| 537 | + def test_job_not_found_returns_404(self, client): |
| 538 | + """Non-existent job returns 404.""" |
| 539 | + response = client.get("/api/v1/playground/index/idx_nonexistent123") |
| 540 | + assert response.status_code == 404 |
| 541 | + assert response.json()["detail"]["error"] == "job_not_found" |
| 542 | + |
| 543 | + @patch('routes.playground.AnonymousIndexingJob') |
| 544 | + def test_queued_job_returns_status(self, mock_job_class, client): |
| 545 | + """Queued job returns correct status.""" |
| 546 | + mock_job_manager = MagicMock() |
| 547 | + mock_job_manager.get_job.return_value = { |
| 548 | + "job_id": "idx_test123456", |
| 549 | + "status": "queued", |
| 550 | + "owner": "user", |
| 551 | + "repo_name": "repo", |
| 552 | + "branch": "main", |
| 553 | + "github_url": "https://github.com/user/repo", |
| 554 | + "created_at": "2024-01-01T00:00:00Z", |
| 555 | + "updated_at": "2024-01-01T00:00:00Z", |
| 556 | + } |
| 557 | + mock_job_class.return_value = mock_job_manager |
| 558 | + |
| 559 | + response = client.get("/api/v1/playground/index/idx_test123456") |
| 560 | + |
| 561 | + assert response.status_code == 200 |
| 562 | + data = response.json() |
| 563 | + assert data["status"] == "queued" |
| 564 | + assert data["message"] == "Job is queued for processing" |
| 565 | + |
| 566 | + @patch('routes.playground.AnonymousIndexingJob') |
| 567 | + def test_processing_job_returns_progress(self, mock_job_class, client): |
| 568 | + """Processing job returns progress info.""" |
| 569 | + mock_job_manager = MagicMock() |
| 570 | + mock_job_manager.get_job.return_value = { |
| 571 | + "job_id": "idx_test123456", |
| 572 | + "status": "processing", |
| 573 | + "owner": "user", |
| 574 | + "repo_name": "repo", |
| 575 | + "branch": "main", |
| 576 | + "github_url": "https://github.com/user/repo", |
| 577 | + "created_at": "2024-01-01T00:00:00Z", |
| 578 | + "updated_at": "2024-01-01T00:00:01Z", |
| 579 | + "progress": { |
| 580 | + "files_processed": 50, |
| 581 | + "files_total": 100, |
| 582 | + "functions_found": 250, |
| 583 | + "current_file": "src/index.ts" |
| 584 | + } |
| 585 | + } |
| 586 | + mock_job_class.return_value = mock_job_manager |
| 587 | + |
| 588 | + response = client.get("/api/v1/playground/index/idx_test123456") |
| 589 | + |
| 590 | + assert response.status_code == 200 |
| 591 | + data = response.json() |
| 592 | + assert data["status"] == "processing" |
| 593 | + assert data["progress"]["files_processed"] == 50 |
| 594 | + assert data["progress"]["percent_complete"] == 50 |
| 595 | + |
| 596 | + @patch('routes.playground.AnonymousIndexingJob') |
| 597 | + def test_completed_job_returns_repo_id(self, mock_job_class, client): |
| 598 | + """Completed job returns repo_id and stats.""" |
| 599 | + mock_job_manager = MagicMock() |
| 600 | + mock_job_manager.get_job.return_value = { |
| 601 | + "job_id": "idx_test123456", |
| 602 | + "status": "completed", |
| 603 | + "owner": "user", |
| 604 | + "repo_name": "repo", |
| 605 | + "branch": "main", |
| 606 | + "github_url": "https://github.com/user/repo", |
| 607 | + "repo_id": "anon_idx_test123456", |
| 608 | + "created_at": "2024-01-01T00:00:00Z", |
| 609 | + "updated_at": "2024-01-01T00:01:00Z", |
| 610 | + "stats": { |
| 611 | + "files_indexed": 100, |
| 612 | + "functions_found": 500, |
| 613 | + "time_taken_seconds": 45.2 |
| 614 | + } |
| 615 | + } |
| 616 | + mock_job_class.return_value = mock_job_manager |
| 617 | + |
| 618 | + response = client.get("/api/v1/playground/index/idx_test123456") |
| 619 | + |
| 620 | + assert response.status_code == 200 |
| 621 | + data = response.json() |
| 622 | + assert data["status"] == "completed" |
| 623 | + assert data["repo_id"] == "anon_idx_test123456" |
| 624 | + assert data["stats"]["files_indexed"] == 100 |
| 625 | + |
| 626 | + @patch('routes.playground.AnonymousIndexingJob') |
| 627 | + def test_failed_job_returns_error(self, mock_job_class, client): |
| 628 | + """Failed job returns error details.""" |
| 629 | + mock_job_manager = MagicMock() |
| 630 | + mock_job_manager.get_job.return_value = { |
| 631 | + "job_id": "idx_test123456", |
| 632 | + "status": "failed", |
| 633 | + "owner": "user", |
| 634 | + "repo_name": "repo", |
| 635 | + "branch": "main", |
| 636 | + "github_url": "https://github.com/user/repo", |
| 637 | + "error": "clone_failed", |
| 638 | + "error_message": "Repository not found or access denied", |
| 639 | + "created_at": "2024-01-01T00:00:00Z", |
| 640 | + "updated_at": "2024-01-01T00:00:30Z", |
| 641 | + } |
| 642 | + mock_job_class.return_value = mock_job_manager |
| 643 | + |
| 644 | + response = client.get("/api/v1/playground/index/idx_test123456") |
| 645 | + |
| 646 | + assert response.status_code == 200 |
| 647 | + data = response.json() |
| 648 | + assert data["status"] == "failed" |
| 649 | + assert data["error"] == "clone_failed" |
| 650 | + assert "not found" in data["error_message"].lower() |
| 651 | + |
| 652 | + @patch('routes.playground.AnonymousIndexingJob') |
| 653 | + def test_partial_job_includes_partial_info(self, mock_job_class, client): |
| 654 | + """Partial indexing job includes partial flag.""" |
| 655 | + mock_job_manager = MagicMock() |
| 656 | + mock_job_manager.get_job.return_value = { |
| 657 | + "job_id": "idx_test123456", |
| 658 | + "status": "processing", |
| 659 | + "owner": "user", |
| 660 | + "repo_name": "large-repo", |
| 661 | + "branch": "main", |
| 662 | + "github_url": "https://github.com/user/large-repo", |
| 663 | + "is_partial": True, |
| 664 | + "max_files": 200, |
| 665 | + "file_count": 500, |
| 666 | + "created_at": "2024-01-01T00:00:00Z", |
| 667 | + "updated_at": "2024-01-01T00:00:10Z", |
| 668 | + "progress": { |
| 669 | + "files_processed": 100, |
| 670 | + "files_total": 200, |
| 671 | + "functions_found": 400 |
| 672 | + } |
| 673 | + } |
| 674 | + mock_job_class.return_value = mock_job_manager |
| 675 | + |
| 676 | + response = client.get("/api/v1/playground/index/idx_test123456") |
| 677 | + |
| 678 | + assert response.status_code == 200 |
| 679 | + data = response.json() |
| 680 | + assert data["partial"] is True |
| 681 | + assert data["max_files"] == 200 |
0 commit comments