8000 kivik/find_test.go at master · dominicbarnes/kivik · GitHub
[go: up one dir, main page]

Skip to content

Latest commit

 

History

History
489 lines (474 loc) · 11 KB

find_test.go

File metadata and controls

489 lines (474 loc) · 11 KB
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
package kivik
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"testing"
"gitlab.com/flimzy/testy"
"github.com/go-kivik/kivik/v4/driver"
internal "github.com/go-kivik/kivik/v4/int/errors"
"github.com/go-kivik/kivik/v4/int/mock"
)
func TestFind(t *testing.T) {
tests := []struct {
name string
db *DB
query interface{}
options []Option
expected *ResultSet
status int
err string
}{
{
name: "non-finder",
db: &DB{
client: &Client{},
driverDB: &mock.DB{},
},
status: http.StatusNotImplemented,
err: "kivik: driver does not support Find interface",
},
{
name: "db error",
db: &DB{
client: &Client{},
driverDB: &mock.Finder{
FindFunc: func(context.Context, interface{}, driver.Options) (driver.Rows, error) {
return nil, errors.New("db error")
},
},
},
status: http.StatusInternalServerError,
err: "db error",
},
{
name: "success",
db: &DB{
client: &Client{},
driverDB: &mock.Finder{
FindFunc: func(_ context.Context, query interface{}, _ driver.Options) (driver.Rows, error) {
expectedQuery := json.RawMessage(`{"limit":3,"selector":{"foo":"bar"},"skip":10}`)
if d := testy.DiffInterface(expectedQuery, query); d != nil {
return nil, fmt.Errorf("Unexpected query:\n%s", d)
}
return &mock.Rows{ID: "a"}, nil
},
},
},
query: map[string]interface{}{"selector": map[string]interface{}{"foo": "bar"}},
options: []Option{
Param("limit", 3),
Param("skip", 10),
},
expected: &ResultSet{
iter: &iter{
feed: &rowsIterator{
Rows: &mock.Rows{ID: "a"},
},
curVal: &driver.Row{},
},
rowsi: &mock.Rows{ID: "a"},
},
},
{
name: "db error",
db: &DB{
err: errors.New("db error"),
},
status: http.StatusInternalServerError,
err: "db error",
},
{
name: "client closed",
db: &DB{
client: &Client{
closed: true,
},
driverDB: &mock.Finder{},
},
status: http.StatusServiceUnavailable,
err: "kivik: client closed",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
rs := test.db.Find(context.Background(), test.query, test.options...)
err := rs.Err()
if d := internal.StatusErrorDiff(test.err, test.status, err); d != "" {
t.Error(d)
}
if err != nil {
return
}
rs.cancel = nil // Determinism
rs. // Determinism
if d := testy.DiffInterface(test.expected, rs); d != nil {
t.Error(d)
}
})
}
t.Run("standalone", func(t *testing.T) {
t.Run("after err, close doesn't block", func(t *testing.T) {
db := &DB{
client: &Client{},
driverDB: &mock.Finder{
FindFunc: func(context.Context, interface{}, driver.Options) (driver.Rows, error) {
return nil, errors.New("sdfsdf")
},
},
}
rows := db.Find(context.Background(), nil)
if err := rows.Err(); err == nil {
t.Fatal("expected an error, got none")
}
_ = db.Close() // Should not block
})
t.Run("not finder, close doesn't block", func(t *testing.T) {
db := &DB{
client: &Client{},
driverDB: &mock.DB{},
}
rows := db.Find(context.Background(), nil)
if err := rows.Err(); err == nil {
t.Fatal("expected an error, got none")
}
_ = db.Close() // Should not block
})
})
}
func TestCreateIndex(t *testing.T) {
tests := []struct {
testName string
db *DB
ddoc, name string
index interface{}
status int
err string
}{
{
testName: "non-finder",
db: &DB{
client: &Client{},
driverDB: &mock.DB{},
},
status: http.StatusNotImplemented,
err: "kivik: driver does not support Find interface",
},
{
testName: "db error",
db: &DB{
client: &Client{},
driverDB: &mock.Finder{
CreateIndexFunc: func(context.Context, string, string, interface{}, driver.Options) error {
return errors.New("db error")
},
},
},
status: http.StatusInternalServerError,
err: "db error",
},
{
testName: "success",
db: &DB{
client: &Client{},
driverDB: &mock.Finder{
CreateIndexFunc: func(_ context.Context, ddoc, name string, index interface{}, _ driver.Options) error {
expectedDdoc := "foo"
expectedName := "bar"
expectedIndex := int(3)
if expectedDdoc != ddoc {
return fmt.Errorf("Unexpected ddoc: %s", ddoc)
}
if expectedName != name {
return fmt.Errorf("Unexpected name: %s", name)
}
if d := testy.DiffInterface(expectedIndex, index); d != nil {
return fmt.Errorf("Unexpected index:\n%s", d)
}
return nil
},
},
},
ddoc: "foo",
name: "bar",
index: int(3),
},
{
name: "closed",
db: &DB{
client: &Client{
closed: true,
},
},
status: http.StatusServiceUnavailable,
err: "kivik: client closed",
},
{
name: "db error",
db: &DB{
client: &Client{},
err: errors.New("db error"),
},
status: http.StatusInternalServerError,
err: "db error",
},
}
for _, test := range tests {
t.Run(test.testName, func(t *testing.T) {
err := test.db.CreateIndex(context.Background(), test.ddoc, test.name, test.index)
if d := internal.StatusErrorDiff(test.err, test.status, err); d != "" {
t.Error(d)
}
})
}
}
func TestDeleteIndex(t *testing.T) {
tests := []struct {
testName string
db *DB
ddoc, name string
status int
err string
}{
{
testName: "non-finder",
db: &DB{
client: &Client{},
driverDB: &mock.DB{},
},
status: http.StatusNotImplemented,
err: "kivik: driver does not support Find interface",
},
{
testName: "db error",
db: &DB{
client: &Client{},
driverDB: &mock.Finder{
DeleteIndexFunc: func(context.Context, string, string, driver.Options) error {
return errors.New("db error")
},
},
},
status: http.StatusInternalServerError,
err: "db error",
},
{
testName: "success",
db: &DB{
client: &Client{},
driverDB: &mock.Finder{
DeleteIndexFunc: func(_ context.Context, ddoc, name string, _ driver.Options) error {
expectedDdoc := "foo"
expectedName := "bar"
if expectedDdoc != ddoc {
return fmt.Errorf("Unexpected ddoc: %s", ddoc)
}
if expectedName != name {
return fmt.Errorf("Unexpected name: %s", name)
}
return nil
},
},
},
ddoc: "foo",
name: "bar",
},
{
testName: "client closed",
db: &DB{
client: &Client{
closed: true,
},
},
status: http.StatusServiceUnavailable,
err: "kivik: client closed",
},
{
testName: "db error",
db: &DB{
err: errors.New("db error"),
},
status: http.StatusInternalServerError,
err: "db error",
},
}
for _, test := range tests {
t.Run(test.testName, func(t *testing.T) {
err := test.db.DeleteIndex(context.Background(), test.ddoc, test.name)
if d := internal.StatusErrorDiff(test.err, test.status, err); d != "" {
t.Error(d)
}
})
}
}
func TestGetIndexes(t *testing.T) {
tests := []struct {
testName string
db *DB
expected []Index
status int
err string
}{
{
testName: "non-finder",
db: &DB{
client: &Client{},
driverDB: &mock.DB{},
},
status: http.StatusNotImplemented,
err: "kivik: driver does not support Find interface",
},
{
testName: "db error",
db: &DB{
client: &Client{},
driverDB: &mock.Finder{
GetIndexesFunc: func(context.Context, driver.Options) ([]driver.Index, error) {
return nil, errors.New("db error")
},
},
},
status: http.StatusInternalServerError,
err: "db error",
},
{
testName: "success",
db: &DB{
client: &Client{},
driverDB: &mock.Finder{
GetIndexesFunc: func(context.Context, driver.Options) ([]driver.Index, error) {
return []driver.Index{
{Name: "a"},
{Name: "b"},
}, nil
},
},
},
expected: []Index{
{
Name: "a",
},
{
Name: "b",
},
},
},
{
testName: "client closed",
db: &DB{
client: &Client{
closed: true,
},
},
status: http.StatusServiceUnavailable,
err: "kivik: client closed",
},
{
testName: "db error",
db: &DB{
err: errors.New("db error"),
},
status: http.StatusInternalServerError,
err: "db error",
},
}
for _, test := range tests {
t.Run(test.testName, func(t *testing.T) {
result, err := test.db.GetIndexes(context.Background())
if d := internal.StatusErrorDiff(test.err, test.status, err); d != "" {
t.Error(d)
}
if err != nil {
return
}
if d := testy.DiffInterface(test.expected, result); d != nil {
t.Error(d)
}
})
}
}
func TestExplain(t *testing.T) {
type tt struct {
db *DB
query interface{}
expected *QueryPlan
status int
err string
}
tests := testy.NewTable()
tests.Add("non-finder", tt{
db: &DB{
client: &Client{},
driverDB: &mock.DB{},
},
status: http.StatusNotImplemented,
err: "kivik: driver does not support Find interface",
})
tests.Add("explain error", tt{
db: &DB{
client: &Client{},
driverDB: &mock.Finder{
ExplainFunc: func(context.Context, interface{}, driver.Options) (*driver.QueryPlan, error) {
return nil, errors.New("explain error")
},
},
},
status: http.StatusInternalServerError,
err: "explain error",
})
tests.Add("success", tt{
db: &DB{
client: &Client{},
driverDB: &mock.Finder{
ExplainFunc: func(_ context.Context, query interface{}, _ driver.Options) (*driver.QueryPlan, error) {
expectedQuery := int(3)
if d := testy.DiffInterface(expectedQuery, query); d != nil {
return nil, fmt.Errorf("Unexpected query:\n%s", d)
}
return &driver.QueryPlan{DBName: "foo"}, nil
},
},
},
query: int(3),
expected: &QueryPlan{DBName: "foo"},
})
tests.Add("client closed", tt{
db: &DB{
driverDB: &mock.Finder{},
client: &Client{
closed: true,
},
},
status: http.StatusServiceUnavailable,
err: "kivik: client closed",
})
tests.Add("db error", tt{
db: &DB{
err: errors.New("db error"),
},
status: http.StatusInternalServerError,
err: "db error",
})
tests.Run(t, func(t *testing.T, tt tt) {
result, err := tt.db.Explain(context.Background(), tt.query)
if d := internal.StatusErrorDiff(tt.err, tt.status, err); d != "" {
t.Error(d)
}
if d := testy.DiffInterface(tt.expected, result); d != nil {
t.Error(d)
}
})
}
0