Switch from Godep to go vendoring

This commit is contained in:
Ken-Håvard Lieng 2016-03-01 01:51:26 +01:00
parent 6b37713bc0
commit cd317761c5
1504 changed files with 263076 additions and 34441 deletions

65
vendor/github.com/blevesearch/bleve/http/alias.go generated vendored Normal file
View file

@ -0,0 +1,65 @@
// Copyright (c) 2014 Couchbase, Inc.
// 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 http
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
type AliasAction struct {
Alias string `json:"alias"`
AddIndexes []string `json:"add"`
RemoveIndexes []string `json:"remove"`
}
type AliasHandler struct{}
func NewAliasHandler() *AliasHandler {
return &AliasHandler{}
}
func (h *AliasHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// read the request body
requestBody, err := ioutil.ReadAll(req.Body)
if err != nil {
showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400)
return
}
var aliasAction AliasAction
// interpret request body as alias actions
if len(requestBody) > 0 {
err := json.Unmarshal(requestBody, &aliasAction)
if err != nil {
showError(w, req, fmt.Sprintf("error parsing alias actions: %v", err), 400)
return
}
} else {
showError(w, req, "request body must contain alias actions", 400)
return
}
err = UpdateAlias(aliasAction.Alias, aliasAction.AddIndexes, aliasAction.RemoveIndexes)
if err != nil {
showError(w, req, fmt.Sprintf("error updating alias: %v", err), 400)
return
}
rv := struct {
Status string `json:"status"`
}{
Status: "ok",
}
mustEncode(w, rv)
}

74
vendor/github.com/blevesearch/bleve/http/debug.go generated vendored Normal file
View file

@ -0,0 +1,74 @@
// Copyright (c) 2014 Couchbase, Inc.
// 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 http
import (
"fmt"
"net/http"
"github.com/blevesearch/bleve/index/upside_down"
)
// DebugDocumentHandler allows you to debug the index content
// for a given document id.
type DebugDocumentHandler struct {
defaultIndexName string
IndexNameLookup varLookupFunc
DocIDLookup varLookupFunc
}
func NewDebugDocumentHandler(defaultIndexName string) *DebugDocumentHandler {
return &DebugDocumentHandler{
defaultIndexName: defaultIndexName,
}
}
func (h *DebugDocumentHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// find the index to operate on
var indexName string
if h.IndexNameLookup != nil {
indexName = h.IndexNameLookup(req)
}
if indexName == "" {
indexName = h.defaultIndexName
}
index := IndexByName(indexName)
if index == nil {
showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404)
return
}
// find the docID
var docID string
if h.DocIDLookup != nil {
docID = h.DocIDLookup(req)
}
rv := make([]interface{}, 0)
rowChan := index.DumpDoc(docID)
for row := range rowChan {
switch row := row.(type) {
case error:
showError(w, req, fmt.Sprintf("error debugging document: %v", row), 500)
return
case upside_down.UpsideDownCouchRow:
tmp := struct {
Key []byte `json:"key"`
Val []byte `json:"val"`
}{
Key: row.Key(),
Val: row.Value(),
}
rv = append(rv, tmp)
}
}
mustEncode(w, rv)
}

56
vendor/github.com/blevesearch/bleve/http/doc_count.go generated vendored Normal file
View file

@ -0,0 +1,56 @@
// Copyright (c) 2014 Couchbase, Inc.
// 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 http
import (
"fmt"
"net/http"
)
type DocCountHandler struct {
defaultIndexName string
IndexNameLookup varLookupFunc
}
func NewDocCountHandler(defaultIndexName string) *DocCountHandler {
return &DocCountHandler{
defaultIndexName: defaultIndexName,
}
}
func (h *DocCountHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// find the index to operate on
var indexName string
if h.IndexNameLookup != nil {
indexName = h.IndexNameLookup(req)
}
if indexName == "" {
indexName = h.defaultIndexName
}
index := IndexByName(indexName)
if index == nil {
showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404)
return
}
docCount, err := index.DocCount()
if err != nil {
showError(w, req, fmt.Sprintf("error counting docs: %v", err), 500)
return
}
rv := struct {
Status string `json:"status"`
Count uint64 `json:"count"`
}{
Status: "ok",
Count: docCount,
}
mustEncode(w, rv)
}

67
vendor/github.com/blevesearch/bleve/http/doc_delete.go generated vendored Normal file
View file

