From 3e92cb38f9be554afccf7ac409dfbedbeec769a2 Mon Sep 17 00:00:00 2001 From: Shashank Kumar Shankar Date: Thu, 15 Feb 2018 14:48:19 -0800 Subject: Update tests and refactor code This patch adds some more tests and refactors the codebase. Change-Id: Iee669b85c5c7f9bdd01271fe86df20506f567d23 Issue-ID: MUSIC-23 Signed-off-by: Shashank Kumar Shankar --- src/dkv/Gopkg.lock | 8 +- src/dkv/api/consulConnection.go | 107 +++++++++++--------- src/dkv/api/consulConnection_test.go | 2 - src/dkv/api/endpointViews.go | 59 ++++++++++-- src/dkv/api/endpointViews_fake.go | 96 ++++++++++++++++++ src/dkv/api/endpointViews_test.go | 182 ++++++++++++++++++++++++++++++++--- src/dkv/api/initialise.go | 27 ++++++ src/dkv/api/initialise_test.go | 42 ++++++++ src/dkv/api/propertiesReader.go | 84 +++++++++++----- src/dkv/api/utils.go | 101 ------------------- src/dkv/api/utils_test.go | 19 ---- src/dkv/main.go | 11 ++- swagger.json | 24 +++++ 13 files changed, 551 insertions(+), 211 deletions(-) create mode 100644 src/dkv/api/endpointViews_fake.go create mode 100644 src/dkv/api/initialise.go create mode 100644 src/dkv/api/initialise_test.go delete mode 100644 src/dkv/api/utils.go delete mode 100644 src/dkv/api/utils_test.go diff --git a/src/dkv/Gopkg.lock b/src/dkv/Gopkg.lock index 33c42f6..97abfee 100644 --- a/src/dkv/Gopkg.lock +++ b/src/dkv/Gopkg.lock @@ -13,6 +13,12 @@ revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a" version = "v1.1" +[[projects]] + name = "github.com/gorilla/handlers" + packages = ["."] + revision = "90663712d74cb411cbef281bc1e08c19d1a76145" + version = "v1.3.0" + [[projects]] name = "github.com/gorilla/mux" packages = ["."] @@ -70,6 +76,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "b980f85326f4b80746ec5b571cb1d39ebd88faba4028d4000bb84775aef0470f" + inputs-digest = "da4b4bdf45858b18ffddcdd32894f4af272104c2501a5334bf1d01abfa6d9a23" solver-name = "gps-cdcl" solver-version = 1 diff --git a/src/dkv/api/consulConnection.go b/src/dkv/api/consulConnection.go index b8074e2..5ea79fd 100644 --- a/src/dkv/api/consulConnection.go +++ b/src/dkv/api/consulConnection.go @@ -18,55 +18,66 @@ package api import ( "errors" - "fmt" - "github.com/hashicorp/consul/api" + consulapi "github.com/hashicorp/consul/api" "os" ) -func (kvStruct *KeyValue) WriteKVsToConsul() error { - for key, value := range kvStruct.kv { - if os.Getenv("CONSUL_IP") == "" { - return errors.New("CONSUL_IP environment variable not set.") - } - err := requestPUT(os.Getenv("CONSUL_IP"), key, value) - if err != nil { - return err - } - fmt.Println("key:", key, "value", value) - } - fmt.Println("Wrote KVs to Consul") - return nil +// 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 } -func GetKVFromConsul(key string) (string, error) { - if os.Getenv("CONSUL_IP") == "" { - return "", errors.New("CONSUL_IP environment variable not set.") - } - resp, err := requestGET(os.Getenv("CONSUL_IP"), key) - return resp, err +type ConsulStruct struct { + consulClient *consulapi.Client } -func GetKVsFromConsul() ([]string, error) { - if os.Getenv("CONSUL_IP") == "" { - return []string{""}, errors.New("CONSUL_IP environment variable not set.") +/* +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 { + config := consulapi.DefaultConfig() + config.Address = os.Getenv("CONSUL_IP") + ":8500" + + client, err := consulapi.NewClient(config) + if err != nil { + return err } - resp, err := requestGETS(os.Getenv("CONSUL_IP")) - return resp, err -} + c.consulClient = client -func requestPUT(url string, key string, value string) error { - config := api.DefaultConfig() - config.Address = url + ":8500" - client, err := api.NewClient(config) + return nil +} +func (c *ConsulStruct) CheckConsulHealth() error { + kv := c.consulClient.KV() + _, _, err := kv.Get("test", nil) if err != nil { - return err + 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)} - kv := client.KV() + _, err := kv.Put(p, nil) - p := &api.KVPair{Key: key, Value: []byte(value)} - _, err = kv.Put(p, nil) if err != nil { return err } @@ -74,12 +85,9 @@ func requestPUT(url string, key string, value string) error { return nil } -func requestGET(url string, key string) (string, error) { - config := api.DefaultConfig() - config.Address = url + ":8500" - client, err := api.NewClient(config) +func (c *ConsulStruct) RequestGET(key string) (string, error) { - kv := client.KV() + kv := c.consulClient.KV() pair, _, err := kv.Get(key, nil) @@ -90,12 +98,9 @@ func requestGET(url string, key string) (string, error) { } -func requestGETS(url string) ([]string, error) { - config := api.DefaultConfig() - config.Address = url + ":8500" - client, err := api.NewClient(config) +func (c *ConsulStruct) RequestGETS() ([]string, error) { - kv := client.KV() + kv := c.consulClient.KV() pairs, _, err := kv.List("", nil) @@ -111,3 +116,15 @@ func requestGETS(url string) ([]string, error) { 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/consulConnection_test.go b/src/dkv/api/consulConnection_test.go index 342542a..cc973ce 100644 --- a/src/dkv/api/consulConnection_test.go +++ b/src/dkv/api/consulConnection_test.go @@ -15,5 +15,3 @@ */ package api - -// TODO(sshank) diff --git a/src/dkv/api/endpointViews.go b/src/dkv/api/endpointViews.go index 3c47ee5..7d19a6a 100644 --- a/src/dkv/api/endpointViews.go +++ b/src/dkv/api/endpointViews.go @@ -18,15 +18,44 @@ package api import ( "encoding/json" + "errors" "github.com/gorilla/mux" "net/http" ) -var getkvs = GetKVsFromConsul +type ResponseStringStruct struct { + Response string `json:"response"` +} + +type ResponseGETStruct struct { + Response map[string]string `json:"response"` +} + +type ResponseGETSStruct struct { + Response []string `json:"response"` +} + +type POSTBodyStruct struct { + Type *TypeStruct `json:"type"` +} + +type TypeStruct struct { + FilePath string `json:"file_path"` +} + +func ValidateBody(body POSTBodyStruct) error { + if body.Type == nil { + return errors.New("Type not set. Recheck POST data.") + } else if body.Type.FilePath == "" { + return errors.New("file_path not set") + } else { + return nil + } +} func HandlePOST(w http.ResponseWriter, r *http.Request) { - var body LoadStruct + var body POSTBodyStruct decoder := json.NewDecoder(r.Body) err := decoder.Decode(&body) @@ -49,7 +78,7 @@ func HandlePOST(w http.ResponseWriter, r *http.Request) { return } - err = KVStruct.ReadConfigs(body) + err = KeyValues.ReadConfigs(body) if err != nil { req := ResponseStringStruct{Response: string(err.Error())} @@ -59,7 +88,7 @@ func HandlePOST(w http.ResponseWriter, r *http.Request) { return } - err = KVStruct.WriteKVsToConsul() + err = KeyValues.WriteKVsToConsul() if err != nil { req := ResponseStringStruct{Response: string(err.Error())} @@ -77,7 +106,7 @@ func HandleGET(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) key := vars["key"] - value, err := GetKVFromConsul(key) + value, err := Consul.RequestGET(key) if err != nil { req := ResponseStringStruct{Response: string(err.Error())} @@ -93,7 +122,7 @@ func HandleGET(w http.ResponseWriter, r *http.Request) { func HandleGETS(w http.ResponseWriter, r *http.Request) { - values, err := getkvs() + values, err := Consul.RequestGETS() if err != nil { req := ResponseStringStruct{Response: string(err.Error())} @@ -106,3 +135,21 @@ func HandleGETS(w http.ResponseWriter, r *http.Request) { 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/endpointViews_fake.go b/src/dkv/api/endpointViews_fake.go new file mode 100644 index 0000000..c147673 --- /dev/null +++ b/src/dkv/api/endpointViews_fake.go @@ -0,0 +1,96 @@ +/* + * 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" + +/* +A ConsulStruct is added inside this so that FakeConsul becomes an implementation of the Consul interface. +If we don't add ConsulStruct inside this, it complains that the FakeConsul Struct doesn't implement all the methods +defined in Consul interface. +*/ +// Correct +type FakeConsul struct { + ConsulStruct +} + +func (f *FakeConsul) RequestGETS() ([]string, error) { + return []string{"key1", "key2"}, nil +} + +func (f *FakeConsul) RequestGET(key string) (string, error) { + return key, nil +} + +func (f *FakeConsul) RequestPUT(key string, value string) error { + return nil +} + +func (f *FakeConsul) RequestDELETE(key string) error { + return nil +} + +// Error +type FakeConsulErr struct { + ConsulStruct +} + +func (f *FakeConsulErr) RequestGETS() ([]string, error) { + return []string{"", ""}, errors.New("Internal Server Error") +} + +func (f *FakeConsulErr) RequestGET(key string) (string, error) { + return "", errors.New("Internal Server Error") +} + +func (f *FakeConsulErr) RequestPUT(key string, value string) error { + return errors.New("Internal Server Error") +} + +func (f *FakeConsulErr) RequestDELETE(key string) error { + return errors.New("Internal Server Error") +} + +/* +This is done similar to the fake Consul above to pass FakeKeyValues to the interface and control method's outputs +as required. +*/ +//Correct +type FakeKeyValues struct { + KeyValuesStruct +} + +func (f *FakeKeyValues) ReadConfigs(body POSTBodyStruct) error { + return nil +} + +func (f *FakeKeyValues) WriteKVsToConsul() error { + return nil +} + +// Error +type FakeKeyValuesErr struct { + KeyValuesStruct +} + +func (f *FakeKeyValuesErr) ReadConfigs(body POSTBodyStruct) error { + return errors.New("Internal Server Error") +} + +func (f *FakeKeyValuesErr) WriteKVsToConsul() error { + return errors.New("Internal Server Error") +} diff --git a/src/dkv/api/endpointViews_test.go b/src/dkv/api/endpointViews_test.go index f603af4..1f7abf3 100644 --- a/src/dkv/api/endpointViews_test.go +++ b/src/dkv/api/endpointViews_test.go @@ -17,7 +17,8 @@ package api import ( - //"encoding/json" + "bytes" + "encoding/json" "github.com/gorilla/mux" "github.com/stretchr/testify/assert" "net/http" @@ -27,32 +28,185 @@ import ( func Router() *mux.Router { router := mux.NewRouter() - router.HandleFunc("/getconfigs", HandleGETS).Methods("GET") router.HandleFunc("/loadconfigs", HandlePOST).Methods("POST") + router.HandleFunc("/getconfig/{key}", HandleGET).Methods("GET") + router.HandleFunc("/deleteconfig/{key}", HandleDELETE).Methods("DELETE") + router.HandleFunc("/getconfigs", HandleGETS).Methods("GET") return router } -func TestHandlePOST(t *testing.T) { - // TODO(sshank) - assert.Equal(t, 0, 0, "Not passed.") +func TestHandleGETS(t *testing.T) { + oldConsul := Consul + Consul = &FakeConsul{} + defer func() { Consul = oldConsul }() + + request, _ := http.NewRequest("GET", "/getconfigs", nil) + response := httptest.NewRecorder() + Router().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", "/getconfigs", nil) + response := httptest.NewRecorder() + Router().ServeHTTP(response, request) + + assert.Equal(t, 400, response.Code, "400 response is expected") } func TestHandleGET(t *testing.T) { - // TODO(sshank) - assert.Equal(t, 0, 0, "Not passed.") + oldConsul := Consul + Consul = &FakeConsul{} + defer func() { Consul = oldConsul }() + + request, _ := http.NewRequest("GET", "/getconfig/key1", nil) + response := httptest.NewRecorder() + Router().ServeHTTP(response, request) + + assert.Equal(t, 200, response.Code, "200 response is expected") } -func TestHandleGETS(t *testing.T) { - getkvOld := getkvs - defer func() { getkvs = getkvOld }() +func TestHandleGET_err(t *testing.T) { + oldConsul := Consul + Consul = &FakeConsulErr{} + defer func() { Consul = oldConsul }() + + request, _ := http.NewRequest("GET", "/getconfig/key1", nil) + response := httptest.NewRecorder() + Router().ServeHTTP(response, request) + + assert.Equal(t, 400, response.Code, "400 response is expected") +} + +func TestHandlePOST(t *testing.T) { + oldConsul := Consul + oldKeyValues := KeyValues + + Consul = &FakeConsul{} + KeyValues = &FakeKeyValues{} - getkvs = func() ([]string, error) { - return nil, nil + defer func() { + Consul = oldConsul + KeyValues = oldKeyValues + }() + + body := &POSTBodyStruct{ + Type: &TypeStruct{ + FilePath: "default", + }, } - request, _ := http.NewRequest("GET", "/getconfigs", nil) + b, _ := json.Marshal(body) + + // json Marshal converts struct to json in Bytes. But bytes doesn't have + // io reader needed. So the byte is passed to NewBuffer. + request, _ := http.NewRequest("POST", "/loadconfigs", bytes.NewBuffer(b)) + response := httptest.NewRecorder() + Router().ServeHTTP(response, request) + + assert.Equal(t, 200, response.Code, "200 response is expected") +} + +func TestHandlePOST_no_body(t *testing.T) { + oldConsul := Consul + oldKeyValues := KeyValues + + Consul = &FakeConsul{} + KeyValues = &FakeKeyValues{} + + defer func() { + Consul = oldConsul + KeyValues = oldKeyValues + }() + + body := &POSTBodyStruct{} + + b, _ := json.Marshal(body) + + request, _ := http.NewRequest("POST", "/loadconfigs", bytes.NewBuffer(b)) + response := httptest.NewRecorder() + Router().ServeHTTP(response, request) + + assert.Equal(t, 400, response.Code, "400 response is expected") +} + +func TestHandlePOST_no_filepath(t *testing.T) { + oldConsul := Consul + oldKeyValues := KeyValues + + Consul = &FakeConsul{} + KeyValues = &FakeKeyValues{} + + defer func() { + Consul = oldConsul + KeyValues = oldKeyValues + }() + + body := &POSTBodyStruct{ + Type: &TypeStruct{}, + } + + b, _ := json.Marshal(body) + + request, _ := http.NewRequest("POST", "/loadconfigs", bytes.NewBuffer(b)) + response := httptest.NewRecorder() + Router().ServeHTTP(response, request) + + assert.Equal(t, 400, response.Code, "400 response is expected") +} + +func TestHandlePOST_ConsulError(t *testing.T) { + oldConsul := Consul + oldKeyValues := KeyValues + + Consul = &FakeConsulErr{} + KeyValues = &FakeKeyValuesErr{} + + defer func() { + Consul = oldConsul + KeyValues = oldKeyValues + }() + + body := &POSTBodyStruct{ + Type: &TypeStruct{ + FilePath: "default", + }, + } + + b, _ := json.Marshal(body) + + request, _ := http.NewRequest("POST", "/loadconfigs", bytes.NewBuffer(b)) + response := httptest.NewRecorder() + Router().ServeHTTP(response, request) + + assert.Equal(t, 500, response.Code, "500 response is expected") +} + +func TestHandleDELETE(t *testing.T) { + oldConsul := Consul + Consul = &FakeConsul{} + defer func() { Consul = oldConsul }() + + request, _ := http.NewRequest("DELETE", "/deleteconfig/key1", nil) + response := httptest.NewRecorder() + Router().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", "/deleteconfig/key1", nil) response := httptest.NewRecorder() Router().ServeHTTP(response, request) - assert.Equal(t, 200, response.Code, "OK response is expected") + assert.Equal(t, 400, response.Code, "400 response is expected") } diff --git a/src/dkv/api/initialise.go b/src/dkv/api/initialise.go new file mode 100644 index 0000000..f85c146 --- /dev/null +++ b/src/dkv/api/initialise.go @@ -0,0 +1,27 @@ +package api + +import ( + "errors" + "os" +) + +func Initialise() error { + if os.Getenv("CONSUL_IP") == "" { + return errors.New("CONSUL_IP environment variable not set.") + } + + Consul = &ConsulStruct{} + KeyValues = &KeyValuesStruct{kvs: make(map[string]string)} + + err := Consul.InitializeConsulClient() + if err != nil { + return err + } + + err = Consul.CheckConsulHealth() + if err != nil { + return err + } + + return nil +} diff --git a/src/dkv/api/initialise_test.go b/src/dkv/api/initialise_test.go new file mode 100644 index 0000000..3063201 --- /dev/null +++ b/src/dkv/api/initialise_test.go @@ -0,0 +1,42 @@ +/* + * 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/stretchr/testify/assert" + "os" + "testing" +) + +func TestInitialise_errorIP(t *testing.T) { + consul_ip := os.Getenv("CONSUL_IP") + os.Unsetenv("CONSUL_IP") + defer os.Setenv("CONSUL_IP", consul_ip) + + 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") + + err := Initialise() + assert.NotNil(t, err) +} diff --git a/src/dkv/api/propertiesReader.go b/src/dkv/api/propertiesReader.go index 018dabe..a1c94bb 100644 --- a/src/dkv/api/propertiesReader.go +++ b/src/dkv/api/propertiesReader.go @@ -20,54 +20,94 @@ import ( "errors" "github.com/magiconair/properties" "io/ioutil" + "log" "path" "runtime" + "sync" ) -func PropertiesFilesToKV(directory string) (map[string]string, error) { - if directory == "default" { - kvs := make(map[string]string) +type KeyValuesInterface interface { + WriteKVsToConsul() error + ReadConfigs(POSTBodyStruct) error + PropertiesFilesToKV(string) error + ReadMultipleProperties(string) error + ReadProperty(string) +} - _, filename, _, ok := runtime.Caller(0) +type KeyValuesStruct struct { + sync.RWMutex + kvs map[string]string +} + +var KeyValues KeyValuesInterface +func (kvStruct *KeyValuesStruct) WriteKVsToConsul() error { + for key, value := range kvStruct.kvs { + err := Consul.RequestPUT(key, value) + if err != nil { + return err + } + log.Println("[INFO] Key: ", key, "| Value: ", value) + } + log.Println("[INFO] Wrote KVs to Consul.") + return nil +} + +func (kvStruct *KeyValuesStruct) ReadConfigs(body POSTBodyStruct) error { + defer kvStruct.Unlock() + + kvStruct.Lock() + + err := kvStruct.PropertiesFilesToKV(body.Type.FilePath) + if err != nil { + return err + } + return nil +} + +func (kvStruct *KeyValuesStruct) PropertiesFilesToKV(directory string) error { + + if directory == "default" { + _, filename, _, ok := runtime.Caller(0) if !ok { - return nil, errors.New("No caller") + return errors.New("No caller") } - configDir := path.Dir(filename) + "/../configurations/" - err := ReadMultipleProperties(configDir, kvs) + defaultDir := path.Dir(filename) + "/../configurations/" + err := kvStruct.ReadMultipleProperties(defaultDir) if err != nil { - return nil, err + return err } - return kvs, nil + + return nil + } else { - // Add case if directory is not there. - kvs := make(map[string]string) directory += "/" - err := ReadMultipleProperties(directory, kvs) + err := kvStruct.ReadMultipleProperties(directory) if err != nil { - return nil, err + return err } - return kvs, nil - } -} -func ReadProperty(path string, kvs map[string]string) { - p := properties.MustLoadFile(path, properties.UTF8) - for _, key := range p.Keys() { - kvs[key] = p.MustGet(key) + return nil } } -func ReadMultipleProperties(path string, kvs map[string]string) error { +func (kvStruct *KeyValuesStruct) ReadMultipleProperties(path string) error { files, err := ioutil.ReadDir(path) if err != nil { return err } for _, f := range files { - ReadProperty(path+f.Name(), kvs) + kvStruct.ReadProperty(path + f.Name()) } return nil } + +func (kvStruct *KeyValuesStruct) ReadProperty(path string) { + p := properties.MustLoadFile(path, properties.UTF8) + for _, key := range p.Keys() { + kvStruct.kvs[key] = p.MustGet(key) + } +} diff --git a/src/dkv/api/utils.go b/src/dkv/api/utils.go deleted file mode 100644 index 8b87848..0000000 --- a/src/dkv/api/utils.go +++ /dev/null @@ -1,101 +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" - "sync" -) - -type KeyValue struct { - sync.RWMutex - kv map[string]string -} - -type ResponseStringStruct struct { - Response string `json:"response"` -} - -type ResponseGETStruct struct { - Response map[string]string `json:"response"` -} - -type ResponseGETSStruct struct { - Response []string `json:"response"` -} - -type LoadStruct struct { - Type *TypeStruct `json:"type"` -} - -type TypeStruct struct { - FilePath string `json:"file_path"` -} - -var KVStruct = &KeyValue{kv: make(map[string]string)} - -func (kvStruct *KeyValue) ReadConfigs(body LoadStruct) error { - if body.Type.FilePath == "default" { - err := kvStruct.FileReader("default") - if err != nil { - return err - } - return nil - } else { - err := kvStruct.FileReader(body.Type.FilePath) - if err != nil { - return err - } - return nil - } -} - -func (kvStruct *KeyValue) FileReader(directory string) error { - defer kvStruct.Unlock() - - kvStruct.Lock() - - if directory == "default" { - propertiesValues, err := PropertiesFilesToKV("default") - if err != nil { - return err - } - for key, value := range propertiesValues { - kvStruct.kv[key] = value - } - return nil - } else { - propertiesValues, err := PropertiesFilesToKV(directory) - if err != nil { - return err - } - for key, value := range propertiesValues { - kvStruct.kv[key] = value - } - return nil - } -} - -func ValidateBody(body LoadStruct) error { - if body.Type == nil { - return errors.New("Type not set. Recheck POST data.") - } else if body.Type.FilePath == "" { - return errors.New("file_path not set") - } else { - return nil - } -} diff --git a/src/dkv/api/utils_test.go b/src/dkv/api/utils_test.go deleted file mode 100644 index 342542a..0000000 --- a/src/dkv/api/utils_test.go +++ /dev/null @@ -1,19 +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 - -// TODO(sshank) diff --git a/src/dkv/main.go b/src/dkv/main.go index 5d0c5b6..8b4850f 100644 --- a/src/dkv/main.go +++ b/src/dkv/main.go @@ -18,15 +18,24 @@ package main import ( "dkv/api" + "github.com/gorilla/handlers" "github.com/gorilla/mux" "log" "net/http" + "os" ) func main() { + err := api.Initialise() + if err != nil { + log.Fatal(err) + } router := mux.NewRouter() router.HandleFunc("/loadconfigs", api.HandlePOST).Methods("POST") router.HandleFunc("/getconfig/{key}", api.HandleGET).Methods("GET") + router.HandleFunc("/deleteconfig/{key}", api.HandleDELETE).Methods("DELETE") router.HandleFunc("/getconfigs", api.HandleGETS).Methods("GET") - log.Fatal(http.ListenAndServe(":8080", router)) + loggedRouter := handlers.LoggingHandler(os.Stdout, router) + log.Println("[INFO] Started Distributed KV Store server.") + log.Fatal(http.ListenAndServe(":8080", loggedRouter)) } diff --git a/swagger.json b/swagger.json index 364bcd3..bb76c41 100644 --- a/swagger.json +++ b/swagger.json @@ -67,6 +67,25 @@ paths: description: "successful operation" schema: $ref: "#/definitions/Get" + /deleteconfig/{key}: + delete: + tags: + - "delete single key" + summary: "Delete value for specific key present in Consul." + description: "Deletes a specific key." + produces: + - "application/json" + parameters: + - name: "key" + in: "path" + description: "Key used to delete" + required: true + type: "string" + responses: + 200: + description: "successful operation" + schema: + $ref: "#/definitions/Delete" definitions: LoadRequest: type: "object" @@ -94,3 +113,8 @@ definitions: properties: response: type: "string" + Delete: + type: "object" + properties: + response: + type: "string" -- cgit 1.2.3-korg