Commit 8210f32
fix(search): parse RESP3 FT.SEARCH responses with bytes-typed keys (#4109)
* fix(search): parse RESP3 FT.SEARCH responses with bytes-typed keys
Since the wire protocol default switched to RESP3 (#4052), the server
returns FT.SEARCH responses as RESP3 maps. When a client is opened with
``decode_responses=False`` the map keys arrive as ``bytes`` rather than
``str``, but ``Result.from_resp3`` looked them up as plain strings:
instance.total = res.get("total_results", 0)
for result_item in res.get("results", []):
...
Because ``b"total_results" != "total_results"``, every lookup missed and
the search appeared to return ``Result{0 total, docs: []}`` even though
the server had matched documents.
Normalise the top-level map and each per-result map to string keys
before reading them, mirroring the pattern already used by
``_parse_hybrid_search_resp3`` in ``redis/commands/search/commands.py``
("Top-level keys are normalised to strings").
Adds ``tests/test_search_result.py`` with regression tests covering
str-keyed, bytes-keyed, and mixed maps, plus the empty/None edge cases.
The tests fail on the unfixed code for the bytes and mixed cases.
Fixes #4107
* fix(search): extend bytes-key normalisation to AGGREGATE and SPELLCHECK
The RESP3 callbacks for FT.SEARCH (`Result.from_resp3`) were taught to
normalise top-level structural map keys to strings so that responses
parsed correctly on connections opened with `decode_responses=False`.
`_parse_aggregate_resp3` (FT.AGGREGATE / FT.CURSOR READ /
FT.PROFILE AGGREGATE) and `_parse_spellcheck_resp3` (FT.SPELLCHECK)
still read `"total_results"`, `"results"` and `"warning"` as
plain strings, so a byte-keyed RESP3 response missed every lookup and
silently parsed as an empty AggregateResult / `{}` even when the
server had returned data.
Apply the same `str_if_bytes` normalisation that
`Result.from_resp3` and `_parse_hybrid_search_resp3` already use:
- normalise the top-level map and (for aggregate) the per-result-item
map; document data inside `extra_attributes` is left as-is so the
caller still sees bytes when `decode_responses=False`, mirroring the
RESP2 shape;
- normalise the outer `results` key for spellcheck; the inner term keys
match the RESP2 `decode_responses=False` shape and stay as bytes.
Adds regression tests for both parsers in
`tests/test_search_result.py`, plus integration tests in
`tests/test_search.py` that exercise the three affected Search
callbacks (FT.SEARCH, FT.AGGREGATE, FT.SPELLCHECK) against a real
RESP3 wire with a `decode_responses=False` client.
* fix(search): apply petyaslavova review feedback
- _parse_spellcheck_resp3 now preserves the suggestion value as-is so
it keeps the decode_responses shape RESP2 would produce (str when
decoded, bytes otherwise) instead of wrapping bytes in str().
- waitForIndex now accepts both str and bytes structural keys in
FT.INFO responses. execute_command bypasses the search module's
callbacks, so the helper has to handle the raw RESP3 dict/RESP2
list shapes for decode_responses=False clients. This unblocks the
previously failing fixed-clients CI matrix entry.
- The bytes-keys integration tests are now parametrised over
protocol=2 (anchors the legacy output shape) and the default
protocol (the path that actually exercises the changed parsers in
_RedisCallbacksRESP3toRESP2Legacy). Explicit protocol=3 was
routing through _RedisCallbacksRESP3 and bypassing the fix.
- Spellcheck assertion is stricter: it pins the term key to
b"impornant" and the suggestion value to b"important".
- Mirror the suggestion-bytes assertion in the
test_search_result.py unit test.
* test(search): tidy review nits in RESP3 bytes-key tests
- Rephrase the parametrisation comment so it explains *why* the two
protocol arms exist in terms of the parsers being exercised
(_parse_search_resp3 / _parse_aggregate_resp3 /
_parse_spellcheck_resp3) rather than "the changed methods", which
was only meaningful relative to this PR's diff.
- Reorder decorators on TestSearchResp3BytesKeys methods so the
test-scope marks (redismod, fixed_client) stay grouped and
@pytest.mark.parametrize sits last, matching the prevailing style
for parametrised tests.
---------
Co-authored-by: petyaslavova <petya.slavova@redis.com>1 parent 2febde0 commit 8210f32
4 files changed
Lines changed: 405 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
494 | 494 | | |
495 | 495 | | |
496 | 496 | | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
497 | 504 | | |
498 | 505 | | |
499 | 506 | | |
500 | 507 | | |
501 | 508 | | |
| 509 | + | |
502 | 510 | | |
503 | 511 | | |
504 | 512 | | |
| |||
640 | 648 | | |
641 | 649 | | |
642 | 650 | | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
643 | 655 | | |
644 | 656 | | |
645 | 657 | | |
| |||
654 | 666 | | |
655 | 667 | | |
656 | 668 | | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
657 | 672 | | |
658 | | - | |
| 673 | + | |
659 | 674 | | |
660 | 675 | | |
661 | 676 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
111 | 111 | | |
112 | 112 | | |
113 | 113 | | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
114 | 118 | | |
115 | 119 | | |
116 | 120 | | |
117 | 121 | | |
118 | 122 | | |
119 | 123 | | |
| 124 | + | |
120 | 125 | | |
121 | 126 | | |
122 | 127 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
| 46 | + | |
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| |||
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
87 | | - | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
88 | 96 | | |
89 | 97 | | |
90 | 98 | | |
91 | 99 | | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
92 | 105 | | |
93 | | - | |
| 106 | + | |
94 | 107 | | |
95 | | - | |
| 108 | + | |
96 | 109 | | |
97 | 110 | | |
98 | 111 | | |
| |||
5590 | 5603 | | |
5591 | 5604 | | |
5592 | 5605 | | |
| 5606 | + | |
| 5607 | + | |
| 5608 | + | |
| 5609 | + | |
| 5610 | + | |
| 5611 | + | |
| 5612 | + | |
| 5613 | + | |
| 5614 | + | |
| 5615 | + | |
| 5616 | + | |
| 5617 | + | |
| 5618 | + | |
| 5619 | + | |
| 5620 | + | |
| 5621 | + | |
| 5622 | + | |
| 5623 | + | |
| 5624 | + | |
| 5625 | + | |
| 5626 | + | |
| 5627 | + | |
| 5628 | + | |
| 5629 | + | |
| 5630 | + | |
| 5631 | + | |
| 5632 | + | |
| 5633 | + | |
| 5634 | + | |
| 5635 | + | |
| 5636 | + | |
| 5637 | + | |
| 5638 | + | |
| 5639 | + | |
| 5640 | + | |
| 5641 | + | |
| 5642 | + | |
| 5643 | + | |
| 5644 | + | |
| 5645 | + | |
| 5646 | + | |
| 5647 | + | |
| 5648 | + | |
| 5649 | + | |
| 5650 | + | |
| 5651 | + | |
| 5652 | + | |
| 5653 | + | |
| 5654 | + | |
| 5655 | + | |
| 5656 | + | |
| 5657 | + | |
| 5658 | + | |
| 5659 | + | |
| 5660 | + | |
| 5661 | + | |
| 5662 | + | |
| 5663 | + | |
| 5664 | + | |
| 5665 | + | |
| 5666 | + | |
| 5667 | + | |
| 5668 | + | |
| 5669 | + | |
| 5670 | + | |
| 5671 | + | |
| 5672 | + | |
| 5673 | + | |
| 5674 | + | |
| 5675 | + | |
| 5676 | + | |
| 5677 | + | |
| 5678 | + | |
| 5679 | + | |
| 5680 | + | |
| 5681 | + | |
| 5682 | + | |
| 5683 | + | |
| 5684 | + | |
| 5685 | + | |
| 5686 | + | |
| 5687 | + | |
| 5688 | + | |
| 5689 | + | |
| 5690 | + | |
| 5691 | + | |
| 5692 | + | |
| 5693 | + | |
| 5694 | + | |
| 5695 | + | |
| 5696 | + | |
| 5697 | + | |
| 5698 | + | |
| 5699 | + | |
| 5700 | + | |
| 5701 | + | |
| 5702 | + | |
| 5703 | + | |
| 5704 | + | |
| 5705 | + | |
| 5706 | + | |
| 5707 | + | |
| 5708 | + | |
| 5709 | + | |
| 5710 | + | |
| 5711 | + | |
| 5712 | + | |
| 5713 | + | |
| 5714 | + | |
| 5715 | + | |
| 5716 | + | |
| 5717 | + | |
0 commit comments