|
1 | 1 | import json |
2 | 2 | from fnmatch import fnmatch |
3 | | -from typing import Any |
| 3 | +from typing import Any, Literal |
4 | 4 |
|
5 | 5 | import requests |
6 | 6 | import yaml |
@@ -442,46 +442,56 @@ def get_labels_from_configmaps(admin_client: DynamicClient, namespace: str) -> l |
442 | 442 | return labels |
443 | 443 |
|
444 | 444 |
|
445 | | -def get_labels_from_api(model_catalog_rest_url: str, user_token: str) -> list[dict[str, Any]]: |
| 445 | +def get_labels_from_api( |
| 446 | + model_catalog_rest_url: str, user_token: str, asset_type: Literal["models", "mcp_servers"] | None = None |
| 447 | +) -> list[dict[str, Any]]: |
446 | 448 | """ |
447 | 449 | Get labels from the API endpoint. |
448 | 450 |
|
449 | 451 | Args: |
450 | 452 | model_catalog_rest_url: Base URL for model catalog API |
451 | 453 | user_token: Authentication token |
| 454 | + asset_type: Filter by asset type ('models' or 'mcp_servers') |
452 | 455 |
|
453 | 456 | Returns: |
454 | 457 | List of label dictionaries from API response |
455 | 458 | """ |
456 | 459 |
|
457 | 460 | url = f"{model_catalog_rest_url}labels" |
458 | 461 | headers = get_rest_headers(token=user_token) |
459 | | - response = execute_get_command(url=url, headers=headers) |
| 462 | + params: dict[str, str] | None = {"assetType": asset_type} if asset_type is not None else None |
| 463 | + response = execute_get_command(url=url, headers=headers, params=params) |
460 | 464 | return response["items"] |
461 | 465 |
|
462 | 466 |
|
| 467 | +def _label_key(label: dict[str, Any]) -> tuple[str | None, str | None, str | None]: |
| 468 | + """Extract comparable key from a label dict.""" |
| 469 | + return (label.get("name"), label.get("displayName"), label.get("description")) |
| 470 | + |
| 471 | + |
463 | 472 | def verify_labels_match(expected_labels: list[dict[str, Any]], api_labels: list[dict[str, Any]]) -> None: |
464 | 473 | """ |
465 | | - Verify that all expected labels are present in the API response. |
| 474 | + Verify that expected labels and API labels match exactly (bidirectional). |
466 | 475 |
|
467 | 476 | Args: |
468 | 477 | expected_labels: Labels expected from ConfigMaps |
469 | 478 | api_labels: Labels returned by API |
470 | 479 |
|
471 | 480 | Raises: |
472 | | - AssertionError: If any expected label is not found in API response |
| 481 | + AssertionError: If there are missing or unexpected labels |
473 | 482 | """ |
474 | 483 | LOGGER.info(f"Verifying {len(expected_labels)} expected labels against {len(api_labels)} API labels") |
475 | 484 |
|
476 | | - for expected_label in expected_labels: |
477 | | - found = False |
478 | | - for api_label in api_labels: |
479 | | - if ( |
480 | | - expected_label.get("name") == api_label.get("name") |
481 | | - and expected_label.get("displayName") == api_label.get("displayName") |
482 | | - and expected_label.get("description") == api_label.get("description") |
483 | | - ): |
484 | | - found = True |
485 | | - break |
486 | | - |
487 | | - assert found, f"Expected label not found in API response: {expected_label}" |
| 485 | + expected_keys = {_label_key(label) for label in expected_labels} |
| 486 | + api_keys = {_label_key(label) for label in api_labels} |
| 487 | + |
| 488 | + missing = expected_keys - api_keys |
| 489 | + unexpected = api_keys - expected_keys |
| 490 | + |
| 491 | + errors = [] |
| 492 | + if missing: |
| 493 | + errors.append(f"Missing labels not found in API response: {missing}") |
| 494 | + if unexpected: |
| 495 | + errors.append(f"Unexpected labels in API response: {unexpected}") |
| 496 | + |
| 497 | + assert not errors, "\n".join(errors) |
0 commit comments