Update tests and refactor code 85/31885/5
authorShashank Kumar Shankar <shashank.kumar.shankar@intel.com>
Thu, 15 Feb 2018 22:48:19 +0000 (14:48 -0800)
committerShashank Kumar Shankar <shashank.kumar.shankar@intel.com>
Wed, 21 Feb 2018 21:51:08 +0000 (13:51 -0800)
This patch adds some more tests and refactors the
codebase.

Change-Id: Iee669b85c5c7f9bdd01271fe86df20506f567d23
Issue-ID: MUSIC-23
Signed-off-by: Shashank Kumar Shankar <shashank.kumar.shankar@intel.com>
12 files changed:
src/dkv/Gopkg.lock
src/dkv/api/consulConnection.go
src/dkv/api/consulConnection_test.go
src/dkv/api/endpointViews.go
src/dkv/api/endpointViews_fake.go [new file with mode: 0644]
src/dkv/api/endpointViews_test.go
src/dkv/api/initialise.go [new file with mode: 0644]
src/dkv/api/initialise_test.go [moved from src/dkv/api/utils_test.go with 53% similarity]
src/dkv/api/propertiesReader.go
src/dkv/api/utils.go [deleted file]
src/dkv/main.go
swagger.json

index 33c42f6..97abfee 100644 (file)
   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
index b8074e2..5ea79fd 100644 (file)
@@ -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
+}
index 3c47ee5..7d19a6a 100644 (file)
@@ -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 (file)
index 0000000..c147673
--- /dev/null
@@ -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")
+}
index f603af4..1f7abf3 100644 (file)
@@ -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 (file)
index 0000000..f85c146
--- /dev/null
@@ -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
+}
similarity index 53%
rename from src/dkv/api/utils_test.go
rename to src/dkv/api/initialise_test.go
index 342542a..3063201 100644 (file)
 
 package api
 
-// TODO(sshank)
+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)
+}
index 018dabe..a1c94bb 100644 (file)
@@ -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 (file)
index 8b87848..0000000
+++ /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
-       }
-}
index 5d0c5b6..8b4850f 100644 (file)
@@ -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))
 }
index 364bcd3..bb76c41 100644 (file)
@@ -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"