Skip to content

Commit 4e383ea

Browse files
vertex-sdk-botcopybara-github
authored andcommitted
feat: Add support for snapshots for Sandboxes in Vertex AI GenAI SDK.
PiperOrigin-RevId: 897294488
1 parent 2fd8ca0 commit 4e383ea

6 files changed

Lines changed: 1471 additions & 16 deletions

File tree

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import datetime
16+
import importlib
17+
from unittest import mock
18+
19+
from google import auth
20+
from google.auth import credentials as auth_credentials
21+
from google.cloud import aiplatform
22+
import vertexai
23+
from google.cloud.aiplatform import initializer
24+
from google.genai import types as genai_types
25+
import pytest
26+
27+
_TEST_CREDENTIALS = mock.Mock(spec=auth_credentials.AnonymousCredentials())
28+
_TEST_LOCATION = "us-central1"
29+
_TEST_PROJECT = "test-project"
30+
_TEST_RESOURCE_ID = "1028944691210842416"
31+
_TEST_SANDBOX_ID = "sandbox-123"
32+
_TEST_SNAPSHOT_ID = "snapshot-456"
33+
_TEST_PARENT = f"projects/{_TEST_PROJECT}/locations/{_TEST_LOCATION}"
34+
_TEST_AGENT_ENGINE_RESOURCE_NAME = (
35+
f"{_TEST_PARENT}/reasoningEngines/{_TEST_RESOURCE_ID}"
36+
)
37+
_TEST_SANDBOX_RESOURCE_NAME = (
38+
f"{_TEST_AGENT_ENGINE_RESOURCE_NAME}/sandboxes/{_TEST_SANDBOX_ID}"
39+
)
40+
_TEST_SNAPSHOT_RESOURCE_NAME = (
41+
f"{_TEST_SANDBOX_RESOURCE_NAME}/sandboxEnvironmentSnapshots/{_TEST_SNAPSHOT_ID}"
42+
)
43+
44+
45+
@pytest.fixture(scope="module")
46+
def google_auth_mock():
47+
with mock.patch.object(auth, "default") as google_auth_mock:
48+
google_auth_mock.return_value = (
49+
auth_credentials.AnonymousCredentials(),
50+
_TEST_PROJECT,
51+
)
52+
yield google_auth_mock
53+
54+
55+
@pytest.mark.usefixtures("google_auth_mock")
56+
class TestSandboxSnapshots:
57+
58+
def setup_method(self):
59+
importlib.reload(initializer)
60+
importlib.reload(aiplatform)
61+
importlib.reload(vertexai)
62+
self.client = vertexai.Client(
63+
project=_TEST_PROJECT,
64+
location=_TEST_LOCATION,
65+
credentials=_TEST_CREDENTIALS,
66+
)
67+
68+
def teardown_method(self):
69+
initializer.global_pool.shutdown(wait=True)
70+
71+
def test_create_snapshot(self):
72+
with mock.patch.object(
73+
self.client.agent_engines.sandboxes._api_client, "request"
74+
) as request_mock:
75+
request_mock.return_value = genai_types.HttpResponse(
76+
body=b'{"expireTime": "2026-04-22T00:00:00Z"}', headers={}
77+
)
78+
79+
snapshot = self.client.agent_engines.sandboxes.snapshots.create(
80+
name=_TEST_SANDBOX_RESOURCE_NAME,
81+
sandbox_environment_snapshot={},
82+
)
83+
84+
assert isinstance(snapshot.expire_time, datetime.datetime)
85+
request_mock.assert_called_once()
86+
args, _ = request_mock.call_args
87+
assert args[0] == "post"
88+
assert args[1] == f"{_TEST_SANDBOX_RESOURCE_NAME}:snapshot"
89+
90+
def test_delete_snapshot(self):
91+
with mock.patch.object(
92+
self.client.agent_engines.sandboxes._api_client, "request"
93+
) as request_mock:
94+
request_mock.return_value = genai_types.HttpResponse(
95+
body=b'{"name": "operation-name"}', headers={}
96+
)
97+
98+
operation = self.client.agent_engines.sandboxes.snapshots.delete(
99+
name=_TEST_SNAPSHOT_RESOURCE_NAME,
100+
)
101+
102+
assert operation.name == "operation-name"
103+
request_mock.assert_called_once()
104+
args, _ = request_mock.call_args
105+
assert args[0] == "delete"
106+
assert args[1] == _TEST_SNAPSHOT_RESOURCE_NAME
107+
108+
def test_get_snapshot(self):
109+
with mock.patch.object(
110+
self.client.agent_engines.sandboxes._api_client, "request"
111+
) as request_mock:
112+
request_mock.return_value = genai_types.HttpResponse(
113+
body=b'{"expireTime": "2026-04-22T00:00:00Z"}', headers={}
114+
)
115+
116+
snapshot = self.client.agent_engines.sandboxes.snapshots.get(
117+
name=_TEST_SNAPSHOT_RESOURCE_NAME,
118+
)
119+
120+
assert isinstance(snapshot.expire_time, datetime.datetime)
121+
request_mock.assert_called_once()
122+
args, _ = request_mock.call_args
123+
assert args[0] == "get"
124+
assert args[1] == _TEST_SNAPSHOT_RESOURCE_NAME
125+
126+
def test_list_snapshots(self):
127+
with mock.patch.object(
128+
self.client.agent_engines.sandboxes._api_client, "request"
129+
) as request_mock:
130+
request_mock.return_value = genai_types.HttpResponse(
131+
body=(
132+
b'{"sandboxEnvironmentSnapshots": [{"expireTime":'
133+
b' "2026-04-22T00:00:00Z"}, {"expireTime":'
134+
b' "2026-04-22T01:00:00Z"}]}'
135+
),
136+
headers={},
137+
)
138+
139+
response = self.client.agent_engines.sandboxes.snapshots.list(
140+
name=_TEST_SANDBOX_RESOURCE_NAME,
141+
)
142+
143+
assert len(response.sandbox_environment_snapshots) == 2
144+
assert isinstance(
145+
response.sandbox_environment_snapshots[0].expire_time,
146+
datetime.datetime,
147+
)
148+
assert isinstance(
149+
response.sandbox_environment_snapshots[1].expire_time,
150+
datetime.datetime,
151+
)
152+
request_mock.assert_called_once()
153+
args, _ = request_mock.call_args
154+
assert args[0] == "get"
155+
assert (
156+
args[1] == f"{_TEST_SANDBOX_RESOURCE_NAME}/sandboxEnvironmentSnapshots"
157+
)

0 commit comments

Comments
 (0)