@ -0,0 +1,67 @@
// Copyright (c) 2014 Couchbase, Inc.
// 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 http
import (
"fmt"
"net/http"
)
type DocDeleteHandler struct {
defaultIndexName string
IndexNameLookup varLookupFunc
DocIDLookup varLookupFunc
}
func NewDocDeleteHandler(defaultIndexName string) *DocDeleteHandler {
return &DocDeleteHandler{
defaultIndexName: defaultIndexName,
}
}
func (h *DocDeleteHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// find the index to operate on
var indexName string
if h.IndexNameLookup != nil {
indexName = h.IndexNameLookup(req)
}
if indexName == "" {
indexName = h.defaultIndexName
}
index := IndexByName(indexName)
if index == nil {
showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404)
return
}
// find the doc id
var docID string
if h.DocIDLookup != nil {
docID = h.DocIDLookup(req)
}
if docID == "" {
showError(w, req, "document id cannot be empty", 400)
return
}
err := index.Delete(docID)
if err != nil {
showError(w, req, fmt.Sprintf("error deleting document '%s': %v", docID, err), 500)
return
}
rv := struct {
Status string `json:"status"`
}{
Status: "ok",
}
mustEncode(w, rv)
}

107
vendor/github.com/blevesearch/bleve/http/doc_get.go generated vendored Normal file
View file

@ -0,0 +1,107 @@
// Copyright (c) 2014 Couchbase, Inc.
// 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 http
import (
"fmt"
"net/http"
"time"
"github.com/blevesearch/bleve/document"
)
type DocGetHandler struct {
defaultIndexName string
IndexNameLookup varLookupFunc
DocIDLookup varLookupFunc
}
func NewDocGetHandler(defaultIndexName string) *DocGetHandler {
return &DocGetHandler{
defaultIndexName: defaultIndexName,
}
}
func (h *DocGetHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// find the index to operate on
var indexName string
if h.IndexNameLookup != nil {
indexName = h.IndexNameLookup(req)
}
if indexName == "" {
indexName = h.defaultIndexName
}
index := IndexByName(indexName)
if index == nil {
showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404)
return
}
// find the doc id
var docID string
if h.DocIDLookup != nil {
docID = h.DocIDLookup(req)
}
if docID == "" {
showError(w, req, "document id cannot be empty", 400)
return
}
doc, err := index.Document(docID)
if err != nil {
showError(w, req, fmt.Sprintf("error deleting document '%s': %v", docID, err), 500)
return
}
if doc == nil {
showError(w, req, fmt.Sprintf("no such document '%s'", docID), 404)
return
}
rv := struct {
ID string `json:"id"`
Fields map[string]interface{} `json:"fields"`
}{
ID: docID,
Fields: map[string]interface{}{},
}
for _, field := range doc.Fields {
var newval interface{}
switch field := field.(type) {
case *document.TextField:
newval = string(field.Value())
case *document.NumericField:
n, err := field.Number()
if err == nil {
newval = n
}
case *document.DateTimeField:
d, err := field.DateTime()
if err == nil {
newval = d.Format(time.RFC3339Nano)
}
}
existing, existed := rv.Fields[field.Name()]
if existed {
switch existing := existing.(type) {
case []interface{}:
rv.Fields[field.Name()] = append(existing, newval)
case interface{}:
arr := make([]interface{}, 2)
arr[0] = existing
arr[1] = newval
rv.Fields[field.Name()] = arr
}
} else {
rv.Fields[field.Name()] = newval
}
}
mustEncode(w, rv)
}

75
vendor/github.com/blevesearch/bleve/http/doc_index.go generated vendored Normal file
View file

@ -0,0 +1,75 @@
// Copyright (c) 2014 Couchbase, Inc.
// 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 http
import (
"fmt"
"io/ioutil"
"net/http"
)
type DocIndexHandler struct {
defaultIndexName string
IndexNameLookup varLookupFunc
DocIDLookup varLookupFunc
}
func NewDocIndexHandler(defaultIndexName string) *DocIndexHandler {
return &DocIndexHandler{
defaultIndexName: defaultIndexName,
}
}
func (h *DocIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// find the index to operate on
var indexName string
if h.IndexNameLookup != nil {
indexName = h.IndexNameLookup(req)
}
if indexName == "" {
indexName = h.defaultIndexName
}
index := IndexByName(indexName)
if index == nil {
showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404)
return
}
// find the doc id
var docID string
if h.DocIDLookup != nil {
docID = h.DocIDLookup(req)
}
if docID == "" {
showError(w, req, "document id cannot be empty", 400)
return
}
// read the request body
requestBody, err := ioutil.ReadAll(req.Body)
if err != nil {
showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400)
return
}
err = index.Index(docID, requestBody)
if err != nil {
showError(w, req, fmt.Sprintf("error indexing document '%s': %v", docID, err), 500)
return
}
rv := struct {
Status string `json:"status"`
}{
Status: "ok",
}
mustEncode(w, rv)
}

58
vendor/github.com/blevesearch/bleve/http/fields.go generated vendored Normal file
View file

@ -0,0 +1,58 @@
// Copyright (c) 2014 Couchbase, Inc.
// 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 http
import (
"fmt"
"net/http"
)
type ListFieldsHandler struct {
defaultIndexName string
IndexNameLookup varLookupFunc
}
func NewListFieldsHandler(defaultIndexName string) *ListFieldsHandler {
return &ListFieldsHandler{
defaultIndexName: defaultIndexName,
}
}
func (h *ListFieldsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// find the index to operate on
var indexName string
if h.IndexNameLookup != nil {
indexName = h.IndexNameLookup(req)
}
if indexName == "" {
indexName = h.defaultIndexName
}
index := IndexByName(indexName)
if index == nil {
showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404)
return
}
fields, err := index.Fields()
if err != nil {
showError(w, req, fmt.Sprintf("error: %v", err), 500)
return
}
fieldsResponse := struct {
Fields []string `json:"fields"`
}{
Fields: fields,
}
// encode the response
mustEncode(w, fieldsResponse)
}

View file

@ -0,0 +1,704 @@
package http
import (
"bytes"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"os"
"reflect"
"testing"
)
func docIDLookup(req *http.Request) string {
return req.FormValue("docID")
}
func indexNameLookup(req *http.Request) string {
return req.FormValue("indexName")
}
func TestHandlers(t *testing.T) {
basePath := "testbase"
err := os.MkdirAll(basePath, 0700)
if err != nil {
t.Fatal(err)
}
defer func() {
err := os.RemoveAll(basePath)
if err != nil {
t.Fatal(err)
}
}()
createIndexHandler := NewCreateIndexHandler(basePath)
createIndexHandler.IndexNameLookup = indexNameLookup
getIndexHandler := NewGetIndexHandler()
getIndexHandler.IndexNameLookup = indexNameLookup
deleteIndexHandler := NewDeleteIndexHandler(basePath)
deleteIndexHandler.IndexNameLookup = indexNameLookup
listIndexesHandler := NewListIndexesHandler()
docIndexHandler := NewDocIndexHandler("")
docIndexHandler.IndexNameLookup = indexNameLookup
docIndexHandler.DocIDLookup = docIDLookup
docCountHandler := NewDocCountHandler("")
docCountHandler.IndexNameLookup = indexNameLookup
docGetHandler := NewDocGetHandler("")
docGetHandler.IndexNameLookup = indexNameLookup
docGetHandler.DocIDLookup = docIDLookup
docDeleteHandler := NewDocDeleteHandler("")
docDeleteHandler.IndexNameLookup = indexNameLookup
docDeleteHandler.DocIDLookup = docIDLookup
searchHandler := NewSearchHandler("")
searchHandler.IndexNameLookup = indexNameLookup
listFieldsHandler := NewListFieldsHandler("")
listFieldsHandler.IndexNameLookup = indexNameLookup
debugHandler := NewDebugDocumentHandler("")
debugHandler.IndexNameLookup = indexNameLookup
debugHandler.DocIDLookup = docIDLookup
aliasHandler := NewAliasHandler()
tests := []struct {
Desc string
Handler http.Handler
Path string
Method string
Params url.Values
Body []byte
Status int
ResponseBody []byte
ResponseMatch map[string]bool
}{
{
Desc: "create index",
Handler: createIndexHandler,
Path: "/create",
Method: "PUT",
Params: url.Values{"indexName": []string{"ti1"}},
Body: []byte("{}"),
Status: http.StatusOK,
ResponseBody: []byte(`{"status":"ok"}`),
},
{
Desc: "create existing index",
Handler: createIndexHandler,
Path: "/create",
Method: "PUT",
Params: url.Values{"indexName": []string{"ti1"}},
Body: []byte("{}"),
Status: http.StatusInternalServerError,
ResponseMatch: map[string]bool{
`path already exists`: true,
},
},
{
Desc: "create index missing index",
Handler: createIndexHandler,
Path: "/create",
Method: "PUT",
Body: []byte("{}"),
Status: http.StatusBadRequest,
ResponseBody: []byte(`index name is required`),
},
{
Desc: "create index invalid json",
Handler: createIndexHandler,
Path: "/create",
Method: "PUT",
Params: url.Values{"indexName": []string{"ti9"}},
Body: []byte("{"),
Status: http.StatusBadRequest,
ResponseMatch: map[string]bool{
`error parsing index mapping`: true,
},
},
{
Desc: "get index",
Handler: getIndexHandler,
Path: "/get",
Method: "GET",
Params: url.Values{"indexName": []string{"ti1"}},
Status: http.StatusOK,
ResponseMatch: map[string]bool{
`"status":"ok"`: true,
`"name":"ti1"`: true,
},
},
{
Desc: "get index does not exist",
Handler: getIndexHandler,
Path: "/get",
Method: "GET",
Params: url.Values{"indexName": []string{"dne"}},
Status: http.StatusNotFound,
ResponseMatch: map[string]bool{
`no such index`: true,
},
},
{
Desc: "get index missing name",
Handler: getIndexHandler,
Path: "/get",
Method: "GET",
Status: http.StatusBadRequest,
ResponseBody: []byte(`index name is required`),
},
{
Desc: "create another index",
Handler: createIndexHandler,
Path: "/create",
Method: "PUT",
Params: url.Values{"indexName": []string{"ti2"}},
Body: []byte("{}"),
Status: http.StatusOK,
ResponseBody: []byte(`{"status":"ok"}`),
},
{
Desc: "list indexes",
Handler: listIndexesHandler,
Path: "/list",
Method: "GET",
Status: http.StatusOK,
ResponseMatch: map[string]bool{
`"status":"ok"`: true,
`"ti1"`: true,
`"ti2"`: true,
},
},
{
Desc: "delete index",
Handler: deleteIndexHandler,
Path: "/delete",
Method: "DELETE",
Params: url.Values{"indexName": []string{"ti2"}},
Status: http.StatusOK,
ResponseBody: []byte(`{"status":"ok"}`),
},
{
Desc: "delete index missing name",
Handler: deleteIndexHandler,
Path: "/delete",
Method: "DELETE",
Status: http.StatusBadRequest,
ResponseBody: []byte(`index name is required`),
},
{
Desc: "list indexes after delete",
Handler: listIndexesHandler,
Path: "/list",
Method: "GET",
Status: http.StatusOK,
ResponseMatch: map[string]bool{
`"status":"ok"`: true,
`"ti1"`: true,
`"ti2"`: false,
},
},
{
Desc: "index doc",
Handler: docIndexHandler,
Path: "/ti1/a",
Method: "PUT",
Params: url.Values{
"indexName": []string{"ti1"},
"docID": []string{"a"},
},
Body: []byte(`{"name":"a","body":"test","rating":7,"created":"2014-11-26","former_ratings":[3,4,2]}`),
Status: http.StatusOK,
ResponseBody: []byte(`{"status":"ok"}`),
},
{
Desc: "index doc invalid index",
Handler: docIndexHandler,
Path: "/tix/a",
Method: "PUT",
Params: url.Values{
"indexName": []string{"tix"},
"docID": []string{"a"},
},
Body: []byte(`{"name":"a","body":"test","rating":7,"created":"2014-11-26","former_ratings":[3,4,2]}`),
Status: http.StatusNotFound,
ResponseBody: []byte(`no such index 'tix'`),
},
{
Desc: "index doc missing ID",
Handler: docIndexHandler,
Path: "/ti1/a",
Method: "PUT",
Params: url.Values{
"indexName": []string{"ti1"},
},
Body: []byte(`{"name":"a","body":"test","rating":7,"created":"2014-11-26","former_ratings":[3,4,2]}`),
Status: http.StatusBadRequest,
ResponseBody: []byte(`document id cannot be empty`),
},
{
Desc: "doc count",
Handler: docCountHandler,
Path: "/ti1/count",
Method: "GET",
Params: url.Values{
"indexName": []string{"ti1"},
},
Status: http.StatusOK,
ResponseBody: []byte(`{"status":"ok","count":1}`),
},
{
Desc: "doc count invalid index",
Handler: docCountHandler,
Path: "/tix/count",
Method: "GET",
Params: url.Values{
"indexName": []string{"tix"},
},
Status: http.StatusNotFound,
ResponseBody: []byte(`no such index 'tix'`),
},
{
Desc: "doc get",
Handler: docGetHandler,
Path: "/ti1/a",
Method: "GET",
Params: url.Values{
"indexName": []string{"ti1"},
"docID": []string{"a"},
},
Status: http.StatusOK,
ResponseMatch: map[string]bool{
`"id":"a"`: true,
`"body":"test"`: true,
`"name":"a"`: true,
},
},
{
Desc: "doc get invalid index",
Handler: docGetHandler,
Path: "/tix/a",
Method: "GET",
Params: url.Values{
"indexName": []string{"tix"},
"docID": []string{"a"},
},
Status: http.StatusNotFound,
ResponseBody: []byte(`no such index 'tix'`),
},
{
Desc: "doc get missing ID",
Handler: docGetHandler,
Path: "/ti1/a",
Method: "GET",
Params: url.Values{
"indexName": []string{"ti1"},
},
Status: http.StatusBadRequest,
ResponseBody: []byte(`document id cannot be empty`),
},
{
Desc: "index another doc",
Handler: docIndexHandler,
Path: "/ti1/b",
Method: "PUT",
Params: url.Values{
"indexName": []string{"ti1"},
"docID": []string{"b"},
},
Body: []byte(`{"name":"b","body":"del"}`),
Status: http.StatusOK,
ResponseBody: []byte(`{"status":"ok"}`),
},
{
Desc: "doc count again",
Handler: docCountHandler,
Path: "/ti1/count",
Method: "GET",
Params: url.Values{
"indexName": []string{"ti1"},
},
Status: http.StatusOK,
ResponseBody: []byte(`{"status":"ok","count":2}`),
},
{
Desc: "delete doc",
Handler: docDeleteHandler,
Path: "/ti1/b",
Method: "DELETE",
Params: url.Values{
"indexName": []string{"ti1"},
"docID": []string{"b"},
},
Status: http.StatusOK,
ResponseBody: []byte(`{"status":"ok"}`),
},
{
Desc: "delete doc invalid index",
Handler: docDeleteHandler,
Path: "/tix/b",
Method: "DELETE",
Params: url.Values{
"indexName": []string{"tix"},
"docID": []string{"b"},
},
Status: http.StatusNotFound,
ResponseBody: []byte(`no such index 'tix'`),
},
{
Desc: "delete doc missing docID",
Handler: docDeleteHandler,
Path: "/ti1/b",
Method: "DELETE",
Params: url.Values{
"indexName": []string{"ti1"},
},
Status: http.StatusBadRequest,
ResponseBody: []byte(`document id cannot be empty`),
},
{
Desc: "doc get",
Handler: docGetHandler,
Path: "/ti1/b",
Method: "GET",
Params: url.Values{
"indexName": []string{"ti1"},
"docID": []string{"b"},
},
Status: http.StatusNotFound,
ResponseMatch: map[string]bool{
`no such document`: true,
},
},
{
Desc: "search",
Handler: searchHandler,
Path: "/ti1/search",
Method: "POST",
Params: url.Values{
"indexName": []string{"ti1"},
},
Body: []byte(`{
"from": 0,
"size": 10,
"query": {
"fuzziness": 0,
"prefix_length": 0,
"field": "body",
"match": "test"
}
}`),
Status: http.StatusOK,
ResponseMatch: map[string]bool{
`"total_hits":1`: true,
`"id":"a"`: true,
},
},
{
Desc: "search index doesnt exist",
Handler: searchHandler,
Path: "/tix/search",
Method: "POST",
Params: url.Values{
"indexName": []string{"tix"},
},
Body: []byte(`{
"from": 0,
"size": 10,
"query": {
"fuzziness": 0,
"prefix_length": 0,
"field": "body",
"match": "test"
}
}`),
Status: http.StatusNotFound,
ResponseBody: []byte(`no such index 'tix'`),
},
{
Desc: "search invalid json",
Handler: searchHandler,
Path: "/ti1/search",
Method: "POST",
Params: url.Values{
"indexName": []string{"ti1"},
},
Body: []byte(`{`),
Status: http.StatusBadRequest,
ResponseMatch: map[string]bool{
`error parsing query`: true,
},
},
{
Desc: "search query does not validate",
Handler: searchHandler,
Path: "/ti1/search",
Method: "POST",
Params: url.Values{
"indexName": []string{"ti1"},
},
Body: []byte(`{
"from": 0,
"size": 10,
"query": {
"field": "body",
"terms": []
}
}`),
Status: http.StatusBadRequest,
ResponseMatch: map[string]bool{
`error validating query`: true,
},
},
{
Desc: "list fields",
Handler: listFieldsHandler,
Path: "/ti1/fields",
Method: "GET",
Params: url.Values{
"indexName": []string{"ti1"},
},
Status: http.StatusOK,
ResponseMatch: map[string]bool{
`"fields":`: true,
`"name"`: true,
`"body"`: true,
`"_all"`: true,
},
},
{
Desc: "list fields invalid index",
Handler: listFieldsHandler,
Path: "/tix/fields",
Method: "GET",
Params: url.Values{
"indexName": []string{"tix"},
},
Status: http.StatusNotFound,
ResponseBody: []byte(`no such index 'tix'`),
},
{
Desc: "debug doc",
Handler: debugHandler,
Path: "/ti1/a/debug",
Method: "GET",
Params: url.Values{
"indexName": []string{"ti1"},
"docID": []string{"a"},
},
Status: http.StatusOK,
ResponseMatch: map[string]bool{
`"key"`: true,
`"val"`: true,
},
},
{
Desc: "debug doc invalid index",
Handler: debugHandler,
Path: "/ti1/a/debug",
Method: "GET",
Params: url.Values{
"indexName": []string{"tix"},
"docID": []string{"a"},
},
Status: http.StatusNotFound,
ResponseBody: []byte(`no such index 'tix'`),
},
{
Desc: "create alias",
Handler: aliasHandler,
Path: "/alias",
Method: "POST",
Body: []byte(`{
"alias": "a1",
"add": ["ti1"]
}`),
Status: http.StatusOK,
ResponseBody: []byte(`{"status":"ok"}`),
},
{
Desc: "create alias invalid json",
Handler: aliasHandler,
Path: "/alias",
Method: "POST",
Body: []byte(`{`),
Status: http.StatusBadRequest,
ResponseMatch: map[string]bool{
`error parsing alias actions`: true,
},
},
{
Desc: "create alias empty",
Handler: aliasHandler,
Path: "/alias",
Method: "POST",
Body: []byte(``),
Status: http.StatusBadRequest,
ResponseMatch: map[string]bool{
`request body must contain alias actions`: true,
},
},
{
Desc: "create alias referring to non-existant index",
Handler: aliasHandler,
Path: "/alias",
Method: "POST",
Body: []byte(`{
"alias": "a2",
"add": ["tix"]
}`),
Status: http.StatusBadRequest,
ResponseMatch: map[string]bool{
`index named 'tix' does not exist`: true,
},
},
{
Desc: "create alias removing from new",
Handler: aliasHandler,
Path: "/alias",
Method: "POST",
Body: []byte(`{
"alias": "a2",
"remove": ["ti1"]
}`),
Status: http.StatusBadRequest,
ResponseMatch: map[string]bool{
`cannot remove indexes from a new alias`: true,
},
},
{
Desc: "create alias same name as index",
Handler: aliasHandler,
Path: "/alias",
Method: "POST",
Body: []byte(`{
"alias": "ti1",
"remove": ["ti1"]
}`),
Status: http.StatusBadRequest,
ResponseMatch: map[string]bool{
`is not an alias`: true,
},
},
{
Desc: "search alias",
Handler: searchHandler,
Path: "/a1/search",
Method: "POST",
Params: url.Values{
"indexName": []string{"a1"},
},
Body: []byte(`{
"from": 0,
"size": 10,
"query": {
"fuzziness": 0,
"prefix_length": 0,
"field": "body",
"match": "test"
}
}`),
Status: http.StatusOK,
ResponseMatch: map[string]bool{
`"total_hits":1`: true,
`"id":"a"`: true,
},
},
{
Desc: "create index to add to alias",
Handler: createIndexHandler,
Path: "/create",
Method: "PUT",
Params: url.Values{"indexName": []string{"ti6"}},
Body: []byte("{}"),
Status: http.StatusOK,
ResponseBody: []byte(`{"status":"ok"}`),
},
{
Desc: "update alias add ti6",
Handler: aliasHandler,
Path: "/alias",
Method: "POST",
Body: []byte(`{
"alias": "a1",
"add": ["ti6"]
}`),
Status: http.StatusOK,
ResponseBody: []byte(`{"status":"ok"}`),
},
{
Desc: "update alias add doesnt exist",
Handler: aliasHandler,
Path: "/alias",
Method: "POST",
Body: []byte(`{
"alias": "a1",
"add": ["ti99"]
}`),
Status: http.StatusBadRequest,
ResponseBody: []byte(`error updating alias: index named 'ti99' does not exist`),
},
{
Desc: "update alias remove ti6",
Handler: aliasHandler,
Path: "/alias",
Method: "POST",
Body: []byte(`{
"alias": "a1",
"remove": ["ti6"]
}`),
Status: http.StatusOK,
ResponseBody: []byte(`{"status":"ok"}`),
},
{
Desc: "update alias remove doesnt exist",
Handler: aliasHandler,
Path: "/alias",
Method: "POST",
Body: []byte(`{
"alias": "a1",
"remove": ["ti98"]
}`),
Status: http.StatusBadRequest,
ResponseBody: []byte(`error updating alias: index named 'ti98' does not exist`),
},
}
for _, test := range tests {
record := httptest.NewRecorder()
req := &http.Request{
Method: test.Method,
URL: &url.URL{Path: test.Path},
Form: test.Params,
Body: ioutil.NopCloser(bytes.NewBuffer(test.Body)),
}
test.Handler.ServeHTTP(record, req)
if got, want := record.Code, test.Status; got != want {
t.Errorf("%s: response code = %d, want %d", test.Desc, got, want)
t.Errorf("%s: response body = %s", test.Desc, record.Body)
}
got := bytes.TrimRight(record.Body.Bytes(), "\n")
if test.ResponseBody != nil {
if !reflect.DeepEqual(got, test.ResponseBody) {
t.Errorf("%s: expected: '%s', got: '%s'", test.Desc, test.ResponseBody, got)
}
}
for pattern, shouldMatch := range test.ResponseMatch {
didMatch := bytes.Contains(got, []byte(pattern))
if didMatch != shouldMatch {
t.Errorf("%s: expected match %t for pattern %s, got %t", test.Desc, shouldMatch, pattern, didMatch)
t.Errorf("%s: response body was: %s", test.Desc, got)
}
}
}
}

