From 7dd6e2f9e3725427c628b214cb31bda1dbe95234 Mon Sep 17 00:00:00 2001 From: Shashank Kumar Shankar Date: Tue, 20 Mar 2018 16:48:05 -0700 Subject: Make datastore generic to support Consul/Cassandra This patch makes the backend datastore to be generic so that the backend datastore can be either Consul or Cassandra. This way, MUSIC's core functionality can be used and makes other minor fixes. Change-Id: Iba4eaa751fe60a293d6f2fd60ad06a8c4be1dd1e Issue-ID: MUSIC-55 Signed-off-by: Shashank Kumar Shankar --- src/dkv/api/backendCassandraDatastore.go | 45 ++++++++++ src/dkv/api/backendConsulConnection.go | 133 ----------------------------- src/dkv/api/backendConsulDatastore.go | 111 ++++++++++++++++++++++++ src/dkv/api/backendDatastoreConnection.go | 27 ++++++ src/dkv/api/backendFilesystemConnection.go | 2 - src/dkv/api/backendPropertiesConnection.go | 4 +- src/dkv/api/backendfakes.go | 16 ++++ src/dkv/api/configHandlers_test.go | 36 ++++---- src/dkv/api/initialise.go | 24 +++++- src/dkv/api/initialise_test.go | 39 +++++++-- src/dkv/api/queryConsulHandlers.go | 87 ------------------- src/dkv/api/queryConsulHandlers_test.go | 105 ----------------------- src/dkv/api/queryDatastoreHandlers.go | 87 +++++++++++++++++++ src/dkv/api/queryDatastoreHandlers_test.go | 105 +++++++++++++++++++++++ 14 files changed, 460 insertions(+), 361 deletions(-) create mode 100644 src/dkv/api/backendCassandraDatastore.go delete mode 100644 src/dkv/api/backendConsulConnection.go create mode 100644 src/dkv/api/backendConsulDatastore.go create mode 100644 src/dkv/api/backendDatastoreConnection.go delete mode 100644 src/dkv/api/queryConsulHandlers.go delete mode 100644 src/dkv/api/queryConsulHandlers_test.go create mode 100644 src/dkv/api/queryDatastoreHandlers.go create mode 100644 src/dkv/api/queryDatastoreHandlers_test.go (limited to 'src') diff --git a/src/dkv/api/backendCassandraDatastore.go b/src/dkv/api/backendCassandraDatastore.go new file mode 100644 index 0000000..555ad0f --- /dev/null +++ b/src/dkv/api/backendCassandraDatastore.go @@ -0,0 +1,45 @@ +/* + * Copyright 2018 Intel Corporation, 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 api + +// (TODO)sahank: Complete MUSIC Cassandra Connections. + +type CassandraStruct struct{} + +func (c *CassandraStruct) InitializeDatastoreClient() error { + return nil +} + +func (c *CassandraStruct) CheckDatastoreHealth() error { + return nil +} + +func (c *CassandraStruct) RequestPUT(key string, value string) error { + return nil +} + +func (c *CassandraStruct) RequestGET(key string) (string, error) { + return "", nil +} + +func (c *CassandraStruct) RequestGETS() ([]string, error) { + return []string{"", ""}, nil +} + +func (c *CassandraStruct) RequestDELETE(key string) error { + return nil +} diff --git a/src/dkv/api/backendConsulConnection.go b/src/dkv/api/backendConsulConnection.go deleted file mode 100644 index 9c2f8d6..0000000 --- a/src/dkv/api/backendConsulConnection.go +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2018 Intel Corporation, 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 api - -import ( - "errors" - consulapi "github.com/hashicorp/consul/api" - "os" -) - -// Interface to have all signature methods. -type ConsulRequester interface { - InitializeConsulClient() error - CheckConsulHealth() error - RequestPUT(string, string) error - RequestGET(string) (string, error) - RequestGETS() ([]string, error) - RequestDELETE(string) error -} - -type ConsulStruct struct { - consulClient *consulapi.Client -} - -/* -This var is an interface used to initialize ConsulStruct when the who API is brought up. This is done this way so -that a fake Consul can be created which satisfies the interface and we can use that fake Consul in unit testing. -*/ -var Consul ConsulRequester - -/* -The following functions seems like they are not used. But since they are following the ConsulRequest interface, -they can be visible to any Struct which is initiated using the ConsulRequest. This is done for this project in -the initialise.go file where we are creating a ConsulStruct and assigning it to Consul var which is declared -above. -*/ -func (c *ConsulStruct) InitializeConsulClient() error { - if os.Getenv("CONSUL_IP") == "" { - return errors.New("CONSUL_IP environment variable not set.") - } - config := consulapi.DefaultConfig() - config.Address = os.Getenv("CONSUL_IP") + ":8500" - - client, err := consulapi.NewClient(config) - if err != nil { - return err - } - c.consulClient = client - - return nil -} - -func (c *ConsulStruct) CheckConsulHealth() error { - kv := c.consulClient.KV() - _, _, err := kv.Get("test", nil) - if err != nil { - return errors.New("[ERROR] Cannot talk to Consul. Check if it is running/reachable.") - } - return nil -} - -func (c *ConsulStruct) RequestPUT(key string, value string) error { - - kv := c.consulClient.KV() - - p := &consulapi.KVPair{Key: key, Value: []byte(value)} - - _, err := kv.Put(p, nil) - - if err != nil { - return err - } - - return nil -} - -func (c *ConsulStruct) RequestGET(key string) (string, error) { - - kv := c.consulClient.KV() - - pair, _, err := kv.Get(key, nil) - - if pair == nil { - return string("No value found for key."), err - } - return string(pair.Value), err - -} - -func (c *ConsulStruct) RequestGETS() ([]string, error) { - - kv := c.consulClient.KV() - - pairs, _, err := kv.List("", nil) - - if len(pairs) == 0 { - return []string{"No keys found."}, err - } - - var res []string - - for _, keypair := range pairs { - res = append(res, keypair.Key) - } - - return res, err -} - -func (c *ConsulStruct) RequestDELETE(key string) error { - kv := c.consulClient.KV() - - _, err := kv.Delete(key, nil) - - if err != nil { - return err - } - - return nil -} diff --git a/src/dkv/api/backendConsulDatastore.go b/src/dkv/api/backendConsulDatastore.go new file mode 100644 index 0000000..231980c --- /dev/null +++ b/src/dkv/api/backendConsulDatastore.go @@ -0,0 +1,111 @@ +/* + * Copyright 2018 Intel Corporation, 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 api + +import ( + "errors" + consulapi "github.com/hashicorp/consul/api" + "os" +) + +type ConsulStruct struct { + consulClient *consulapi.Client +} + +func (c *ConsulStruct) InitializeDatastoreClient() error { + if os.Getenv("DATASTORE_IP") == "" { + return errors.New("DATASTORE_IP environment variable not set.") + } + config := consulapi.DefaultConfig() + config.Address = os.Getenv("DATASTORE_IP") + ":8500" + + client, err := consulapi.NewClient(config) + if err != nil { + return err + } + c.consulClient = client + + return nil +} + +func (c *ConsulStruct) CheckDatastoreHealth() error { + kv := c.consulClient.KV() + _, _, err := kv.Get("test", nil) + if err != nil { + return errors.New("[ERROR] Cannot talk to Datastore. Check if it is running/reachable.") + } + return nil +} + +func (c *ConsulStruct) RequestPUT(key string, value string) error { + + kv := c.consulClient.KV() + + p := &consulapi.KVPair{Key: key, Value: []byte(value)} + + _, err := kv.Put(p, nil) + + if err != nil { + return err + } + + return nil +} + +func (c *ConsulStruct) RequestGET(key string) (string, error) { + + kv := c.consulClient.KV() + + pair, _, err := kv.Get(key, nil) + + if pair == nil { + return string("No value found for key."), err + } + return string(pair.Value), err + +} + +func (c *ConsulStruct) RequestGETS() ([]string, error) { + + kv := c.consulClient.KV() + + pairs, _, err := kv.List("", nil) + + if len(pairs) == 0 { + return []string{"No keys found."}, err + } + + var res []string + + for _, keypair := range pairs { + res = append(res, keypair.Key) + } + + return res, err +} + +func (c *ConsulStruct) RequestDELETE(key string) error { + kv := c.consulClient.KV() + + _, err := kv.Delete(key, nil) + + if err != nil { + return err + } + + return nil +} diff --git a/src/dkv/api/backendDatastoreConnection.go b/src/dkv/api/backendDatastoreConnection.go new file mode 100644 index 0000000..ebfcc4b --- /dev/null +++ b/src/dkv/api/backendDatastoreConnection.go @@ -0,0 +1,27 @@ +/* + * Copyright 2018 Intel Corporation, 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 api + +// Interface to have Data Store signature methods. +type DatastoreConnector interface { + InitializeDatastoreClient() error + CheckDatastoreHealth() error + RequestPUT(string, string) error + RequestGET(string) (string, error) + RequestGETS() ([]string, error) + RequestDELETE(string) error +} diff --git a/src/dkv/api/backendFilesystemConnection.go b/src/dkv/api/backendFilesystemConnection.go index e6c37ab..519022c 100644 --- a/src/dkv/api/backendFilesystemConnection.go +++ b/src/dkv/api/backendFilesystemConnection.go @@ -49,8 +49,6 @@ const ( var MOUNTPATH = "" -var Directory DirectoryOperationer - func (d *DirectoryStruct) CreateService(body CreateRegisterServiceBody) (string, error) { // Having same name is prohibited? diff --git a/src/dkv/api/backendPropertiesConnection.go b/src/dkv/api/backendPropertiesConnection.go index d485b40..df9683b 100644 --- a/src/dkv/api/backendPropertiesConnection.go +++ b/src/dkv/api/backendPropertiesConnection.go @@ -34,8 +34,6 @@ type KeyValuesInterface interface { type KeyValuesStruct struct{} -var KeyValues KeyValuesInterface - func (kvStruct *KeyValuesStruct) WriteKVsToConsul(token string, subdomain string, kvs map[string]string) error { var prefix = "" if subdomain != "" { @@ -45,7 +43,7 @@ func (kvStruct *KeyValuesStruct) WriteKVsToConsul(token string, subdomain string } for key, value := range kvs { key = prefix + key - err := Consul.RequestPUT(key, value) + err := Datastore.RequestPUT(key, value) if err != nil { return err } diff --git a/src/dkv/api/backendfakes.go b/src/dkv/api/backendfakes.go index c5ca39a..8c8b8a9 100644 --- a/src/dkv/api/backendfakes.go +++ b/src/dkv/api/backendfakes.go @@ -31,6 +31,14 @@ type FakeConsul struct { ConsulStruct } +func (f *FakeConsul) InitializeDatastoreClient() error { + return nil +} + +func (f *FakeConsul) CheckDatastoreHealth() error { + return nil +} + func (f *FakeConsul) RequestGETS() ([]string, error) { return []string{"key1", "key2"}, nil } @@ -52,6 +60,14 @@ type FakeConsulErr struct { ConsulStruct } +func (f *FakeConsulErr) InitializeDatastoreClient() error { + return errors.New("Internal Server Error") +} + +func (f *FakeConsulErr) CheckDatastoreHealth() error { + return errors.New("Internal Server Error") +} + func (f *FakeConsulErr) RequestGETS() ([]string, error) { return []string{"", ""}, errors.New("Internal Server Error") } diff --git a/src/dkv/api/configHandlers_test.go b/src/dkv/api/configHandlers_test.go index e2f796a..bb11eb1 100644 --- a/src/dkv/api/configHandlers_test.go +++ b/src/dkv/api/configHandlers_test.go @@ -75,14 +75,14 @@ func TestHandleConfigDelete_err(t *testing.T) { } func TestHandleConfigPOST(t *testing.T) { - oldConsul := Consul + oldDatastore := Datastore oldKeyValues := KeyValues - Consul = &FakeConsul{} + Datastore = &FakeConsul{} KeyValues = &FakeKeyValues{} defer func() { - Consul = oldConsul + Datastore = oldDatastore KeyValues = oldKeyValues }() @@ -104,14 +104,14 @@ func TestHandleConfigPOST(t *testing.T) { } func TestHandleConfigPOST_only_token(t *testing.T) { - oldConsul := Consul + oldDatastore := Datastore oldKeyValues := KeyValues - Consul = &FakeConsul{} + Datastore = &FakeConsul{} KeyValues = &FakeKeyValues{} defer func() { - Consul = oldConsul + Datastore = oldDatastore KeyValues = oldKeyValues }() @@ -133,14 +133,14 @@ func TestHandleConfigPOST_only_token(t *testing.T) { } func TestHandleConfigPOST_no_body(t *testing.T) { - oldConsul := Consul + oldDatastore := Datastore oldKeyValues := KeyValues - Consul = &FakeConsul{} + Datastore = &FakeConsul{} KeyValues = &FakeKeyValues{} defer func() { - Consul = oldConsul + Datastore = oldDatastore KeyValues = oldKeyValues }() @@ -156,14 +156,14 @@ func TestHandleConfigPOST_no_body(t *testing.T) { } func TestHandleConfigPOST_ConsulError(t *testing.T) { - oldConsul := Consul + oldDatastore := Datastore oldKeyValues := KeyValues - Consul = &FakeConsulErr{} + Datastore = &FakeConsulErr{} KeyValues = &FakeKeyValuesErr{} defer func() { - Consul = oldConsul + Datastore = oldDatastore KeyValues = oldKeyValues }() @@ -196,14 +196,14 @@ func TestHandleConfigUpload_err(t *testing.T) { } func TestHandleDefaultConfigLoad(t *testing.T) { - oldConsul := Consul + oldDatastore := Datastore oldKeyValues := KeyValues - Consul = &FakeConsul{} + Datastore = &FakeConsul{} KeyValues = &FakeKeyValues{} defer func() { - Consul = oldConsul + Datastore = oldDatastore KeyValues = oldKeyValues }() @@ -215,14 +215,14 @@ func TestHandleDefaultConfigLoad(t *testing.T) { } func TestHandleDefaultConfigLoad_err(t *testing.T) { - oldConsul := Consul + oldDatastore := Datastore oldKeyValues := KeyValues - Consul = &FakeConsul{} + Datastore = &FakeConsul{} KeyValues = &FakeKeyValuesErr{} defer func() { - Consul = oldConsul + Datastore = oldDatastore KeyValues = oldKeyValues }() diff --git a/src/dkv/api/initialise.go b/src/dkv/api/initialise.go index f4edc6c..20a5df4 100644 --- a/src/dkv/api/initialise.go +++ b/src/dkv/api/initialise.go @@ -16,19 +16,35 @@ package api -import "os" +import ( + "errors" + "os" +) + +var ( + Datastore DatastoreConnector + KeyValues KeyValuesInterface + Directory DirectoryOperationer +) func Initialise() error { - Consul = &ConsulStruct{} + if os.Getenv("DATASTORE") == "" { + return errors.New("DATASTORE environment variable not set.") + } + if os.Getenv("DATASTORE") == "consul" { + Datastore = &ConsulStruct{} + } else if os.Getenv("DATASTORE") == "cassandra" { + Datastore = &CassandraStruct{} + } KeyValues = &KeyValuesStruct{} Directory = &DirectoryStruct{directory: ""} - err := Consul.InitializeConsulClient() + err := Datastore.InitializeDatastoreClient() if err != nil { return err } - err = Consul.CheckConsulHealth() + err = Datastore.CheckDatastoreHealth() if err != nil { return err } diff --git a/src/dkv/api/initialise_test.go b/src/dkv/api/initialise_test.go index 3063201..363edce 100644 --- a/src/dkv/api/initialise_test.go +++ b/src/dkv/api/initialise_test.go @@ -22,20 +22,41 @@ import ( "testing" ) -func TestInitialise_errorIP(t *testing.T) { - consul_ip := os.Getenv("CONSUL_IP") - os.Unsetenv("CONSUL_IP") - defer os.Setenv("CONSUL_IP", consul_ip) +func TestInitialise_cassandra(t *testing.T) { + oldDatastore_ip := os.Getenv("DATASTORE_IP") + oldDatastore_type := os.Getenv("DATASTORE") + + os.Setenv("DATASTORE_IP", "localhost") + os.Setenv("DATASTORE", "cassandra") + + defer func() { + os.Setenv("DATASTORE_IP", oldDatastore_ip) + os.Setenv("DATASTORE", oldDatastore_type) + }() + + err := Initialise() + assert.Nil(t, err) +} +func TestInitialise_consulError(t *testing.T) { + oldDatastore_ip := os.Getenv("DATASTORE_IP") + oldDatastore_type := os.Getenv("DATASTORE") + + os.Setenv("DATASTORE_IP", "localhost") + os.Setenv("DATASTORE", "consul") + + defer func() { + os.Setenv("DATASTORE_IP", oldDatastore_ip) + os.Setenv("DATASTORE", oldDatastore_type) + }() err := Initialise() assert.NotNil(t, err) } -func TestInitialise_errorConsul(t *testing.T) { - // This is done this way cause the Consul interface with Fake Struct will get - // overridden with real Struct during runtime. - os.Setenv("CONSUL_IP", "test") - defer os.Unsetenv("CONSUL_IP") +func TestInitialise_datastoreEmptyError(t *testing.T) { + datastore := os.Getenv("DATASTORE") + os.Unsetenv("DATASTORE") + defer os.Setenv("DATASTORE", datastore) err := Initialise() assert.NotNil(t, err) diff --git a/src/dkv/api/queryConsulHandlers.go b/src/dkv/api/queryConsulHandlers.go deleted file mode 100644 index fb63b6d..0000000 --- a/src/dkv/api/queryConsulHandlers.go +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2018 Intel Corporation, 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 api - -import ( - "encoding/json" - "github.com/gorilla/mux" - "net/http" -) - -type ResponseStringStruct struct { - Response string `json:"response"` -} - -type ResponseGETStruct struct { - Response map[string]string `json:"response"` -} - -type ResponseGETSStruct struct { - Response []string `json:"response"` -} - -func HandleGET(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - key := vars["token"] + "/" + vars["key"] - - value, err := Consul.RequestGET(key) - - if err != nil { - req := ResponseStringStruct{Response: string(err.Error())} - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusBadRequest) - json.NewEncoder(w).Encode(req) - } else { - req := ResponseGETStruct{Response: map[string]string{key: value}} - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(req) - } -} - -func HandleGETS(w http.ResponseWriter, r *http.Request) { - - values, err := Consul.RequestGETS() - - if err != nil { - req := ResponseStringStruct{Response: string(err.Error())} - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusBadRequest) - json.NewEncoder(w).Encode(req) - } else { - req := ResponseGETSStruct{Response: values} - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(req) - } -} - -func HandleDELETE(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - key := vars["key"] - - err := Consul.RequestDELETE(key) - - if err != nil { - req := ResponseStringStruct{Response: string(err.Error())} - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusBadRequest) - json.NewEncoder(w).Encode(req) - } else { - req := ResponseStringStruct{Response: "Key deletion successful."} - w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(&req) - } -} diff --git a/src/dkv/api/queryConsulHandlers_test.go b/src/dkv/api/queryConsulHandlers_test.go deleted file mode 100644 index 38f3acd..0000000 --- a/src/dkv/api/queryConsulHandlers_test.go +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2018 Intel Corporation, 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 api - -import ( - "github.com/gorilla/mux" - "github.com/stretchr/testify/assert" - "net/http" - "net/http/httptest" - "testing" -) - -func RouterConsul() *mux.Router { - router := mux.NewRouter() - router.HandleFunc("/v1/getconfig/{key}", HandleGET).Methods("GET") - router.HandleFunc("/v1/deleteconfig/{key}", HandleDELETE).Methods("DELETE") - router.HandleFunc("/v1/getconfigs", HandleGETS).Methods("GET") - return router -} - -func TestHandleGETS(t *testing.T) { - oldConsul := Consul - Consul = &FakeConsul{} - defer func() { Consul = oldConsul }() - - request, _ := http.NewRequest("GET", "/v1/getconfigs", nil) - response := httptest.NewRecorder() - RouterConsul().ServeHTTP(response, request) - - assert.Equal(t, 200, response.Code, "200 response is expected") -} - -func TestHandleGETS_err(t *testing.T) { - oldConsul := Consul - Consul = &FakeConsulErr{} - defer func() { Consul = oldConsul }() - - request, _ := http.NewRequest("GET", "/v1/getconfigs", nil) - response := httptest.NewRecorder() - RouterConsul().ServeHTTP(response, request) - - assert.Equal(t, 400, response.Code, "400 response is expected") -} - -func TestHandleGET(t *testing.T) { - oldConsul := Consul - Consul = &FakeConsul{} - defer func() { Consul = oldConsul }() - - request, _ := http.NewRequest("GET", "/v1/getconfig/key1", nil) - response := httptest.NewRecorder() - RouterConsul().ServeHTTP(response, request) - - assert.Equal(t, 200, response.Code, "200 response is expected") -} - -func TestHandleGET_err(t *testing.T) { - oldConsul := Consul - Consul = &FakeConsulErr{} - defer func() { Consul = oldConsul }() - - request, _ := http.NewRequest("GET", "/v1/getconfig/key1", nil) - response := httptest.NewRecorder() - RouterConsul().ServeHTTP(response, request) - - assert.Equal(t, 400, response.Code, "400 response is expected") -} - -func TestHandleDELETE(t *testing.T) { - oldConsul := Consul - Consul = &FakeConsul{} - defer func() { Consul = oldConsul }() - - request, _ := http.NewRequest("DELETE", "/v1/deleteconfig/key1", nil) - response := httptest.NewRecorder() - RouterConsul().ServeHTTP(response, request) - - assert.Equal(t, 200, response.Code, "200 response is expected") -} - -func TestHandleDELETE_err(t *testing.T) { - oldConsul := Consul - Consul = &FakeConsulErr{} - defer func() { Consul = oldConsul }() - - request, _ := http.NewRequest("DELETE", "/v1/deleteconfig/key1", nil) - response := httptest.NewRecorder() - RouterConsul().ServeHTTP(response, request) - - assert.Equal(t, 400, response.Code, "400 response is expected") -} diff --git a/src/dkv/api/queryDatastoreHandlers.go b/src/dkv/api/queryDatastoreHandlers.go new file mode 100644 index 0000000..4197ac0 --- /dev/null +++ b/src/dkv/api/queryDatastoreHandlers.go @@ -0,0 +1,87 @@ +/* + * Copyright 2018 Intel Corporation, 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 api + +import ( + "encoding/json" + "github.com/gorilla/mux" + "net/http" +) + +type ResponseStringStruct struct { + Response string `json:"response"` +} + +type ResponseGETStruct struct { + Response map[string]string `json:"response"` +} + +type ResponseGETSStruct struct { + Response []string `json:"response"` +} + +func HandleGET(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + key := vars["token"] + "/" + vars["key"] + + value, err := Datastore.RequestGET(key) + + if err != nil { + req := ResponseStringStruct{Response: string(err.Error())} + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusBadRequest) + json.NewEncoder(w).Encode(req) + } else { + req := ResponseGETStruct{Response: map[string]string{key: value}} + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(req) + } +} + +func HandleGETS(w http.ResponseWriter, r *http.Request) { + + values, err := Datastore.RequestGETS() + + if err != nil { + req := ResponseStringStruct{Response: string(err.Error())} + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusBadRequest) + json.NewEncoder(w).Encode(req) + } else { + req := ResponseGETSStruct{Response: values} + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(req) + } +} + +func HandleDELETE(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + key := vars["key"] + + err := Datastore.RequestDELETE(key) + + if err != nil { + req := ResponseStringStruct{Response: string(err.Error())} + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusBadRequest) + json.NewEncoder(w).Encode(req) + } else { + req := ResponseStringStruct{Response: "Key deletion successful."} + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(&req) + } +} diff --git a/src/dkv/api/queryDatastoreHandlers_test.go b/src/dkv/api/queryDatastoreHandlers_test.go new file mode 100644 index 0000000..c6211bc --- /dev/null +++ b/src/dkv/api/queryDatastoreHandlers_test.go @@ -0,0 +1,105 @@ +/* + * Copyright 2018 Intel Corporation, 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 api + +import ( + "github.com/gorilla/mux" + "github.com/stretchr/testify/assert" + "net/http" + "net/http/httptest" + "testing" +) + +func RouterConsul() *mux.Router { + router := mux.NewRouter() + router.HandleFunc("/v1/getconfig/{key}", HandleGET).Methods("GET") + router.HandleFunc("/v1/deleteconfig/{key}", HandleDELETE).Methods("DELETE") + router.HandleFunc("/v1/getconfigs", HandleGETS).Methods("GET") + return router +} + +func TestHandleGETS(t *testing.T) { + oldDataStore := Datastore + Datastore = &FakeConsul{} + defer func() { Datastore = oldDataStore }() + + request, _ := http.NewRequest("GET", "/v1/getconfigs", nil) + response := httptest.NewRecorder() + RouterConsul().ServeHTTP(response, request) + + assert.Equal(t, 200, response.Code, "200 response is expected") +} + +func TestHandleGETS_err(t *testing.T) { + oldDataStore := Datastore + Datastore = &FakeConsulErr{} + defer func() { Datastore = oldDataStore }() + + request, _ := http.NewRequest("GET", "/v1/getconfigs", nil) + response := httptest.NewRecorder() + RouterConsul().ServeHTTP(response, request) + + assert.Equal(t, 400, response.Code, "400 response is expected") +} + +func TestHandleGET(t *testing.T) { + oldDataStore := Datastore + Datastore = &FakeConsul{} + defer func() { Datastore = oldDataStore }() + + request, _ := http.NewRequest("GET", "/v1/getconfig/key1", nil) + response := httptest.NewRecorder() + RouterConsul().ServeHTTP(response, request) + + assert.Equal(t, 200, response.Code, "200 response is expected") +} + +func TestHandleGET_err(t *testing.T) { + oldDataStore := Datastore + Datastore = &FakeConsulErr{} + defer func() { Datastore = oldDataStore }() + + request, _ := http.NewRequest("GET", "/v1/getconfig/key1", nil) + response := httptest.NewRecorder() + RouterConsul().ServeHTTP(response, request) + + assert.Equal(t, 400, response.Code, "400 response is expected") +} + +func TestHandleDELETE(t *testing.T) { + oldDataStore := Datastore + Datastore = &FakeConsul{} + defer func() { Datastore = oldDataStore }() + + request, _ := http.NewRequest("DELETE", "/v1/deleteconfig/key1", nil) + response := httptest.NewRecorder() + RouterConsul().ServeHTTP(response, request) + + assert.Equal(t, 200, response.Code, "200 response is expected") +} + +func TestHandleDELETE_err(t *testing.T) { + oldDataStore := Datastore + Datastore = &FakeConsulErr{} + defer func() { Datastore = oldDataStore }() + + request, _ := http.NewRequest("DELETE", "/v1/deleteconfig/key1", nil) + response := httptest.NewRecorder() + RouterConsul().ServeHTTP(response, request) + + assert.Equal(t, 400, response.Code, "400 response is expected") +} -- cgit 1.2.3-korg