eintopf.info@v0.13.16/service/search/aggregation_test.go (about) 1 // Copyright (C) 2022 The Eintopf authors 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <https://www.gnu.org/licenses/>. 15 16 package search 17 18 import ( 19 "reflect" 20 "testing" 21 "time" 22 ) 23 24 type aggregatorTestcase struct { 25 name string 26 values []interface{} 27 wantError string 28 wantBucket Bucket 29 } 30 31 func TestTermsAggregator(t *testing.T) { 32 testcases := []aggregatorTestcase{ 33 { 34 name: "InvalidType", 35 values: []interface{}{2}, 36 wantError: "invalid type: int", 37 }, { 38 name: "TypeString", 39 values: []interface{}{"a"}, 40 wantBucket: TermsBucket{Term{Term: "a", Count: 1}}, 41 }, { 42 name: "Type[]string", 43 values: []interface{}{[]string{"a"}}, 44 wantBucket: TermsBucket{Term{Term: "a", Count: 1}}, 45 }, { 46 name: "Type[]interface{}", 47 values: []interface{}{[]interface{}{"a"}}, 48 wantBucket: TermsBucket{Term{Term: "a", Count: 1}}, 49 }, { 50 name: "IncreasesCount", 51 values: []interface{}{"a", "a", "b"}, 52 wantBucket: TermsBucket{ 53 Term{Term: "a", Count: 2}, 54 Term{Term: "b", Count: 1}, 55 }, 56 }, 57 } 58 testAggregator(t, testcases, func() aggregator { 59 return &termsAggregator{make(map[string]int)} 60 }) 61 } 62 63 func TestDateAggregator(t *testing.T) { 64 time1 := time.Date(2019, 1, 12, 20, 0, 0, 0, time.UTC) 65 time2 := time.Date(2019, 2, 12, 20, 0, 0, 0, time.UTC) 66 time3 := time.Date(2019, 7, 12, 20, 0, 0, 0, time.UTC) 67 testcases := []aggregatorTestcase{ 68 { 69 name: "InvalidType", 70 values: []interface{}{2}, 71 wantError: "invalid type: int", 72 }, { 73 name: "InvalidDate", 74 values: []interface{}{"a"}, 75 wantError: `invalid date format: parsing time "a" as "2006-01-02T15:04:05Z07:00": cannot parse "a" as "2006"`, 76 }, { 77 name: "2Dates", 78 values: []interface{}{ 79 time1.Format(DateLayout), 80 time2.Format(DateLayout), 81 }, 82 wantBucket: DateRangeBucket{ 83 Min: time1, 84 Max: time2, 85 }, 86 }, { 87 name: "3Dates", 88 values: []interface{}{ 89 time2.Format(DateLayout), 90 time3.Format(DateLayout), 91 time1.Format(DateLayout), 92 }, 93 wantBucket: DateRangeBucket{ 94 Min: time1, 95 Max: time3, 96 }, 97 }, 98 } 99 100 testAggregator(t, testcases, func() aggregator { 101 return &dateRangeAggregator{ 102 min: time.Date(9999, 0, 0, 0, 0, 0, 0, time.UTC), 103 max: time.Date(0, 0, 0, 0, 0, 0, 0, time.UTC), 104 } 105 }) 106 } 107 108 func testAggregator(t *testing.T, testcases []aggregatorTestcase, newAggregator func() aggregator) { 109 t.Helper() 110 111 for _, tc := range testcases { 112 t.Run(tc.name, func(tt *testing.T) { 113 aggregator := newAggregator() 114 for _, v := range tc.values { 115 err := aggregator.aggregate(v) 116 if tc.wantError != "" { 117 if err.Error() != tc.wantError { 118 tt.Fatalf("aggregator.aggregate(%v): error doesn't match:\nwant: %s\ngot: %s", v, tc.wantError, err.Error()) 119 } 120 return 121 } 122 if err != nil { 123 tt.Fatalf("aggregator.aggregate(%v): failed unexpectedly: %s", v, err.Error()) 124 } 125 } 126 127 bucket := aggregator.bucket() 128 if !reflect.DeepEqual(bucket, tc.wantBucket) { 129 tt.Fatalf("bucket doesn't match:\nwant: %v\ngot: %v", tc.wantBucket, bucket) 130 } 131 }) 132 } 133 } 134 135 func TestAggregationCacheKey(t *testing.T) { 136 for _, tc := range []struct { 137 a1 Aggregation 138 a2 Aggregation 139 wantEqual bool 140 }{ 141 { 142 a1: Aggregation{ 143 Type: TermsAggregation, 144 Field: "foo", 145 Filters: []Filter{ 146 &TermsFilter{Field: "bar", Terms: []string{"a", "b"}}, 147 &DateRangeFilter{Field: "baz", Min: time.Unix(1000000, 0), Max: time.Unix(1000, 0)}, 148 }, 149 }, 150 a2: Aggregation{ 151 Type: TermsAggregation, 152 Field: "foo", 153 Filters: []Filter{ 154 &TermsFilter{Field: "bar", Terms: []string{"a", "b"}}, 155 &DateRangeFilter{Field: "baz", Min: time.Unix(1000000, 0), Max: time.Unix(1000, 0)}, 156 }, 157 }, 158 wantEqual: true, 159 }, { 160 a1: Aggregation{Type: TermsAggregation}, 161 a2: Aggregation{Type: DateRangeAggregation}, 162 wantEqual: false, 163 }, { 164 a1: Aggregation{Field: "foo"}, 165 a2: Aggregation{Field: "bar"}, 166 wantEqual: false, 167 }, { 168 a1: Aggregation{Filters: []Filter{&TermsFilter{Field: "foo"}}}, 169 a2: Aggregation{Filters: []Filter{&TermsFilter{Field: "bar"}}}, 170 wantEqual: false, 171 }, 172 } { 173 c1 := tc.a1.CacheKey() 174 c2 := tc.a2.CacheKey() 175 176 if tc.wantEqual && c1 != c2 { 177 t.Errorf("cache keys are unequal: %v == %v: %s != %s", tc.a1, tc.a2, c1, c2) 178 } 179 if !tc.wantEqual && c1 == c2 { 180 t.Errorf("cache keys are equal: %v != %v: %s == %s", tc.a1, tc.a2, c1, c2) 181 } 182 } 183 }