You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.rst
+18Lines changed: 18 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,6 +3,24 @@ Changelog
3
3
4
4
.. towncrier release notes start
5
5
6
+
2026.09.08.1
7
+
------------
8
+
9
+
- The URL of a reco counts report now has the shape of the presigned cloud storage URL which real Vuforia returns.
10
+
The report file is named ``{date}-{hour}.csv`` for the current month and ``{month}.csv`` for the previous month, so two requests for the same month in the same hour name the same file and serve the report which the first request generated.
11
+
The URL carries the query parameters of a presigned URL, and the mock honors ``X-Amz-Date`` and ``X-Amz-Expires`` as real Vuforia's storage does, so a URL which is out of date or which has no query parameters gives the ``403`` XML error document which Amazon S3 gives.
12
+
A report which is not yet generated gives the ``404`` ``NoSuchKey`` XML error document which Amazon S3 gives, as real Vuforia has now been observed to do, rather than an empty body.
13
+
14
+
2026.09.08
15
+
----------
16
+
17
+
- The response delay and client timeout simulation is now provided by the ``mock-response-delay`` package.
18
+
19
+
- The mock now returns NGINX's ``400 Request Header Or Cookie Too Large`` response for any request header line longer than 8190 bytes, as real Vuforia does.
20
+
21
+
- Match real Vuforia's request rate limiting, which was checked against it on 2026-09-08.
22
+
``DOCUMENTED_REQUEST_RATE_LIMITS`` now allows two ``GET /targets`` requests per minute rather than one, a rate-limited request gets Envoy's empty-bodied ``429`` response rather than a JSON ``TooManyRequests`` body, and the limits are applied before the request's signature is checked.
Copy file name to clipboardExpand all lines: docs/source/differences-to-vws.rst
+80-31Lines changed: 80 additions & 31 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -184,16 +184,30 @@ endpoints in general, with 45 requests per second for
184
184
``GET /targets/{target_id}``, 10 requests per second for
185
185
``GET /duplicates/{target_id}``, and 1 request per minute for ``GET /targets``.
186
186
187
-
The mock models these limits separately for each group of endpoints, but it applies no limit by default.
188
-
Applying a limit of 1 request per minute to ``GET /targets`` by default would break the tests of anything which uses the mock.
189
-
190
-
.. admonition:: Unverified assumption
191
-
192
-
:ref:`unverified-request-rate-limits`
187
+
The limits were checked against real Vuforia on 2026-09-08, by sending bursts of requests to read-only endpoints:
188
+
189
+
* ``GET /targets`` accepts two requests per minute, not one.
190
+
The window is a fixed clock minute: two requests at 40 seconds past the minute were accepted, a third was rejected, and a request three seconds into the next minute was accepted again.
191
+
* The per-second limits are enforced roughly, not exactly.
192
+
Bursts of 40 concurrent ``GET /summary`` requests saw between 17 and 37 succeed against the documented 15, and a burst of 120 ``GET /targets/{target_id}`` requests saw 74 succeed against the documented 45, so the limiter appears to be spread over more than one instance or window.
193
+
* A limit is keyed on the server access key in the ``Authorization`` header, so one database's burst does not affect another database.
194
+
Vuforia applies the limit before checking the signature, so a request with a bad signature counts towards the limit, and a request over the limit gets a ``429`` response whether or not it is signed correctly.
195
+
Requests without an ``Authorization`` header are not rate limited.
196
+
* A rate-limited request gets a ``429`` (``TOO MANY REQUESTS``) response from Envoy with an empty body, no ``Content-Type`` header and an ``x-envoy-ratelimited: true`` header.
197
+
Vuforia has an Envoy layer at its edge and another in front of the application, and either may reject the request.
198
+
Only a rejection by the inner layer carries an ``x-envoy-upstream-service-time`` header, which the mock always includes.
199
+
The ``TooManyRequests`` result code from Vuforia's result codes table does not appear.
200
+
201
+
The mock returns the empty Envoy response, applies each limit before checking the request's signature, and tracks each limit separately for each database and each group of endpoints.
202
+
The mock's windows are rolling rather than clock-aligned, so two ``GET /targets`` requests block a third until a minute has passed since the first, and the mock enforces the per-second limits exactly.
203
+
The mock only limits requests whose access key belongs to a database, because the limits are configured on the database.
204
+
205
+
The mock applies no limit by default.
206
+
Applying a limit of two requests per minute to ``GET /targets`` by default would break the tests of anything which uses the mock.
193
207
194
208
Set ``request_rate_limits`` to
195
209
:data:`mock_vws.request_rate_limits.DOCUMENTED_REQUEST_RATE_LIMITS` to apply
196
-
the documented limits::
210
+
the limits which real Vuforia applies::
197
211
198
212
from mock_vws import MockVWS
199
213
from mock_vws.database import CloudDatabase
@@ -205,8 +219,8 @@ the documented limits::
205
219
206
220
with MockVWS() as mock:
207
221
mock.add_cloud_database(cloud_database=database)
208
-
# A second ``GET /targets`` request within a minute returns
209
-
# ``TooManyRequests``.
222
+
# A third ``GET /targets`` request within a minute gets a ``429``
223
+
# response.
210
224
...
211
225
212
226
``requests_per_second_limit`` remains available. It applies one limit to all
@@ -457,35 +471,70 @@ As real Vuforia does, the mock returns a 401 response with the
457
471
server keys but which names any other database, including one named by its
458
472
name rather than by its ID.
459
473
460
-
Real Vuforia returns a presigned URL for cloud storage.
461
-
The mock returns a URL served by the mock itself, without the query
462
-
parameters of a presigned URL, so the mock's URL never expires where a real
463
-
one expires after just under seven days.
474
+
Real Vuforia returns a presigned URL for cloud storage, of this form:
Copy file name to clipboardExpand all lines: docs/source/unverified-behavior.rst
+2-27Lines changed: 2 additions & 27 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -38,19 +38,6 @@ The status code and the body shape come from Vuforia's documentation and from th
38
38
A real database with an exhausted request quota would verify this.
39
39
No such response has been seen.
40
40
41
-
.. _unverified-request-rate-limits:
42
-
43
-
Request rate limits
44
-
-------------------
45
-
46
-
:Category: never-attempted
47
-
:API: VWS Target API
48
-
49
-
Vuforia documents a limit of 15 requests per second for VWS endpoints in general, 45 per second for ``GET /targets/{target_id}``, 10 per second for ``GET /duplicates/{target_id}`` and one per minute for ``GET /targets``.
50
-
The mock models the limits separately for each group of endpoints, and applies them only when it is asked to.
51
-
52
-
Sending more than the documented number of requests to a real database, and seeing what it returns, would verify this.
53
-
54
41
.. _unverified-project-suspended:
55
42
56
43
A suspended database
@@ -79,8 +66,9 @@ Additional result codes
79
66
:Category: never-attempted
80
67
:API: VWS Target API
81
68
82
-
``ProjectHasNoApiAccess``, ``TargetQuotaReached`` and ``TooManyRequests`` come from Vuforia's result codes table.
69
+
``ProjectHasNoApiAccess``and ``TargetQuotaReached`` come from Vuforia's result codes table.
83
70
No response from a real database in any of those states has been seen, which is why the mock's ``ProjectHasNoApiAccess`` casing is the table's casing rather than an observed one.
71
+
The table also lists ``TooManyRequests``, but a rate-limited request to a real database gets a ``429`` response with no body at all, so the mock never returns that result code.
84
72
85
73
A database put into each state by the Target Manager portal would verify these.
86
74
@@ -97,19 +85,6 @@ The mock does not implement this, so a user of the mock sees a successful respon
97
85
98
86
A database with more than a million images would verify this, which a test account cannot hold.
99
87
100
-
.. _unverified-reco-counts-report-not-ready:
101
-
102
-
A reco counts report which is not ready
103
-
---------------------------------------
104
-
105
-
:Category: never-attempted
106
-
:API: Reco Counts Report API
107
-
108
-
The URL which the mock returns for a reco counts report gives a 404 response until the report is ready.
109
-
110
-
A request for a real report which caught it before it was generated would verify this.
111
-
Every real report requested so far has been ready by the time it was asked for.
0 commit comments