View file

@ -0,0 +1,78 @@
// Copyright (c) 2014 Couchbase, Inc.
// 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 http
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"github.com/blevesearch/bleve"
)
type CreateIndexHandler struct {
basePath string
IndexNameLookup varLookupFunc
}
func NewCreateIndexHandler(basePath string) *CreateIndexHandler {
return &CreateIndexHandler{
basePath: basePath,
}
}
func (h *CreateIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// find the name of the index to create
var indexName string
if h.IndexNameLookup != nil {
indexName = h.IndexNameLookup(req)
}
if indexName == "" {
showError(w, req, "index name is required", 400)
return
}
indexMapping := bleve.NewIndexMapping()
// read the request body
requestBody, err := ioutil.ReadAll(req.Body)
if err != nil {
showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400)
return
}
// interpret request body as index mapping
if len(requestBody) > 0 {
err := json.Unmarshal(requestBody, &indexMapping)
if err != nil {
showError(w, req, fmt.Sprintf("error parsing index mapping: %v", err), 400)
return
}
}
newIndex, err := bleve.New(h.indexPath(indexName), indexMapping)
if err != nil {
showError(w, req, fmt.Sprintf("error creating index: %v", err), 500)
return
}
RegisterIndexName(indexName, newIndex)
rv := struct {
Status string `json:"status"`
}{
Status: "ok",
}
mustEncode(w, rv)
}
func (h *CreateIndexHandler) indexPath(name string) string {
return h.basePath + string(os.PathSeparator) + name
}

