Skip to content

Commit fdd66ae

Browse files
Validate target status for VuMark instance generation (#2981)
Return TargetStatusNotSuccessError when a VuMark instance generation request targets a VuMark target that is not yet in the success state. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent bcf3523 commit fdd66ae

4 files changed

Lines changed: 56 additions & 3 deletions

File tree

src/mock_vws/_flask_server/vws.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,9 +398,6 @@ def generate_vumark_instance(target_id: str) -> Response:
398398
databases=all_databases,
399399
)
400400

401-
# ``target_id`` is validated by request validators.
402-
del target_id
403-
404401
database = get_database_matching_server_keys(
405402
request_headers=dict(request.headers),
406403
request_body=request.data,
@@ -411,6 +408,10 @@ def generate_vumark_instance(target_id: str) -> Response:
411408
if not isinstance(database, VuMarkDatabase):
412409
raise InvalidTargetTypeError
413410

411+
target = database.get_vumark_target(target_id=target_id)
412+
if target.status != TargetStatuses.SUCCESS.value:
413+
raise TargetStatusNotSuccessError
414+
414415
accept = request.headers.get(key="Accept", default="")
415416
valid_accept_types: dict[str, bytes] = {
416417
"image/png": VUMARK_PNG,

src/mock_vws/_requests_mock_server/mock_web_services_api.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,11 @@ def generate_vumark_instance(self, request: RequestData) -> _ResponseType:
319319
if not isinstance(database, VuMarkDatabase):
320320
raise InvalidTargetTypeError
321321

322+
target_id = request.path.split(sep="/")[-2]
323+
target = database.get_vumark_target(target_id=target_id)
324+
if target.status != TargetStatuses.SUCCESS.value:
325+
raise TargetStatusNotSuccessError
326+
322327
accept = dict(request.headers).get("Accept", "")
323328
if accept not in valid_accept_types:
324329
raise InvalidAcceptHeaderError

src/mock_vws/database.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,15 @@ class VuMarkDatabase:
203203
hash=False,
204204
)
205205

206+
def get_vumark_target(self, target_id: str) -> VuMarkTarget:
207+
"""Return a VuMark target from the database with the given ID."""
208+
(target,) = (
209+
target
210+
for target in self.vumark_targets
211+
if target.target_id == target_id
212+
)
213+
return target
214+
206215
def to_dict(self) -> VuMarkDatabaseDict:
207216
"""Dump a VuMark database to a dictionary which can be loaded as
208217
JSON.

src/mock_vws/target.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ class VuMarkTargetDict(TypedDict):
2424

2525
target_id: str
2626
name: str
27+
processing_time_seconds: float
28+
last_modified_date: str
29+
upload_date: str
2730

2831

2932
class ImageTargetDict(TypedDict):
@@ -228,14 +231,46 @@ class VuMarkTarget:
228231
"""
229232

230233
name: str
234+
processing_time_seconds: float = 0.0
231235
target_id: str = field(default_factory=_random_hex)
236+
last_modified_date: datetime.datetime = field(default_factory=_time_now)
237+
upload_date: datetime.datetime = field(default_factory=_time_now)
238+
239+
@property
240+
def status(self) -> str:
241+
"""Return the status of the target.
242+
243+
VuMark targets always succeed after processing.
244+
"""
245+
processing_time = datetime.timedelta(
246+
seconds=float(self.processing_time_seconds),
247+
)
248+
249+
timezone = self.upload_date.tzinfo
250+
now = datetime.datetime.now(tz=timezone)
251+
time_since_change = now - self.last_modified_date
252+
253+
if time_since_change <= processing_time:
254+
return TargetStatuses.PROCESSING.value
255+
256+
return TargetStatuses.SUCCESS.value
232257

233258
@classmethod
234259
def from_dict(cls, target_dict: VuMarkTargetDict) -> Self:
235260
"""Load a VuMark target from a dictionary."""
261+
timezone = ZoneInfo(key="GMT")
262+
last_modified_date = datetime.datetime.fromisoformat(
263+
target_dict["last_modified_date"],
264+
).replace(tzinfo=timezone)
265+
upload_date = datetime.datetime.fromisoformat(
266+
target_dict["upload_date"],
267+
).replace(tzinfo=timezone)
236268
return cls(
237269
target_id=target_dict["target_id"],
238270
name=target_dict["name"],
271+
processing_time_seconds=target_dict["processing_time_seconds"],
272+
last_modified_date=last_modified_date,
273+
upload_date=upload_date,
239274
)
240275

241276
def to_dict(self) -> VuMarkTargetDict:
@@ -245,4 +280,7 @@ def to_dict(self) -> VuMarkTargetDict:
245280
return {
246281
"target_id": self.target_id,
247282
"name": self.name,
283+
"processing_time_seconds": float(self.processing_time_seconds),
284+
"last_modified_date": self.last_modified_date.isoformat(),
285+
"upload_date": self.upload_date.isoformat(),
248286
}

0 commit comments

Comments
 (0)