Follow-up to #3343, which adds POST /imagetargets/databases/{database_id}/reports/recoCounts. That report is necessarily header-only, because the mock has no way to have any recognitions to report. This issue proposes fixing that gap properly.
What the mock does today
Recognition counts exist as fields but are inert:
CloudDatabase has current_month_recos, previous_month_recos, total_recos and reco_threshold (src/mock_vws/database.py). They are keyword-only dataclass fields, so they can be set when constructing a database.
ImageTarget has current_month_recos, previous_month_recos and total_recos (src/mock_vws/target.py).
- Nothing ever changes any of them.
_query_tools.py matches targets without touching recognition counts.
There are two concrete holes in that:
- The database fields do not survive the Flask/Docker backend. They are absent from
CloudDatabaseDict, to_dict and from_dict. A user who passes total_recos=500 to CloudDatabase gets it in-process and silently loses it through the Flask backend, so the same test gives different answers on different backends.
- The target fields cannot be set at all. They are absent from
ImageTargetDict, to_dict and from_dict, and ImageTarget objects are only ever constructed inside add_target, so no public API reaches them. GET /summary/{target_id} and the new reco counts CSV can therefore only ever report zero per target.
Neither the database nor the target reco fields are mentioned in the class docstrings, so even the part that does work is undiscoverable.
Why not just count recognitions on query?
This is the obvious fix and it is the wrong one.
Real Vuforia's recognition counts lag by a long time — long enough that they do not move within a test run. Two tests assert this against the real service, not just the mock:
tests/mock_vws/test_target_summary.py::TestRecognitionCounts::test_recognition performs a query and then asserts all three target counts are still 0. It runs under verify_mock_vuforia, so it passes against real Vuforia.
tests/mock_vws/test_database_summary.py::TestRecos was relaxed in 2031caf ("Account for recos now being non-zero", March 2020) to assert only that the counts are integers which do not change between two quick requests, precisely because the real values are delayed.
So incrementing a counter when a query matches would make the mock less faithful for the interaction users actually write tests around: add a target, query it, read a summary. Users who assert total_recos == 0 after a query — matching real Vuforia — would start failing.
Proposal: seedable, not automatic
Let users state the recognition counts they want, and leave the mock's default behaviour exactly as it is now.
- Round-trip the existing
CloudDatabase reco fields through CloudDatabaseDict / to_dict / from_dict, so the in-process and Flask/Docker backends agree. Add reco_threshold too, which has the same problem.
- Round-trip the
ImageTarget reco fields through ImageTargetDict / to_dict / from_dict.
- Give users a way to set recognition counts on a target, which today has no entry point at all. Targets are created by API calls, so this has to be post-creation — something like a
MockVWS method taking a target ID and the three counts, mirrored by a target manager route for the Flask backend (the existing PUT /cloud_databases/<name>/targets/<target_id> route is the natural home).
- Have the reco counts CSV report derive its rows from the per-target counts for the requested month: one row per target whose count for that month is non-zero, with
target_id and reco_count. current_month_recos and previous_month_recos map onto the two months the endpoint accepts, so seeded targets produce a real report body.
- Document the fields in the
CloudDatabase and ImageTarget docstrings and in differences-to-vws.rst, replacing the current bare "The mock does not count recognitions" with the reason (real counts are delayed past the length of a test) and the seeding recipe.
Optionally, and only if wanted: a MockVWS flag to opt into incrementing counts on matching queries, off by default. This would be for users who want to exercise "counts went up" code paths and accept that real Vuforia will not behave that way within a test. I would not do this without a user asking for it.
Acceptance criteria
CloudDatabase and ImageTarget recognition counts and reco_threshold round-trip through to_dict / from_dict, so the in-process and Flask/Docker backends return identical summaries for the same seeded values.
- Recognition counts can be set on a target through a public API on both backends.
GET /summary, GET /summary/{target_id} and the reco counts CSV all reflect seeded values.
- The reco counts CSV contains one row per target with a non-zero count for the requested month.
- Default behaviour is unchanged: with nothing seeded, every count is
0 and the CSV is header-only, so the existing verified tests keep passing against real Vuforia.
- Verified fake tests cover seeded and unseeded cases on both mock backends. The seeded cases cannot run against real Vuforia and should be marked mock-only, with the reason recorded in
differences-to-vws.rst alongside the other mock-only paths.
Follow-up to #3343, which adds
POST /imagetargets/databases/{database_id}/reports/recoCounts. That report is necessarily header-only, because the mock has no way to have any recognitions to report. This issue proposes fixing that gap properly.What the mock does today
Recognition counts exist as fields but are inert:
CloudDatabasehascurrent_month_recos,previous_month_recos,total_recosandreco_threshold(src/mock_vws/database.py). They are keyword-only dataclass fields, so they can be set when constructing a database.ImageTargethascurrent_month_recos,previous_month_recosandtotal_recos(src/mock_vws/target.py)._query_tools.pymatches targets without touching recognition counts.There are two concrete holes in that:
CloudDatabaseDict,to_dictandfrom_dict. A user who passestotal_recos=500toCloudDatabasegets it in-process and silently loses it through the Flask backend, so the same test gives different answers on different backends.ImageTargetDict,to_dictandfrom_dict, andImageTargetobjects are only ever constructed insideadd_target, so no public API reaches them.GET /summary/{target_id}and the new reco counts CSV can therefore only ever report zero per target.Neither the database nor the target reco fields are mentioned in the class docstrings, so even the part that does work is undiscoverable.
Why not just count recognitions on query?
This is the obvious fix and it is the wrong one.
Real Vuforia's recognition counts lag by a long time — long enough that they do not move within a test run. Two tests assert this against the real service, not just the mock:
tests/mock_vws/test_target_summary.py::TestRecognitionCounts::test_recognitionperforms a query and then asserts all three target counts are still0. It runs underverify_mock_vuforia, so it passes against real Vuforia.tests/mock_vws/test_database_summary.py::TestRecoswas relaxed in 2031caf ("Account for recos now being non-zero", March 2020) to assert only that the counts are integers which do not change between two quick requests, precisely because the real values are delayed.So incrementing a counter when a query matches would make the mock less faithful for the interaction users actually write tests around: add a target, query it, read a summary. Users who assert
total_recos == 0after a query — matching real Vuforia — would start failing.Proposal: seedable, not automatic
Let users state the recognition counts they want, and leave the mock's default behaviour exactly as it is now.
CloudDatabasereco fields throughCloudDatabaseDict/to_dict/from_dict, so the in-process and Flask/Docker backends agree. Addreco_thresholdtoo, which has the same problem.ImageTargetreco fields throughImageTargetDict/to_dict/from_dict.MockVWSmethod taking a target ID and the three counts, mirrored by a target manager route for the Flask backend (the existingPUT /cloud_databases/<name>/targets/<target_id>route is the natural home).target_idandreco_count.current_month_recosandprevious_month_recosmap onto the two months the endpoint accepts, so seeded targets produce a real report body.CloudDatabaseandImageTargetdocstrings and indifferences-to-vws.rst, replacing the current bare "The mock does not count recognitions" with the reason (real counts are delayed past the length of a test) and the seeding recipe.Optionally, and only if wanted: a
MockVWSflag to opt into incrementing counts on matching queries, off by default. This would be for users who want to exercise "counts went up" code paths and accept that real Vuforia will not behave that way within a test. I would not do this without a user asking for it.Acceptance criteria
CloudDatabaseandImageTargetrecognition counts andreco_thresholdround-trip throughto_dict/from_dict, so the in-process and Flask/Docker backends return identical summaries for the same seeded values.GET /summary,GET /summary/{target_id}and the reco counts CSV all reflect seeded values.0and the CSV is header-only, so the existing verified tests keep passing against real Vuforia.differences-to-vws.rstalongside the other mock-only paths.