View file

@ -0,0 +1,70 @@
// Copyright (c) 2014 Couchbase, Inc.
// 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 http
import (
"fmt"
"net/http"
"os"
)
type DeleteIndexHandler struct {
basePath string
IndexNameLookup varLookupFunc
}
func NewDeleteIndexHandler(basePath string) *DeleteIndexHandler {
return &DeleteIndexHandler{
basePath: basePath,
}
}
func (h *DeleteIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// find the name of the index to delete
var indexName string
if h.IndexNameLookup != nil {
indexName = h.IndexNameLookup(req)
}
if indexName == "" {
showError(w, req, "index name is required", 400)
return
}
indexToDelete := UnregisterIndexByName(indexName)
if indexToDelete == nil {
showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404)
return
}
// close the index
err := indexToDelete.Close()
if err != nil {
showError(w, req, fmt.Sprintf("error closing index: %v", err), 500)
return
}
// now delete it
err = os.RemoveAll(h.indexPath(indexName))
if err != nil {
showError(w, req, fmt.Sprintf("error deleting index: %v", err), 500)
return
}
rv := struct {
Status string `json:"status"`
}{
Status: "ok",
}
mustEncode(w, rv)
}
func (h *DeleteIndexHandler) indexPath(name string) string {
return h.basePath + string(os.PathSeparator) + name
}

54
vendor/github.com/blevesearch/bleve/http/index_get.go generated vendored Normal file
View file

@ -0,0 +1,54 @@
// Copyright (c) 2014 Couchbase, Inc.
// 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 http
import (
"fmt"
"net/http"
"github.com/blevesearch/bleve"
)
type GetIndexHandler struct {
IndexNameLookup varLookupFunc
}
func NewGetIndexHandler() *GetIndexHandler {
return &GetIndexHandler{}
}
func (h *GetIndexHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// find the name of the index to create
var indexName string
if h.IndexNameLookup != nil {
indexName = h.IndexNameLookup(req)
}
if indexName == "" {
showError(w, req, "index name is required", 400)
return
}
index := IndexByName(indexName)
if index == nil {
showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404)
return
}
rv := struct {
Status string `json:"status"`
Name string `json:"name"`
Mapping *bleve.IndexMapping `json:"mapping"`
}{
Status: "ok",
Name: indexName,
Mapping: index.Mapping(),
}
mustEncode(w, rv)
}

33
vendor/github.com/blevesearch/bleve/http/index_list.go generated vendored Normal file
View file

@ -0,0 +1,33 @@
// Copyright (c) 2014 Couchbase, Inc.
// 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 http
import (
"net/http"
)
type ListIndexesHandler struct {
}
func NewListIndexesHandler() *ListIndexesHandler {
return &ListIndexesHandler{}
}
func (h *ListIndexesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
indexNames := IndexNames()
rv := struct {
Status string `json:"status"`
Indexes []string `json:"indexes"`
}{
Status: "ok",
Indexes: indexNames,
}
mustEncode(w, rv)
}

120
vendor/github.com/blevesearch/bleve/http/registry.go generated vendored Normal file
View file

@ -0,0 +1,120 @@
// Copyright (c) 2014 Couchbase, Inc.
// 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 http
import (
"fmt"
"sync"
"github.com/blevesearch/bleve"
)
var indexNameMapping map[string]bleve.Index
var indexNameMappingLock sync.RWMutex
var indexStats = bleve.IndexStats{}
func RegisterIndexName(name string, idx bleve.Index) {
indexNameMappingLock.Lock()
defer indexNameMappingLock.Unlock()
if indexNameMapping == nil {
indexNameMapping = make(map[string]bleve.Index)
}
indexNameMapping[name] = idx
indexStats[name] = idx.Stats()
}
func UnregisterIndexByName(name string) bleve.Index {
indexNameMappingLock.Lock()
defer indexNameMappingLock.Unlock()
if indexNameMapping == nil {
return nil
}
rv := indexNameMapping[name]
if rv != nil {
delete(indexNameMapping, name)
}
delete(indexStats, name)
return rv
}
func IndexByName(name string) bleve.Index {
indexNameMappingLock.RLock()
defer indexNameMappingLock.RUnlock()
return indexNameMapping[name]
}
func IndexNames() []string {
indexNameMappingLock.RLock()
defer indexNameMappingLock.RUnlock()
rv := make([]string, len(indexNameMapping))
count := 0
for k := range indexNameMapping {
rv[count] = k
count++
}
return rv
}
func IndexStats() bleve.IndexStats {
return indexStats
}
func UpdateAlias(alias string, add, remove []string) error {
indexNameMappingLock.Lock()
defer indexNameMappingLock.Unlock()
index, exists := indexNameMapping[alias]
if !exists {
// new alias
if len(remove) > 0 {
return fmt.Errorf("cannot remove indexes from a new alias")
}
indexes := make([]bleve.Index, len(add))
for i, addIndexName := range add {
addIndex, indexExists := indexNameMapping[addIndexName]
if !indexExists {
return fmt.Errorf("index named '%s' does not exist", addIndexName)
}
indexes[i] = addIndex
}
indexAlias := bleve.NewIndexAlias(indexes...)
indexNameMapping[alias] = indexAlias
} else {
// something with this name already exists
indexAlias, isAlias := index.(bleve.IndexAlias)
if !isAlias {
return fmt.Errorf("'%s' is not an alias", alias)
}
// build list of add indexes
addIndexes := make([]bleve.Index, len(add))
for i, addIndexName := range add {
addIndex, indexExists := indexNameMapping[addIndexName]
if !indexExists {
return fmt.Errorf("index named '%s' does not exist", addIndexName)
}
addIndexes[i] = addIndex
}
// build list of remove indexes
removeIndexes := make([]bleve.Index, len(remove))
for i, removeIndexName := range remove {
removeIndex, indexExists := indexNameMapping[removeIndexName]
if !indexExists {
return fmt.Errorf("index named '%s' does not exist", removeIndexName)
}
removeIndexes[i] = removeIndex
}
indexAlias.Swap(addIndexes, removeIndexes)
}
return nil
}

84
vendor/github.com/blevesearch/bleve/http/search.go generated vendored Normal file
View file

@ -0,0 +1,84 @@
// Copyright (c) 2014 Couchbase, Inc.
// 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 http
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"github.com/blevesearch/bleve"
)
// SearchHandler can handle search requests sent over HTTP
type SearchHandler struct {
defaultIndexName string
IndexNameLookup varLookupFunc
}
func NewSearchHandler(defaultIndexName string) *SearchHandler {
return &SearchHandler{
defaultIndexName: defaultIndexName,
}
}
func (h *SearchHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// find the index to operate on
var indexName string
if h.IndexNameLookup != nil {
indexName = h.IndexNameLookup(req)
}
if indexName == "" {
indexName = h.defaultIndexName
}
index := IndexByName(indexName)
if index == nil {
showError(w, req, fmt.Sprintf("no such index '%s'", indexName), 404)
return
}
// read the request body
requestBody, err := ioutil.ReadAll(req.Body)
if err != nil {
showError(w, req, fmt.Sprintf("error reading request body: %v", err), 400)
return
}
logger.Printf("request body: %s", requestBody)
// parse the request
var searchRequest bleve.SearchRequest
err = json.Unmarshal(requestBody, &searchRequest)
if err != nil {
showError(w, req, fmt.Sprintf("error parsing query: %v", err), 400)
return
}
logger.Printf("parsed request %#v", searchRequest)
// validate the query
err = searchRequest.Query.Validate()
if err != nil {
showError(w, req, fmt.Sprintf("error validating query: %v", err), 400)
return
}
// execute the query
searchResponse, err := index.Search(&searchRequest)
if err != nil {
showError(w, req, fmt.Sprintf("error executing query: %v", err), 500)
return
}
// encode the response
mustEncode(w, searchResponse)
}

46
vendor/github.com/blevesearch/bleve/http/util.go generated vendored Normal file
View file

@ -0,0 +1,46 @@
// Copyright (c) 2014 Couchbase, Inc.
// 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 http
import (
"encoding/json"
"io"
"io/ioutil"
"log"
"net/http"
)
func showError(w http.ResponseWriter, r *http.Request,
msg string, code int) {
logger.Printf("Reporting error %v/%v", code, msg)
http.Error(w, msg, code)
}
func mustEncode(w io.Writer, i interface{}) {
if headered, ok := w.(http.ResponseWriter); ok {
headered.Header().Set("Cache-Control", "no-cache")
headered.Header().Set("Content-type", "application/json")
}
e := json.NewEncoder(w)
if err := e.Encode(i); err != nil {
panic(err)
}
}
type varLookupFunc func(req *http.Request) string
var logger = log.New(ioutil.Discard, "bleve.http", log.LstdFlags)
// SetLog sets the logger used for logging
// by default log messages are sent to ioutil.Discard
func SetLog(l *log.Logger) {
logger = l
}