|
7 | 7 | from __future__ import annotations |
8 | 8 |
|
9 | 9 | import uuid |
| 10 | +from collections.abc import Callable |
10 | 11 | from datetime import UTC, datetime |
11 | 12 | from typing import cast |
12 | 13 | from unittest.mock import AsyncMock, MagicMock |
|
21 | 22 | ) |
22 | 23 | from ai.backend.common.dto.manager.v2.deployment.types import IntOrPercent |
23 | 24 | from ai.backend.common.identifier.deployment import DeploymentID |
| 25 | +from ai.backend.common.identifier.deployment_revision import DeploymentRevisionID |
24 | 26 | from ai.backend.common.identifier.image import ImageID |
25 | 27 | from ai.backend.common.identifier.runtime_variant import RuntimeVariantID |
26 | 28 | from ai.backend.common.identifier.vfolder import VFolderUUID |
|
50 | 52 | ExecutionSpec, |
51 | 53 | ModelMountConfigData, |
52 | 54 | ModelRevisionData, |
| 55 | + ModelRevisionSpec, |
53 | 56 | ModelRuntimeConfigData, |
| 57 | + MountMetadata, |
54 | 58 | ReplicaSpec, |
55 | 59 | ResourceConfigData, |
56 | 60 | ResourceSpec, |
|
76 | 80 | AddModelRevisionAction, |
77 | 81 | ) |
78 | 82 | from ai.backend.manager.services.deployment.processors import DeploymentProcessors |
79 | | -from ai.backend.manager.services.deployment.service import DeploymentService |
| 83 | +from ai.backend.manager.services.deployment.service import ( |
| 84 | + DeploymentService, |
| 85 | + _convert_deployment_info_to_data, |
| 86 | +) |
80 | 87 | from ai.backend.manager.sokovan.deployment import DeploymentController |
81 | 88 |
|
82 | 89 |
|
@@ -634,3 +641,72 @@ async def test_persists_coordinator_jwt_instead_of_random( |
634 | 641 | creator = cast(RBACEntityCreator[object], repo_call.args[0]) |
635 | 642 | spec = cast(EndpointTokenCreatorSpec, creator.spec) |
636 | 643 | assert spec.token == sample_coordinator_jwt |
| 644 | + |
| 645 | + |
| 646 | +class TestConvertDeploymentInfoToData: |
| 647 | + """Regression test for ``_convert_deployment_info_to_data`` (BA-5963).""" |
| 648 | + |
| 649 | + @pytest.fixture |
| 650 | + def make_revision_spec(self) -> Callable[[], ModelRevisionSpec]: |
| 651 | + def make() -> ModelRevisionSpec: |
| 652 | + return ModelRevisionSpec( |
| 653 | + revision_id=DeploymentRevisionID(uuid.uuid4()), |
| 654 | + image_id=ImageID(uuid.uuid4()), |
| 655 | + resource_spec=ResourceSpec( |
| 656 | + cluster_mode=ClusterMode.SINGLE_NODE, |
| 657 | + cluster_size=1, |
| 658 | + resource_slots={"cpu": "1"}, |
| 659 | + ), |
| 660 | + mounts=MountMetadata( |
| 661 | + model_vfolder_id=VFolderUUID(uuid.uuid4()), |
| 662 | + model_definition_path="model-definition.yaml", |
| 663 | + model_mount_destination="/models", |
| 664 | + extra_mounts=[], |
| 665 | + ), |
| 666 | + execution=ExecutionSpec( |
| 667 | + runtime_variant_id=RuntimeVariantID(uuid.uuid4()), |
| 668 | + ), |
| 669 | + ) |
| 670 | + |
| 671 | + return make |
| 672 | + |
| 673 | + def test_current_revision_resolved_by_id_match_not_list_order( |
| 674 | + self, |
| 675 | + make_revision_spec: Callable[[], ModelRevisionSpec], |
| 676 | + ) -> None: |
| 677 | + """Pin: revision lookup must use explicit ``current_revision_id``, not list[0].""" |
| 678 | + deploying_spec = make_revision_spec() |
| 679 | + current_spec = make_revision_spec() |
| 680 | + |
| 681 | + deployment_info = DeploymentInfo( |
| 682 | + id=DeploymentID(uuid.uuid4()), |
| 683 | + metadata=DeploymentMetadata( |
| 684 | + name="ba5963-test", |
| 685 | + domain="default", |
| 686 | + project=uuid.uuid4(), |
| 687 | + resource_group="default", |
| 688 | + created_user=uuid.uuid4(), |
| 689 | + session_owner=uuid.uuid4(), |
| 690 | + created_at=datetime(2024, 1, 1, tzinfo=UTC), |
| 691 | + revision_history_limit=10, |
| 692 | + ), |
| 693 | + state=DeploymentState( |
| 694 | + lifecycle=EndpointLifecycle.DEPLOYING, |
| 695 | + scaling_state=ScalingState.STABLE, |
| 696 | + retry_count=0, |
| 697 | + ), |
| 698 | + replica_spec=ReplicaSpec(replica_count=1), |
| 699 | + network=DeploymentNetworkSpec(open_to_public=False), |
| 700 | + model_revisions=[deploying_spec, current_spec], |
| 701 | + options=DeploymentOptions(), |
| 702 | + current_revision_id=current_spec.revision_id, |
| 703 | + deploying_revision_id=deploying_spec.revision_id, |
| 704 | + ) |
| 705 | + |
| 706 | + deployment_data = _convert_deployment_info_to_data(deployment_info) |
| 707 | + |
| 708 | + assert deployment_data.current_revision_id == current_spec.revision_id |
| 709 | + assert deployment_data.deploying_revision_id == deploying_spec.revision_id |
| 710 | + assert deployment_data.current_revision_id != deployment_data.deploying_revision_id |
| 711 | + assert deployment_data.revision is not None |
| 712 | + assert deployment_data.revision.id == current_spec.revision_id |
0 commit comments