test(search): pin the geo predicates in the parity suite

This commit is contained in:
Dominik Schmidt committed 2026-09-03 02:06:30 +02:00
1 parent 003323670b
commit 71b4f95172
6 files changed
+76 -3

No files matched your search

+13 -1
View File
@@ -39,6 +39,16 @@ func (e UnsupportedTimeRangeError) Error() string {
return fmt.Sprintf("unable to convert '%v' to a time range", e.Value)
}
// GeoFieldError records a geo predicate that was used on a field that is not
// indexed as a geopoint.
type GeoFieldError struct {
Key string
}
func (e GeoFieldError) Error() string {
return fmt.Sprintf("geo predicate on non-geo field %q", e.Key)
}
// IsValidationError reports whether err is one of the KQL parse/validation
// errors produced by this package, i.e. the query itself is at fault and the
// caller should treat it as a bad request.
@@ -47,9 +57,11 @@ func IsValidationError(err error) bool {
startsWithBinaryOperator *StartsWithBinaryOperatorError
namedGroupInvalidNodes *NamedGroupInvalidNodesError
unsupportedTimeRange *UnsupportedTimeRangeError
geoField *GeoFieldError
)
return errors.As(err, &startsWithBinaryOperator) ||
errors.As(err, &namedGroupInvalidNodes) ||
errors.As(err, &unsupportedTimeRange)
errors.As(err, &unsupportedTimeRange) ||
errors.As(err, &geoField)
}
@@ -20,7 +20,7 @@ import (
func geoQueryField(key string) (string, error) {
field, ok := query.ResolveGeoField(key)
if !ok {
return "", fmt.Errorf("geo predicate on non-geo field %q", key)
return "", &kql.GeoFieldError{Key: key}
}
return field, nil
}
+20
View File
@@ -418,6 +418,26 @@ Fixtures:
| RANGE-07 | `mtime>2021` | no match | no match | no match | ✅ |
| RANGE-08 | `name>100` | no match | no match | no match | ✅ |
### geo
Fixtures:
- `vienna.txt`
- `bruck.txt`
- `berlin.txt`
- `nowhere.txt`
| Case | Query | expected | bleve | OpenSearch | same? |
|---|---|---|---|---|---|
| GEO-01 | `location:geo.distance(48.2082, 16.3738, 5km)` | vienna.txt | vienna.txt | vienna.txt | ✅ |
| GEO-02 | `location:geo.distance(48.2082, 16.3738, 50km)` | bruck.txt, vienna.txt | bruck.txt, vienna.txt | bruck.txt, vienna.txt | ✅ |
| GEO-03 | `location:geo.distance(48.2082, 16.3738, 1m)` | vienna.txt | vienna.txt | vienna.txt | ✅ |
| GEO-04 | `location:geo.bbox(47.9, 16.1, 48.3, 16.5)` | vienna.txt | vienna.txt | vienna.txt | ✅ |
| GEO-05 | `location:geo.bbox(48.3, 16.1, 47.9, 16.5)` | vienna.txt | vienna.txt | vienna.txt | ✅ |
| GEO-06 | `location:geo.polygon(48.3 16.1, 48.3 16.5, 47.9 16.5, 47.9 16.1)` | vienna.txt | vienna.txt | vienna.txt | ✅ |
| GEO-07 | `location:geo.distance(0, 0, 20000km)` | berlin.txt, bruck.txt, vienna.txt | berlin.txt, bruck.txt, vienna.txt | berlin.txt, bruck.txt, vienna.txt | ✅ |
| GEO-08 | `name:geo.distance(48.2082, 16.3738, 5km)` | bad request | bad request | bad request | ✅ |
### scope
Fixtures:
@@ -109,6 +109,7 @@ func queryGroups() []queryGroup {
stressGroup(),
everythingGroup(),
rangeGroup(),
geoGroup(),
scopeGroup(),
invalidGroup(),
}
@@ -0,0 +1,40 @@
package parity
import (
libregraph "github.com/opencloud-eu/libre-graph-api-go"
"github.com/opencloud-eu/opencloud/services/search/pkg/search"
)
func at(lat, lon float64) fixtureOption {
return withLocation(&libregraph.GeoCoordinates{
Latitude: libregraph.PtrFloat64(lat),
Longitude: libregraph.PtrFloat64(lon),
})
}
func geoGroup() queryGroup {
return queryGroup{
name: "geo",
fixtures: []search.Resource{
// vienna, and a second point ~35km east of it
fixtureDoc("vienna.txt", at(48.2082, 16.3738)),
fixtureDoc("bruck.txt", at(48.2082, 16.8500)),
fixtureDoc("berlin.txt", at(52.5200, 13.4050)),
fixtureDoc("nowhere.txt"),
},
cases: []queryCase{
{id: 1, query: `location:geo.distance(48.2082, 16.3738, 5km)`, want: []string{"vienna.txt"}},
{id: 2, query: `location:geo.distance(48.2082, 16.3738, 50km)`, want: []string{"vienna.txt", "bruck.txt"}},
{id: 3, query: `location:geo.distance(48.2082, 16.3738, 1m)`, want: []string{"vienna.txt"}},
{id: 4, query: `location:geo.bbox(47.9, 16.1, 48.3, 16.5)`, want: []string{"vienna.txt"}},
// the corners may come in either order, both name the same box
{id: 5, query: `location:geo.bbox(48.3, 16.1, 47.9, 16.5)`, want: []string{"vienna.txt"}},
{id: 6, query: `location:geo.polygon(48.3 16.1, 48.3 16.5, 47.9 16.5, 47.9 16.1)`, want: []string{"vienna.txt"}},
// a document without a location is never a geo hit
{id: 7, query: `location:geo.distance(0, 0, 20000km)`, want: []string{"vienna.txt", "bruck.txt", "berlin.txt"}},
// geo predicates only apply to geopoint fields, both engines reject the rest
{id: 8, query: `name:geo.distance(48.2082, 16.3738, 5km)`, wantBadRequest: true},
},
}
}
+1 -1
View File
@@ -47,7 +47,7 @@ var bleveEscaper = strings.NewReplacer(
func geoQueryField(key string) (string, error) {
field, ok := searchQuery.ResolveGeoField(key)
if !ok {
return "", fmt.Errorf("geo predicate on non-geo field %q", key)
return "", &kql.GeoFieldError{Key: key}
}
return field, nil
}