|
15 | 15 | # limitations under the License.
|
16 | 16 | #
|
17 | 17 |
|
18 |
| -from unittest.mock import call |
19 | 18 | import re
|
| 19 | +from typing import Dict |
20 | 20 | from unittest import mock
|
| 21 | +from unittest.mock import call |
21 | 22 | from unittest.mock import patch
|
22 |
| -from typing import Dict |
23 | 23 |
|
24 | 24 | from google.api_core import operation as ga_operation
|
25 | 25 | from google.cloud import aiplatform
|
26 | 26 | from google.cloud.aiplatform import base
|
27 | 27 | from google.cloud.aiplatform.compat import types
|
28 |
| -from vertexai.resources.preview import ( |
29 |
| - FeatureOnlineStore, |
30 |
| - FeatureOnlineStoreType, |
31 |
| - FeatureViewBigQuerySource, |
32 |
| - IndexConfig, |
33 |
| - DistanceMeasureType, |
34 |
| - TreeAhConfig, |
35 |
| -) |
36 |
| -from vertexai.resources.preview.feature_store import ( |
37 |
| - feature_online_store, |
38 |
| -) |
39 | 28 | from google.cloud.aiplatform.compat.services import (
|
40 | 29 | feature_online_store_admin_service_client,
|
41 | 30 | )
|
42 |
| -import pytest |
43 |
| - |
44 |
| -from test_feature_view import fv_eq |
45 | 31 | from feature_store_constants import (
|
46 |
| - _TEST_PROJECT, |
47 |
| - _TEST_LOCATION, |
48 |
| - _TEST_PARENT, |
49 | 32 | _TEST_BIGTABLE_FOS1_ID,
|
50 |
| - _TEST_BIGTABLE_FOS1_PATH, |
51 | 33 | _TEST_BIGTABLE_FOS1_LABELS,
|
| 34 | + _TEST_BIGTABLE_FOS1_PATH, |
52 | 35 | _TEST_BIGTABLE_FOS2_ID,
|
53 |
| - _TEST_BIGTABLE_FOS2_PATH, |
54 | 36 | _TEST_BIGTABLE_FOS2_LABELS,
|
| 37 | + _TEST_BIGTABLE_FOS2_PATH, |
55 | 38 | _TEST_BIGTABLE_FOS3_ID,
|
56 |
| - _TEST_BIGTABLE_FOS3_PATH, |
57 | 39 | _TEST_BIGTABLE_FOS3_LABELS,
|
| 40 | + _TEST_BIGTABLE_FOS3_PATH, |
58 | 41 | _TEST_ESF_OPTIMIZED_FOS_ID,
|
59 |
| - _TEST_ESF_OPTIMIZED_FOS_PATH, |
60 | 42 | _TEST_ESF_OPTIMIZED_FOS_LABELS,
|
61 |
| - _TEST_PSC_OPTIMIZED_FOS_ID, |
62 |
| - _TEST_PSC_OPTIMIZED_FOS_LABELS, |
63 |
| - _TEST_PSC_PROJECT_ALLOWLIST, |
| 43 | + _TEST_ESF_OPTIMIZED_FOS_PATH, |
64 | 44 | _TEST_FOS_LIST,
|
65 |
| - _TEST_FV1_ID, |
66 |
| - _TEST_FV1_PATH, |
67 |
| - _TEST_FV1_LABELS, |
68 | 45 | _TEST_FV1_BQ_URI,
|
69 | 46 | _TEST_FV1_ENTITY_ID_COLUMNS,
|
| 47 | + _TEST_FV1_ID, |
| 48 | + _TEST_FV1_LABELS, |
| 49 | + _TEST_FV1_PATH, |
| 50 | + _TEST_LOCATION, |
70 | 51 | _TEST_OPTIMIZED_EMBEDDING_FV_ID,
|
71 | 52 | _TEST_OPTIMIZED_EMBEDDING_FV_PATH,
|
| 53 | + _TEST_PARENT, |
| 54 | + _TEST_PROJECT, |
| 55 | + _TEST_PSC_OPTIMIZED_FOS_ID, |
| 56 | + _TEST_PSC_OPTIMIZED_FOS_LABELS, |
| 57 | + _TEST_PSC_OPTIMIZED_FOS_PATH, |
| 58 | + _TEST_PSC_PROJECT_ALLOWLIST, |
72 | 59 | )
|
| 60 | +from test_feature_view import fv_eq |
| 61 | +from vertexai.resources.preview import ( |
| 62 | + DistanceMeasureType, |
| 63 | + FeatureOnlineStore, |
| 64 | + FeatureOnlineStoreType, |
| 65 | + FeatureViewBigQuerySource, |
| 66 | + IndexConfig, |
| 67 | + TreeAhConfig, |
| 68 | +) |
| 69 | +from vertexai.resources.preview.feature_store import ( |
| 70 | + feature_online_store, |
| 71 | +) |
| 72 | +import pytest |
73 | 73 |
|
74 | 74 |
|
75 | 75 | @pytest.fixture
|
@@ -277,24 +277,109 @@ def test_create_esf_optimized_store(
|
277 | 277 | )
|
278 | 278 |
|
279 | 279 |
|
280 |
| -@pytest.mark.parametrize("create_request_timeout", [None, 1.0]) |
281 |
| -def test_create_psc_optimized_store( |
282 |
| - create_request_timeout, |
283 |
| -): |
| 280 | +def test_create_psc_optimized_store_no_project_allowlist_raises_error(): |
284 | 281 | aiplatform.init(project=_TEST_PROJECT, location=_TEST_LOCATION)
|
| 282 | + |
285 | 283 | with pytest.raises(
|
286 | 284 | ValueError,
|
287 |
| - match=re.escape("private_service_connect is not supported"), |
| 285 | + match=re.escape( |
| 286 | + "`project_allowlist` cannot be empty when `enable_private_service_connect` is" |
| 287 | + " set to true." |
| 288 | + ), |
288 | 289 | ):
|
289 | 290 | FeatureOnlineStore.create_optimized_store(
|
290 | 291 | _TEST_PSC_OPTIMIZED_FOS_ID,
|
291 | 292 | labels=_TEST_PSC_OPTIMIZED_FOS_LABELS,
|
292 |
| - create_request_timeout=create_request_timeout, |
293 | 293 | enable_private_service_connect=True,
|
294 |
| - project_allowlist=_TEST_PSC_PROJECT_ALLOWLIST, |
295 | 294 | )
|
296 | 295 |
|
297 | 296 |
|
| 297 | +def test_create_psc_optimized_store_empty_project_allowlist_raises_error(): |
| 298 | + aiplatform.init(project=_TEST_PROJECT, location=_TEST_LOCATION) |
| 299 | + |
| 300 | + with pytest.raises( |
| 301 | + ValueError, |
| 302 | + match=re.escape( |
| 303 | + "`project_allowlist` cannot be empty when `enable_private_service_connect` is" |
| 304 | + " set to true." |
| 305 | + ), |
| 306 | + ): |
| 307 | + FeatureOnlineStore.create_optimized_store( |
| 308 | + _TEST_PSC_OPTIMIZED_FOS_ID, |
| 309 | + enable_private_service_connect=True, |
| 310 | + project_allowlist=[], |
| 311 | + ) |
| 312 | + |
| 313 | + |
| 314 | +@pytest.mark.parametrize("create_request_timeout", [None, 1.0]) |
| 315 | +@pytest.mark.parametrize("sync", [True, False]) |
| 316 | +def test_create_psc_optimized_store( |
| 317 | + create_psc_optimized_fos_mock, |
| 318 | + get_psc_optimized_fos_mock, |
| 319 | + fos_logger_mock, |
| 320 | + create_request_timeout, |
| 321 | + sync, |
| 322 | +): |
| 323 | + aiplatform.init(project=_TEST_PROJECT, location=_TEST_LOCATION) |
| 324 | + fos = FeatureOnlineStore.create_optimized_store( |
| 325 | + _TEST_PSC_OPTIMIZED_FOS_ID, |
| 326 | + labels=_TEST_PSC_OPTIMIZED_FOS_LABELS, |
| 327 | + create_request_timeout=create_request_timeout, |
| 328 | + enable_private_service_connect=True, |
| 329 | + project_allowlist=_TEST_PSC_PROJECT_ALLOWLIST, |
| 330 | + ) |
| 331 | + |
| 332 | + if not sync: |
| 333 | + fos.wait() |
| 334 | + |
| 335 | + expected_feature_online_store = types.feature_online_store_v1.FeatureOnlineStore( |
| 336 | + optimized=types.feature_online_store_v1.FeatureOnlineStore.Optimized(), |
| 337 | + dedicated_serving_endpoint=types.feature_online_store_v1.FeatureOnlineStore.DedicatedServingEndpoint( |
| 338 | + private_service_connect_config=types.service_networking_v1.PrivateServiceConnectConfig( |
| 339 | + enable_private_service_connect=True, |
| 340 | + project_allowlist=_TEST_PSC_PROJECT_ALLOWLIST, |
| 341 | + ) |
| 342 | + ), |
| 343 | + labels=_TEST_PSC_OPTIMIZED_FOS_LABELS, |
| 344 | + ) |
| 345 | + create_psc_optimized_fos_mock.assert_called_once_with( |
| 346 | + parent=_TEST_PARENT, |
| 347 | + feature_online_store=expected_feature_online_store, |
| 348 | + feature_online_store_id=_TEST_PSC_OPTIMIZED_FOS_ID, |
| 349 | + metadata=(), |
| 350 | + timeout=create_request_timeout, |
| 351 | + ) |
| 352 | + |
| 353 | + fos_logger_mock.assert_has_calls( |
| 354 | + [ |
| 355 | + call("Creating FeatureOnlineStore"), |
| 356 | + call( |
| 357 | + "Create FeatureOnlineStore backing LRO:" |
| 358 | + f" {create_psc_optimized_fos_mock.return_value.operation.name}" |
| 359 | + ), |
| 360 | + call( |
| 361 | + "FeatureOnlineStore created. Resource name:" |
| 362 | + " projects/test-project/locations/us-central1/featureOnlineStores/my_psc_optimized_fos" |
| 363 | + ), |
| 364 | + call("To use this FeatureOnlineStore in another session:"), |
| 365 | + call( |
| 366 | + "feature_online_store =" |
| 367 | + " aiplatform.FeatureOnlineStore('projects/test-project/locations/us-central1/featureOnlineStores/my_psc_optimized_fos')" |
| 368 | + ), |
| 369 | + ] |
| 370 | + ) |
| 371 | + |
| 372 | + fos_eq( |
| 373 | + fos, |
| 374 | + name=_TEST_PSC_OPTIMIZED_FOS_ID, |
| 375 | + resource_name=_TEST_PSC_OPTIMIZED_FOS_PATH, |
| 376 | + project=_TEST_PROJECT, |
| 377 | + location=_TEST_LOCATION, |
| 378 | + labels=_TEST_PSC_OPTIMIZED_FOS_LABELS, |
| 379 | + type=FeatureOnlineStoreType.OPTIMIZED, |
| 380 | + ) |
| 381 | + |
| 382 | + |
298 | 383 | def test_list(list_fos_mock):
|
299 | 384 | aiplatform.init(project=_TEST_PROJECT, location=_TEST_LOCATION)
|
300 | 385 |
|
|
0 commit comments