github.com/go-kivik/kivik/v4@v4.3.2/x/memorydb/find_test.go (about) 1 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 2 // use this file except in compliance with the License. You may obtain a copy of 3 // the License at 4 // 5 // http://www.apache.org/licenses/LICENSE-2.0 6 // 7 // Unless required by applicable law or agreed to in writing, software 8 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 // License for the specific language governing permissions and limitations under 11 // the License. 12 13 package memorydb 14 15 import ( 16 "bytes" 17 "context" 18 "encoding/json" 19 "strings" 20 "testing" 21 22 "gitlab.com/flimzy/testy" 23 24 "github.com/go-kivik/kivik/v4/driver" 25 ) 26 27 func TestIndexSpecUnmarshalJSON(t *testing.T) { 28 type isuTest struct { 29 name string 30 input string 31 expected *indexSpec 32 err string 33 } 34 tests := []isuTest{ 35 { 36 name: "ddoc only", 37 input: `"foo"`, 38 expected: &indexSpec{ddoc: "foo"}, 39 }, 40 { 41 name: "ddoc and index", 42 input: `["foo","bar"]`, 43 expected: &indexSpec{ddoc: "foo", index: "bar"}, 44 }, 45 { 46 name: "invalid json", 47 input: "asdf", 48 err: "invalid character 'a' looking for beginning of value", 49 }, 50 { 51 name: "extra fields", 52 input: `["foo","bar","baz"]`, 53 err: "invalid index specification", 54 }, 55 { 56 name: "One field", 57 input: `["foo"]`, 58 expected: &indexSpec{ddoc: "foo"}, 59 }, 60 { 61 name: "Empty array", 62 input: `[]`, 63 err: "invalid index specification", 64 }, 65 } 66 for _, test := range tests { 67 t.Run(test.name, func(t *testing.T) { 68 result := &indexSpec{} 69 err := result.UnmarshalJSON([]byte(test.input)) 70 var msg string 71 if err != nil { 72 msg = err.Error() 73 } 74 if msg != test.err { 75 t.Errorf("Unexpected error: %s", err) 76 } 77 if err != nil { 78 return 79 } 80 if d := testy.DiffInterface(test.expected, result); d != nil { 81 t.Error(d) 82 } 83 }) 84 } 85 } 86 87 func TestCreateIndex(t *testing.T) { 88 d := &db{} 89 err := d.CreateIndex(context.Background(), "foo", "bar", "baz", nil) 90 if err != errFindNotImplemented { 91 t.Errorf("Unexpected error: %s", err) 92 } 93 } 94 95 func TestGetIndexes(t *testing.T) { 96 d := &db{} 97 _, err := d.GetIndexes(context.Background(), nil) 98 if err != errFindNotImplemented { 99 t.Errorf("Unexpected error: %s", err) 100 } 101 } 102 103 func TestDeleteIndex(t *testing.T) { 104 d := &db{} 105 err := d.DeleteIndex(context.Background(), "foo", "bar", nil) 106 if err != errFindNotImplemented { 107 t.Errorf("Unexpected error: %s", err) 108 } 109 } 110 111 // TestFind tests selectors, to see that the proper doc IDs are returned. 112 func TestFind(t *testing.T) { 113 type findTest struct { 114 name string 115 db *db 116 query interface{} 117 expectedIDs []string 118 err string 119 rowsErr string 120 } 121 tests := []findTest{ 122 { 123 name: "invalid query", 124 query: make(chan int), 125 err: "json: unsupported type: chan int", 126 }, 127 { 128 name: "Invalid JSON query", 129 query: "asdf", 130 err: "invalid character 'a' looking for beginning of value", 131 }, 132 { 133 name: "No query", 134 err: "Missing required key: selector", 135 }, 136 { 137 name: "empty selector", 138 query: `{"selector":{}}`, 139 db: func() *db { 140 db := setupDB(t) 141 for _, id := range []string{"a", "c", "z", "q", "chicken"} { 142 if _, err := db.Put(context.Background(), id, map[string]string{"value": id}, nil); err != nil { 143 t.Fatal(err) 144 } 145 } 146 return db 147 }(), 148 expectedIDs: []string{"a", "c", "chicken", "q", "z"}, 149 }, 150 { 151 name: "simple selector", 152 query: `{"selector":{"value":"chicken"}}`, 153 db: func() *db { 154 db := setupDB(t) 155 for _, id := range []string{"a", "c", "z", "q", "chicken"} { 156 if _, err := db.Put(context.Background(), id, map[string]string{"value": id}, nil); err != nil { 157 t.Fatal(err) 158 } 159 } 160 return db 161 }(), 162 expectedIDs: []string{"chicken"}, 163 }, 164 } 165 for _, test := range tests { 166 t.Run(test.name, func(t *testing.T) { 167 db := test.db 168 if db == nil { 169 db = setupDB(t) 170 } 171 rows, err := db.Find(context.Background(), test.query, nil) 172 var msg string 173 if err != nil { 174 msg = err.Error() 175 } 176 if msg != test.err { 177 t.Errorf("Unexpected error: %s", err) 178 } 179 if err != nil { 180 return 181 } 182 checkRows(t, rows, test.expectedIDs, test.rowsErr) 183 }) 184 } 185 } 186 187 // TestFindDoc is the same as Testfind, but assumes only a single result 188 // (ignores any others), and compares the entire document. 189 func TestFindDoc(t *testing.T) { 190 type fdTest struct { 191 name string 192 db *db 193 query interface{} 194 expected interface{} 195 } 196 tests := []fdTest{ 197 { 198 name: "simple selector", 199 query: `{"selector":{}}`, 200 db: func() *db { 201 db := setupDB(t) 202 id := "chicken" 203 if _, err := db.Put(context.Background(), id, map[string]string{"value": id}, nil); err != nil { 204 t.Fatal(err) 205 } 206 return db 207 }(), 208 expected: map[string]interface{}{ 209 "_id": "chicken", 210 "_rev": "1-xxx", 211 "value": "chicken", 212 }, 213 }, 214 { 215 name: "fields", 216 query: `{"selector":{}, "fields":["value","_rev"]}`, 217 db: func() *db { 218 db := setupDB(t) 219 if _, err := db.Put(context.Background(), "foo", map[string]string{"value": "foo"}, nil); err != nil { 220 t.Fatal(err) 221 } 222 return db 223 }(), 224 expected: map[string]interface{}{ 225 "value": "foo", 226 "_rev": "1-xxx", 227 }, 228 }, 229 } 230 for _, test := range tests { 231 t.Run(test.name, func(t *testing.T) { 232 db := test.db 233 if db == nil { 234 db = setupDB(t) 235 } 236 rows, err := db.Find(context.Background(), test.query, nil) 237 if err != nil { 238 t.Fatal(err) 239 } 240 var row driver.Row 241 if e := rows.Next(&row); e != nil { 242 t.Fatal(e) 243 } 244 _ = rows.Close() 245 var result map[string]interface{} 246 if e := json.NewDecoder(row.Doc).Decode(&result); e != nil { 247 t.Fatal(e) 248 } 249 parts := strings.Split(result["_rev"].(string), "-") 250 result["_rev"] = parts[0] + "-xxx" 251 if d := testy.DiffAsJSON(test.expected, result); d != nil { 252 t.Error(d) 253 } 254 }) 255 } 256 } 257 258 func TestResultWarning(t *testing.T) { 259 rows := &findResults{} 260 expected := "no matching index found, create an index to optimize query time" 261 if w := rows.Warning(); w != expected { 262 t.Errorf("Unexpected warning: %s", w) 263 } 264 } 265 266 func TestFilterDoc(t *testing.T) { 267 type fdTest struct { 268 name string 269 rows *findResults 270 data string 271 expected string 272 err string 273 } 274 tests := []fdTest{ 275 { 276 name: "no filter", 277 rows: &findResults{}, 278 data: `{"foo":"bar"}`, 279 expected: `{"foo":"bar"}`, 280 }, 281 { 282 name: "with filter", 283 rows: &findResults{fields: map[string]struct{}{"foo": {}}}, 284 data: `{"foo":"bar", "baz":"qux"}`, 285 expected: `{"foo":"bar"}`, 286 }, 287 { 288 name: "invalid json", 289 rows: &findResults{fields: map[string]struct{}{"foo": {}}}, 290 data: `{"foo":"bar", "baz":"qux}`, 291 err: "unexpected end of JSON input", 292 }, 293 } 294 for _, test := range tests { 295 t.Run(test.name, func(t *testing.T) { 296 result, err := test.rows.filterDoc([]byte(test.data)) 297 var msg string 298 if err != nil { 299 msg = err.Error() 300 } 301 if msg != test.err { 302 t.Errorf("Unexpected error: %s", msg) 303 } 304 if err != nil { 305 return 306 } 307 if d := testy.DiffJSON([]byte(test.expected), result); d != nil { 308 t.Error(d) 309 } 310 }) 311 } 312 } 313 314 func TestToJSON(t *testing.T) { 315 type tjTest struct { 316 Name string 317 Input interface{} 318 Expected string 319 } 320 tests := []tjTest{ 321 { 322 Name: "Null", 323 Expected: "null", 324 }, 325 { 326 Name: "String", 327 Input: `{"foo":"bar"}`, 328 Expected: `{"foo":"bar"}`, 329 }, 330 { 331 Name: "ByteSlice", 332 Input: []byte(`{"foo":"bar"}`), 333 Expected: `{"foo":"bar"}`, 334 }, 335 { 336 Name: "RawMessage", 337 Input: json.RawMessage(`{"foo":"bar"}`), 338 Expected: `{"foo":"bar"}`, 339 }, 340 { 341 Name: "Interface", 342 Input: map[string]string{"foo": "bar"}, 343 Expected: `{"foo":"bar"}`, 344 }, 345 } 346 for _, test := range tests { 347 t.Run(test.Name, func(t *testing.T) { 348 r, err := toJSON(test.Input) 349 if err != nil { 350 t.Fatalf("jsonify failed: %s", err) 351 } 352 buf := &bytes.Buffer{} 353 _, _ = buf.ReadFrom(r) 354 result := strings.TrimSpace(buf.String()) 355 if result != test.Expected { 356 t.Errorf("Expected: `%s`\n Actual: `%s`", test.Expected, result) 357 } 358 }) 359 } 360 }