mirror of
https://github.com/milvus-io/milvus.git
synced 2026-07-21 10:15:43 +00:00
test: rewrite scalar expression filtering tests with eval ground truth and bug regression (#48450)
## Summary - Rewrite `test_milvus_client_scalar_filtering.py` (2156→1567 lines) with eval-based ground truth, deterministic boundary values, and comprehensive operator/type coverage - Add `NullValue` sentinel class in `common_func.py` for SQL NULL 3VL semantics (reusable across test files) - 4 focused test classes replacing 1 monolithic class: Correctness, IndexConsistency, CornerCase (bug regression), JSON ## Why The original test had fundamental gaps discovered while analyzing real bugs: - **No boundary values** (INT64_MAX/MIN, 2^53) → missed #48440 (overflow) - **No ground truth** (only self-consistency) → couldn't detect wrong results from all code paths - **Hand-written validators** with incorrect NULL handling → false passes - **No NOT+AND+OR compound coverage** → missed #48441 (3VL bitmap) - **No bool literal / mixed-type IN tests** → missed #48443, #48442 ## What's covered now **Type coverage**: INT8/16/32/64, FLOAT, DOUBLE, BOOL, VARCHAR, JSON, ARRAY(INT8/16/32/64/FLOAT/DOUBLE/BOOL/VARCHAR) **Operator coverage**: `==, !=, >, <, >=, <=, IN, NOT IN, LIKE (12 patterns), IS NULL, IS NOT NULL, +, -, *, /, %, **, array_contains, array_contains_all, array_contains_any, array_length, json path, json_contains` **Compound expressions**: AND, OR, NOT, &&, ||, NOT+AND, NOT+OR, triple nesting, DeMorgan, double NOT, 3-way AND/OR, cross-field, range patterns **Index consistency**: INVERTED, BITMAP, STL_SORT, TRIE — verified with both cross-index comparison AND ground truth **Bug regression (L0)**: #48440 overflow (+,-,*), #48441 3VL NOT+nullable (incl. all-NULL segment), #48442 JSON mixed-type IN precision, #48443 bool literal parser ## Test results (master-20260318-3ec434d) ``` 37 tests: 32 passed, 5 failed (all real Milvus bugs) L0+L1 (19 tests, -n 4): 37 seconds ``` | Failed test | Issue | |---|---| | test_int64_overflow_addition | #48440 | | test_int64_overflow_subtraction | #48440 | | test_3vl_not_all_null_segment | #48441 | | test_bool_literal_in_logical_expr | #48443 | | test_json_mixed_type_in_precision | #48442 | ## Tag distribution - **L0 (7)**: Bug regression — every PR must run - **L1 (12)**: Core type correctness + compound + index consistency - **L2 (18)**: Extended types + all arrays + JSON path/contains issue: #48048 ## Test plan - [x] L0+L1 pass (minus known Milvus bugs) - [x] L2 pass - [x] Eval engine verified: SQL NULL 3VL, NOT propagation, NOT IN, IS NULL/IS NOT NULL - [x] No false passes: parser errors → pytest.fail, skip rate tracking 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: yanliang567 <82361606+yanliang567@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
b1d7b7427a
commit
3af5fe71e3
@@ -49,6 +49,45 @@ except ValueError as e:
|
||||
RNG = None
|
||||
|
||||
|
||||
class NullValue:
|
||||
"""Sentinel for SQL NULL semantics in expression evaluation.
|
||||
All comparisons return False (NULL compared to anything is unknown/falsy).
|
||||
Arithmetic propagates NULL. Python's OR short-circuit handles cases like
|
||||
``int64 == 0 or float == 100`` correctly when float is NULL.
|
||||
"""
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, NullValue):
|
||||
return False
|
||||
return False
|
||||
|
||||
def __ne__(self, other): return False
|
||||
def __lt__(self, other): return False
|
||||
def __le__(self, other): return False
|
||||
def __gt__(self, other): return False
|
||||
def __ge__(self, other): return False
|
||||
def __add__(self, other): return self
|
||||
def __radd__(self, other): return self
|
||||
def __sub__(self, other): return self
|
||||
def __rsub__(self, other): return self
|
||||
def __mul__(self, other): return self
|
||||
def __rmul__(self, other): return self
|
||||
def __truediv__(self, other): return self
|
||||
def __rtruediv__(self, other): return self
|
||||
def __mod__(self, other): return self
|
||||
def __rmod__(self, other): return self
|
||||
def __pow__(self, other): return self
|
||||
def __rpow__(self, other): return self
|
||||
def __neg__(self): return self
|
||||
def __pos__(self): return self
|
||||
def __abs__(self): return self
|
||||
def __hash__(self): return id(self)
|
||||
def __bool__(self): return False
|
||||
def __repr__(self): return "NULL"
|
||||
|
||||
|
||||
SQL_NULL = NullValue()
|
||||
|
||||
|
||||
@singledispatch
|
||||
def to_serializable(val):
|
||||
"""Used by default."""
|
||||
|
||||
+1499
-2059
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user