Skip to content

fix(favorite): follow the three-valued addUrl contract - #21

Merged
marevol merged 2 commits into
mainfrom
fix/favorite-result-current-api
Sep 13, 2026
Merged

marevol merged 2 commits into
mainfrom
fix/favorite-result-current-api

Conversation

@marevol

@marevol marevol commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

The fix from #19, built on the OpenSearch packages Fess uses today, so it can be merged ahead of the OpenSearch fork migration.

main does not compile against the current Fess 15.9.0-SNAPSHOT: FavoriteLogService.addUrl returns the three-valued FavoriteResult since codelibs/fess#3391, so if (!addUrl(...)) in JsonApiManager#processFavoriteRequest is no longer valid Java, and every PR on this repository fails CI until that is fixed.

#19 fixes it, but its new test imports org.codelibs.fesen.opensearch.action.update.UpdateRequestBuilder, which exists only once codelibs/fess#3439 relocates OpenSearch, so its test compile fails today. This branch carries #19's two commits unchanged except for that one import, which is now org.opensearch.action.update.UpdateRequestBuilder, the type SearchHelper#update takes in current Fess. The production change is identical to #19; switching the import to the relocated package belongs with the fork migration.

What the fix does (from #19)

addUrl result behaviour, matching Fess core's v2 FavoritePostHandler
ADDED bump favorite_count, report status 0
ALREADY_ADDED status 0, favorite_count is not bumped
NO_SUCH_USER the documented error (status 4), no bump

Testing

FavoriteLogService.addUrl used to return a boolean and now returns a
FavoriteResult (ADDED / ALREADY_ADDED / NO_SUCH_USER), so `!addUrl(...)` no
longer compiles. This module has not built since that change, independently of
anything else.

The old false meant exactly one thing -- the user code resolved to no user and
nothing was written -- so NO_SUCH_USER keeps raising the same error. The new
outcome is ALREADY_ADDED: re-adding a URL the user already marked is an
idempotent success, and the favorite_count bump is skipped for it. Bumping on a
repeat is what the upstream change set out to stop, because favorite_count is a
documented sort key and a double click or a client retry would otherwise move a
document up the ranking without anyone else favoriting it. This mirrors how
Fess's own v2 FavoritePostHandler branches on the same enum.

No test covers this path in this module; the behaviour is verified only by
matching the core handler.
The switch from a boolean addUrl to the three-valued FavoriteResult changed
behaviour as well as the signature, and nothing in this module held that
behaviour in place: the choice was justified only by matching Fess core's v2
FavoritePostHandler, which is not something a build can check.

JsonApiManagerFavoriteTest pins all three outcomes against what core does. ADDED
bumps favorite_count and reports status 0. ALREADY_ADDED reports the same status
0 but must not bump, because favorite_count is a documented sort key and a
repeat would otherwise let one user push a document up the ranking by clicking
twice; a separate case runs the request twice and asserts the count is bumped
once. NO_SUCH_USER keeps reporting status 4 with "Failed to add url", the error
the old false produced, and bumps nothing.

The bump is searchHelper.update(id, lambda), so it is asserted as whether update
was called and for which document id. A recording SearchHelper captures the call
without running the lambda, which would need a live search engine client. One
further case applies the lambda addUrl is handed and checks the log entry it
populates, so an empty lambda could not pass. Capture happens at
writeJsonResponse(int, String, String) so the real error shaping in the
Throwable overload still runs and the asserted message is the one a caller sees.

Both branches were mutation-checked: widening the ADDED guard to
"not NO_SUCH_USER" fails the two count cases, and removing the NO_SUCH_USER
guard fails the error case.

Registration happens before super.setUp because the container's own
jsonApiManager resolves webApiManagerFactory from a @PostConstruct, and the stub
FessConfig answers each index-field key directly because FessConfig.SimpleImpl
throws NullPointerException from any properties-backed getter without a
container this test does not start.

Tests run: 75 before, 80 after.
@marevol marevol added this to the 15.9.0 milestone Sep 13, 2026
@marevol
marevol merged commit eb379db into main Sep 13, 2026
3 checks passed
@marevol marevol self-assigned this Sep 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant