mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
Merge remote-tracking branch 'origin/master' into metrics
This commit is contained in:
commit
baafc7792a
3 changed files with 135 additions and 57 deletions
|
|
@ -35,3 +35,57 @@ func testMessageMarshal(t *testing.T, m proto.Message) {
|
|||
t.Fatalf("unexpected message marshalling: %s", unmarshalled)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that BroadcastReceiver can register a BroadcastHandler.
|
||||
func TestBroadcast_BroadcastReceiver(t *testing.T) {
|
||||
|
||||
s := pilosa.NewServer()
|
||||
|
||||
sbr := NewSimpleBroadcastReceiver()
|
||||
sbh := NewSimpleBroadcastHandler()
|
||||
|
||||
s.BroadcastReceiver = sbr
|
||||
s.BroadcastReceiver.Start(sbh)
|
||||
|
||||
msg := &internal.DeleteDBMessage{
|
||||
DB: "d",
|
||||
}
|
||||
|
||||
s.BroadcastReceiver.(*SimpleBroadcastReceiver).Receive(msg)
|
||||
|
||||
// Make sure the message received is what was sentd
|
||||
if !reflect.DeepEqual(sbh.receivedMessage, msg) {
|
||||
t.Fatalf("unexpected message: %s", sbh.receivedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
type SimpleBroadcastReceiver struct {
|
||||
broadcastHandler pilosa.BroadcastHandler
|
||||
}
|
||||
|
||||
func NewSimpleBroadcastReceiver() *SimpleBroadcastReceiver {
|
||||
return &SimpleBroadcastReceiver{}
|
||||
}
|
||||
|
||||
func (r *SimpleBroadcastReceiver) Start(h pilosa.BroadcastHandler) error {
|
||||
r.broadcastHandler = h
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *SimpleBroadcastReceiver) Receive(pb proto.Message) error {
|
||||
r.broadcastHandler.ReceiveMessage(pb)
|
||||
return nil
|
||||
}
|
||||
|
||||
type SimpleBroadcastHandler struct {
|
||||
receivedMessage proto.Message
|
||||
}
|
||||
|
||||
func NewSimpleBroadcastHandler() *SimpleBroadcastHandler {
|
||||
return &SimpleBroadcastHandler{}
|
||||
}
|
||||
|
||||
func (h *SimpleBroadcastHandler) ReceiveMessage(pb proto.Message) error {
|
||||
h.receivedMessage = pb.(proto.Message)
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
129
handler.go
129
handler.go
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/gorilla/mux"
|
||||
"github.com/pilosa/pilosa/internal"
|
||||
"github.com/pilosa/pilosa/pql"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Handler represents an HTTP handler.
|
||||
|
|
@ -255,55 +256,62 @@ type postDBRequest struct {
|
|||
Options DBOptions `json:"options"`
|
||||
}
|
||||
|
||||
//_postDBRequest is necessary to avoid recursion while decoding.
|
||||
type _postDBRequest postDBRequest
|
||||
|
||||
// Custom Unmarshal JSON to validate request body when creating a new database
|
||||
func (p *postDBRequest) UnmarshalJSON(b []byte) error {
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal(b, &data); err != nil {
|
||||
|
||||
// m is an overflow map used to capture additional, unexpected keys.
|
||||
m := make(map[string]interface{})
|
||||
if err := json.Unmarshal(b, &m); err != nil {
|
||||
return err
|
||||
}
|
||||
for key, value := range data {
|
||||
switch key {
|
||||
case "options":
|
||||
value, err := validateOptions(data, "columnLabel")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value == "" {
|
||||
p.Options = DBOptions{}
|
||||
} else {
|
||||
p.Options = DBOptions{ColumnLabel: value}
|
||||
}
|
||||
|
||||
validDBOptions := getValidOptions(DBOptions{})
|
||||
err := validateOptions(m, validDBOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Unmarshal expected values.
|
||||
var _p _postDBRequest
|
||||
if err := json.Unmarshal(b, &_p); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Options = _p.Options
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Raise errors for any unknown key
|
||||
func validateOptions(data map[string]interface{}, validDBOptions []string) error {
|
||||
for k, v := range data {
|
||||
switch k {
|
||||
case "options":
|
||||
options, ok := v.(map[string]interface{})
|
||||
if !ok {
|
||||
return errors.New("options is not map[string]interface{}")
|
||||
}
|
||||
for kk, vv := range options {
|
||||
if !foundItem(validDBOptions, kk) {
|
||||
return fmt.Errorf("Unknown key: %v:%v", kk, vv)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("Unknown key: %v:%v", key, value)
|
||||
return fmt.Errorf("Unknown key: %v:%v", k, v)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateOptions(data map[string]interface{}, field string) (string, error) {
|
||||
options, ok := data["options"].(map[string]interface{})
|
||||
if !ok {
|
||||
return "", errors.New("options is not map[string]interface{}")
|
||||
}
|
||||
var optionValue string
|
||||
if len(options) == 0 {
|
||||
optionValue = ""
|
||||
} else {
|
||||
for k, v := range options {
|
||||
switch k {
|
||||
case field:
|
||||
val, ok := options[field].(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("invalid option %v: {%v:%v}", field, k, v)
|
||||
}
|
||||
optionValue = val
|
||||
default:
|
||||
return "", fmt.Errorf("invalid key for options {%v:%v}", k, v)
|
||||
}
|
||||
func foundItem(items []string, item string) bool {
|
||||
for _, i := range items {
|
||||
if item == i {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return optionValue, nil
|
||||
return false
|
||||
}
|
||||
|
||||
type postDBResponse struct{}
|
||||
|
|
@ -526,32 +534,45 @@ func (h *Handler) handlePostFrame(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
// Custom Unmarshal JSON to validate request body when creating a new frame
|
||||
type _postFrameRequest postFrameRequest
|
||||
|
||||
// Custom Unmarshal JSON to validate request body when creating a new frame. If there's new FrameOptions,
|
||||
// adding it to validFrameOptions to make sure the new option is validated, otherwise the request will be failed
|
||||
func (p *postFrameRequest) UnmarshalJSON(b []byte) error {
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal(b, &data); err != nil {
|
||||
// m is an overflow map used to capture additional, unexpected keys.
|
||||
m := make(map[string]interface{})
|
||||
if err := json.Unmarshal(b, &m); err != nil {
|
||||
return err
|
||||
}
|
||||
for key, value := range data {
|
||||
switch key {
|
||||
case "options":
|
||||
value, err := validateOptions(data, "rowLabel")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if value == "" {
|
||||
p.Options = FrameOptions{}
|
||||
} else {
|
||||
p.Options = FrameOptions{RowLabel: value}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("Unknown key: {%v:%v}", key, value)
|
||||
}
|
||||
|
||||
validFrameOptions := getValidOptions(FrameOptions{})
|
||||
err := validateOptions(m, validFrameOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Unmarshal expected values.
|
||||
var _p _postFrameRequest
|
||||
if err := json.Unmarshal(b, &_p); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Options = _p.Options
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func getValidOptions(option interface{}) []string {
|
||||
validOptions := []string{}
|
||||
val := reflect.ValueOf(option)
|
||||
for i := 0; i < val.Type().NumField(); i++ {
|
||||
jsonTag := val.Type().Field(i).Tag.Get("json")
|
||||
s := strings.Split(jsonTag, ",")
|
||||
validOptions = append(validOptions, s[0])
|
||||
}
|
||||
return validOptions
|
||||
}
|
||||
|
||||
type postFrameRequest struct {
|
||||
Options FrameOptions `json:"options"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ func TestPostDBRequestUnmarshalJSON(t *testing.T) {
|
|||
{json: `{"options": 4}`, err: "options is not map[string]interface{}"},
|
||||
{json: `{"option": {}}`, err: "Unknown key: option:map[]"},
|
||||
{json: `{"options": {"columnLabel": "test"}}`, expected: postDBRequest{Options: DBOptions{ColumnLabel: "test"}}},
|
||||
{json: `{"options": {"columnLabl": "test"}}`, err: "invalid key for options {columnLabl:test}"},
|
||||
{json: `{"options": {"columnLabl": "test"}}`, err: "Unknown key: columnLabl:test"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := &postDBRequest{}
|
||||
|
|
@ -51,9 +51,12 @@ func TestPostFrameRequestUnmarshalJSON(t *testing.T) {
|
|||
}{
|
||||
{json: `{"options": {}}`, expected: postFrameRequest{Options: FrameOptions{}}},
|
||||
{json: `{"options": 4}`, err: "options is not map[string]interface{}"},
|
||||
{json: `{"option": {}}`, err: "Unknown key: {option:map[]}"},
|
||||
{json: `{"option": {}}`, err: "Unknown key: option:map[]"},
|
||||
{json: `{"options": {"rowLabel": "test"}}`, expected: postFrameRequest{Options: FrameOptions{RowLabel: "test"}}},
|
||||
{json: `{"options": {"rowLabl": "test"}}`, err: "invalid key for options {rowLabl:test}"},
|
||||
{json: `{"options": {"rowLabl": "test"}}`, err: "Unknown key: rowLabl:test"},
|
||||
{json: `{"options": {"rowLabel": "test", "inverseEnabled": true}}`, expected: postFrameRequest{Options: FrameOptions{RowLabel: "test", InverseEnabled: true}}},
|
||||
{json: `{"options": {"rowLabel": "test", "inverseEnabled": true, "cacheType": "type"}}`, expected: postFrameRequest{Options: FrameOptions{RowLabel: "test", InverseEnabled: true, CacheType: "type"}}},
|
||||
{json: `{"options": {"rowLabel": "test", "inverse": true, "cacheType": "type"}}`, err: "Unknown key: inverse:true"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
actual := &postFrameRequest{}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue