Initial commit 55/55/2 v0.0.1
authorMarco Tallskog <marco.tallskog@nokia.com>
Wed, 17 Apr 2019 10:19:22 +0000 (13:19 +0300)
committerMarco Tallskog <marco.tallskog@nokia.com>
Wed, 17 Apr 2019 10:39:20 +0000 (13:39 +0300)
Change-Id: Iaf5456d3f1b8b59a727d7df46fe556fe00ac4c0e
Signed-off-by: Marco Tallskog <marco.tallskog@nokia.com>
LICENSES.txt [new file with mode: 0644]
README [new file with mode: 0644]
bench_test.go [new file with mode: 0644]
cmd/sdltester/sdltester.go [new file with mode: 0644]
example_test.go [new file with mode: 0644]
go.mod [new file with mode: 0644]
go.sum [new file with mode: 0644]
internal/sdlgoredis/sdlgoredis.go [new file with mode: 0644]
sdl.go [new file with mode: 0644]
sdl_test.go [new file with mode: 0644]

diff --git a/LICENSES.txt b/LICENSES.txt
new file mode 100644 (file)
index 0000000..d5f6563
--- /dev/null
@@ -0,0 +1,29 @@
+Unless otherwise specified, all software contained herein is licensed
+under the Apache License, Version 2.0 (the "Software License");
+you may not use this software except in compliance with the Software
+License. You may obtain a copy of the Software License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the Software License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the Software License for the specific language governing permissions
+and limitations under the Software License.
+
+
+
+Unless otherwise specified, all documentation contained herein is licensed
+under the Creative Commons License, Attribution 4.0 Intl. (the
+"Documentation License"); you may not use this documentation except in
+compliance with the Documentation License. You may obtain a copy of the
+Documentation License at
+
+https://creativecommons.org/licenses/by/4.0/
+
+Unless required by applicable law or agreed to in writing, documentation
+distributed under the Documentation License is distributed on an "AS IS"
+BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+implied. See the Documentation License for the specific language governing
+permissions and limitations under the Documentation License.
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/bench_test.go b/bench_test.go
new file mode 100644 (file)
index 0000000..233f128
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+   Copyright (c) 2019 AT&T Intellectual Property.
+   Copyright (c) 2018-2019 Nokia.
+
+   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 sdlgo_test
+
+import (
+       "fmt"
+       "strconv"
+       "strings"
+       "testing"
+
+       "gerrit.oran-osc.org/r/ric-plt/sdlgo"
+)
+
+type singleBenchmark struct {
+       key       string
+       keySize   int
+       valueSize int
+}
+
+type multiBenchmark struct {
+       keyBase   string
+       keyCount  int
+       keySize   int
+       valueSize int
+}
+
+func (bm singleBenchmark) String(oper string) string {
+       return fmt.Sprintf("op = %s key=%d value=%d", oper, bm.keySize, bm.valueSize)
+}
+
+func (bm multiBenchmark) String(oper string) string {
+       return fmt.Sprintf("op = %s keycnt=%d key=%d value=%d", oper, bm.keyCount, bm.keySize, bm.valueSize)
+}
+func BenchmarkSet(b *testing.B) {
+       benchmarks := []singleBenchmark{
+               {"a", 10, 64},
+               {"b", 10, 1024},
+               {"c", 10, 64 * 1024},
+               {"d", 10, 1024 * 1024},
+               {"e", 10, 10 * 1024 * 1024},
+
+               {"f", 100, 64},
+               {"g", 100, 1024},
+               {"h", 100, 64 * 1024},
+               {"i", 100, 1024 * 1024},
+               {"j", 100, 10 * 1024 * 1024},
+       }
+
+       for _, bm := range benchmarks {
+               b.Run(bm.String("set"), func(b *testing.B) {
+                       key := strings.Repeat(bm.key, bm.keySize)
+                       value := strings.Repeat("1", bm.valueSize)
+                       sdl := sdlgo.NewSdlInstance("namespace", sdlgo.NewDatabase())
+
+                       b.ResetTimer()
+                       b.RunParallel(func(pb *testing.PB) {
+                               for pb.Next() {
+                                       err := sdl.Set(key, value)
+                                       if err != nil {
+                                               b.Fatal(err)
+                                       }
+                               }
+                       })
+               })
+       }
+}
+
+func BenchmarkGet(b *testing.B) {
+       benchmarks := []singleBenchmark{
+               {"a", 10, 64},
+               {"b", 10, 1024},
+               {"c", 10, 64 * 1024},
+               {"d", 10, 1024 * 1024},
+               {"e", 10, 10 * 1024 * 1024},
+
+               {"f", 100, 64},
+               {"g", 100, 1024},
+               {"h", 100, 64 * 1024},
+               {"i", 100, 1024 * 1024},
+               {"j", 100, 10 * 1024 * 1024},
+       }
+
+       for _, bm := range benchmarks {
+               b.Run(bm.String("Get"), func(b *testing.B) {
+                       key := strings.Repeat(bm.key, bm.keySize)
+                       value := strings.Repeat("1", bm.valueSize)
+                       sdl := sdlgo.NewSdlInstance("namespace", sdlgo.NewDatabase())
+                       if err := sdl.Set(key, value); err != nil {
+                               b.Fatal(err)
+                       }
+                       b.ResetTimer()
+                       b.RunParallel(func(pb *testing.PB) {
+                               for pb.Next() {
+                                       _, err := sdl.Get([]string{key})
+                                       if err != nil {
+                                               b.Fatal(err)
+                                       }
+                               }
+                       })
+               })
+       }
+}
+
+func BenchmarkMultiSet(b *testing.B) {
+       benchmarks := []multiBenchmark{
+               {"a", 2, 10, 64},
+               {"b", 10, 10, 64},
+               {"c", 100, 10, 64},
+               {"d", 1000, 10, 64},
+               {"e", 5000, 10, 64},
+
+               {"f", 2, 100, 64},
+               {"g", 10, 100, 64},
+               {"h", 100, 100, 64},
+               {"i", 1000, 100, 64},
+               {"j", 5000, 100, 64},
+       }
+
+       for _, bm := range benchmarks {
+               b.Run(bm.String("mset"), func(b *testing.B) {
+                       sdl := sdlgo.NewSdlInstance("namespace", sdlgo.NewDatabase())
+                       value := strings.Repeat("1", bm.valueSize)
+                       keyVals := make([]string, 0)
+                       for i := 0; i < bm.keyCount; i++ {
+                               key := strings.Repeat(bm.keyBase+strconv.Itoa(i), bm.keySize)
+                               keyVals = append(keyVals, key, value)
+                       }
+                       b.ResetTimer()
+                       b.RunParallel(func(pb *testing.PB) {
+                               for pb.Next() {
+                                       err := sdl.Set(keyVals)
+                                       if err != nil {
+                                               b.Fatal(err)
+                                       }
+                               }
+                       })
+               })
+       }
+}
+
+func BenchmarkMultiGet(b *testing.B) {
+       benchmarks := []multiBenchmark{
+               {"a", 2, 10, 64},
+               {"b", 10, 10, 64},
+               {"c", 100, 10, 64},
+               {"d", 1000, 10, 64},
+               {"e", 5000, 10, 64},
+
+               {"f", 2, 100, 64},
+               {"g", 10, 100, 64},
+               {"h", 100, 100, 64},
+               {"i", 1000, 100, 64},
+               {"j", 5000, 100, 64},
+       }
+
+       for _, bm := range benchmarks {
+               b.Run(bm.String("gset"), func(b *testing.B) {
+                       sdl := sdlgo.NewSdlInstance("namespace", sdlgo.NewDatabase())
+                       keyVals := make([]string, 0)
+                       for i := 0; i < bm.keyCount; i++ {
+                               key := strings.Repeat(bm.keyBase+strconv.Itoa(i), bm.keySize)
+                               keyVals = append(keyVals, key)
+                       }
+                       b.ResetTimer()
+                       b.RunParallel(func(pb *testing.PB) {
+                               for pb.Next() {
+                                       _, err := sdl.Get(keyVals)
+                                       if err != nil {
+                                               b.Fatal(err)
+                                       }
+                               }
+                       })
+               })
+       }
+}
diff --git a/cmd/sdltester/sdltester.go b/cmd/sdltester/sdltester.go
new file mode 100644 (file)
index 0000000..85e5569
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+   Copyright (c) 2019 AT&T Intellectual Property.
+   Copyright (c) 2018-2019 Nokia.
+
+   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 main
+
+import (
+       "fmt"
+       "os"
+       "time"
+
+       "gerrit.oran-osc.org/r/ric-plt/sdlgo"
+)
+
+/*
+ * This program demonsrates the basic usage of sdlgo module.
+ *
+ * The following scenarios are provided:
+ *
+ * - write: Write data. Performance is measured.
+ *
+ * - read: Read data. Performance is measured.
+ *
+ * - remove: Remove data. Performance is measured.
+ *
+ * - noexist: Read non-existing data. Performance is measured and empty container is returned as nothing was
+ *            found.
+ *
+ * - getall: Read all keys within a namespace. One can manually add keys under the used namespace and all
+ *           those keys should be returned here. Performance is measured.
+ *
+ * - removeall: Remove all keys within a namespace. Performance is measured.
+ *
+ * - emptymap: Write an empty container. Performance is measured.
+ *
+ * - multiple: Make two writes. Performance is measured.
+ *
+ * - emptydata: Write empty data for a key. Performance is measured.
+ *
+ * - writeif and writeifnot: Write if old data (written with the "write" option) has remained and remains
+ *                           unchanged during the function call. Do not write if data has changed. Performance
+ *                           is measured.
+ *
+ * - removeif: Remove if old data (written with the "write" option) has remained and remains
+ *             unchanged during the function call. Do not remove data if data has changed. Performance
+ *             is measured.
+ */
+
+func main() {
+       sdl := sdlgo.NewSdlInstance("tag1", sdlgo.NewDatabase())
+
+       if len(os.Args) > 1 {
+               switch command := os.Args[1]; command {
+               case "write":
+                       write(sdl)
+               case "read":
+                       read(sdl)
+               case "remove":
+                       remove(sdl)
+               case "noexist":
+                       noexist(sdl)
+               case "getall":
+                       getall(sdl)
+               case "removeall":
+                       removeall(sdl)
+               case "emptymap":
+                       emptymap(sdl)
+               case "multiple":
+                       multiple(sdl)
+               case "emptydata":
+                       emptydata(sdl)
+               case "writeif":
+                       writeif(sdl)
+               case "writeifnot":
+                       writeifnot(sdl)
+               case "removeif":
+                       removeif(sdl)
+               default:
+                       printHelp()
+               }
+
+       } else {
+               printHelp()
+       }
+}
+
+func printHelp() {
+       fmt.Println("Usage: sdltester <command>")
+       fmt.Println("Commands:")
+       fmt.Println("write        Write data. Performance is measured")
+       fmt.Println("read         Read data. Performance is measured")
+       fmt.Println("remove       Remove data. Performance is measured")
+       fmt.Println("noexist      Read non-existing data. Performance is measured and empty container is returned as nothing was")
+       fmt.Println("             found")
+       fmt.Println("getall       Read all keys within a namespace. One can manually add keys under the used namespace and all")
+       fmt.Println("             those keys should be returned here. Performance is measured")
+       fmt.Println("removeall    Remove all keys within a namespace. Performance is measured")
+       fmt.Println("emptymap     Write an empty container. Performance is measured")
+       fmt.Println("multiple     Make two writes. Performance is measured")
+       fmt.Println("emptydata    Write empty data for a key. Performance is measured")
+       fmt.Println("writeif      Write if old data (written with the \"write\" option) has remained and remains")
+       fmt.Println("             unchanged during the function call. Do not write if data has changed. Performance")
+       fmt.Println("             is measured")
+       fmt.Println("writeifnot   Write only if key is not set. Performance is measured")
+       fmt.Println("removeif     Remove if old data (written with the \"write\" option) has remained and remains")
+       fmt.Println("             unchanged during the function call. Do not remove data if data has changed. Performance")
+       fmt.Println("             is measured")
+}
+
+func write(sdl *sdlgo.SdlInstance) {
+       data := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+               0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x44}
+       start := time.Now()
+       err := sdl.Set("key1", data)
+       elapsed := time.Since(start)
+       if err == nil {
+               fmt.Printf("Write: %s\n", elapsed)
+       } else {
+               fmt.Println(err)
+       }
+}
+
+func read(sdl *sdlgo.SdlInstance) {
+       k := []string{"key1"}
+       start := time.Now()
+       data, err := sdl.Get(k)
+       elapsed := time.Since(start)
+       if err == nil {
+               value, ok := data["key1"]
+               if ok && value != nil {
+                       fmt.Printf("Read: %s\n", elapsed)
+               } else {
+                       fmt.Printf("Read, not found: %s\n", elapsed)
+               }
+
+       } else {
+               fmt.Println(err)
+       }
+}
+
+func remove(sdl *sdlgo.SdlInstance) {
+       k := []string{"key1"}
+       start := time.Now()
+       err := sdl.Remove(k)
+       elapsed := time.Since(start)
+       if err == nil {
+               fmt.Printf("Remove: %s\n", elapsed)
+       } else {
+               fmt.Println(err)
+       }
+}
+
+func noexist(sdl *sdlgo.SdlInstance) {
+       start := time.Now()
+       _, err := sdl.Get([]string{"no1", "no2"})
+       elapsed := time.Since(start)
+       if err == nil {
+               fmt.Printf("Noexist: %s\n", elapsed)
+       } else {
+               fmt.Println(err)
+       }
+}
+
+func getall(sdl *sdlgo.SdlInstance) {
+       start := time.Now()
+       keys, err := sdl.GetAll()
+       elapsed := time.Since(start)
+       if err == nil {
+               fmt.Printf("Getall: %s\n", elapsed)
+               for _, i := range keys {
+                       fmt.Println(i)
+               }
+       } else {
+               fmt.Println(err)
+       }
+}
+
+func removeall(sdl *sdlgo.SdlInstance) {
+       start := time.Now()
+       err := sdl.RemoveAll()
+       elapsed := time.Since(start)
+       if err == nil {
+               fmt.Printf("Removeall: %s\n", elapsed)
+       } else {
+               fmt.Println(err)
+       }
+}
+
+func emptymap(sdl *sdlgo.SdlInstance) {
+       start := time.Now()
+       err := sdl.Set("", "")
+       elapsed := time.Since(start)
+       if err == nil {
+               fmt.Printf("Emptymap: %s\n", elapsed)
+       } else {
+               fmt.Println(err)
+       }
+}
+
+func multiple(sdl *sdlgo.SdlInstance) {
+       data := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+               0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x44}
+       start := time.Now()
+       err := sdl.Set("key1m", data)
+       elapsed := time.Since(start)
+       if err == nil {
+               fmt.Printf("Multiple: %s ", elapsed)
+       } else {
+               fmt.Println(err)
+       }
+       start = time.Now()
+       err = sdl.Set("key2m", data)
+       elapsed = time.Since(start)
+       if err == nil {
+               fmt.Printf(" %s \n", elapsed)
+       } else {
+               fmt.Println(err)
+       }
+}
+
+func emptydata(sdl *sdlgo.SdlInstance) {
+       data := []byte{}
+       start := time.Now()
+       err := sdl.Set("key1", data)
+       elapsed := time.Since(start)
+       if err == nil {
+               fmt.Printf("Emptydata: %s\n", elapsed)
+       } else {
+               fmt.Println(err)
+       }
+}
+
+func writeif(sdl *sdlgo.SdlInstance) {
+       oldVec := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+               0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x44}
+       newVec := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+               0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x66}
+       start := time.Now()
+       _, err := sdl.SetIf("key1", oldVec, newVec)
+       elapsed := time.Since(start)
+       if err == nil {
+               fmt.Printf("Writeif: %s\n", elapsed)
+       } else {
+               fmt.Println(err)
+       }
+}
+
+func writeifnot(sdl *sdlgo.SdlInstance) {
+       vec := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+               0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x88}
+       start := time.Now()
+       _, err := sdl.SetIfNotExists("key1", vec)
+       elapsed := time.Since(start)
+       if err == nil {
+               fmt.Printf("Writeifnot: %s\n", elapsed)
+       } else {
+               fmt.Println(err)
+       }
+}
+
+func removeif(sdl *sdlgo.SdlInstance) {
+       vec := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
+               0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x88}
+       start := time.Now()
+       _, err := sdl.RemoveIf("key1", vec)
+       elapsed := time.Since(start)
+       if err == nil {
+               fmt.Printf("Removeif: %s\n", elapsed)
+       } else {
+               fmt.Println(err)
+       }
+}
diff --git a/example_test.go b/example_test.go
new file mode 100644 (file)
index 0000000..5f78028
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+   Copyright (c) 2019 AT&T Intellectual Property.
+   Copyright (c) 2018-2019 Nokia.
+
+   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 sdlgo_test
+
+import (
+       "fmt"
+
+       "gerrit.oran-osc.org/r/ric-plt/sdlgo"
+)
+
+var sdl *sdlgo.SdlInstance
+
+func init() {
+       sdl = sdlgo.NewSdlInstance("namespace", sdlgo.NewDatabase())
+}
+
+func ExampleSdlInstance_Set() {
+       err := sdl.Set("stringdata", "data", "intdata", 42)
+       if err != nil {
+               panic(err)
+       } else {
+               fmt.Println("Data written successfully")
+       }
+       // Output: Data written successfully
+}
+
+func ExampleSdlInstance_Get() {
+       retMap, err := sdl.Get([]string{"strigdata", "intdata"})
+       if err != nil {
+               panic(err)
+       } else {
+               fmt.Println(retMap)
+       }
+}
diff --git a/go.mod b/go.mod
new file mode 100644 (file)
index 0000000..d46db31
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,12 @@
+module gerrit.oran-osc.org/r/ric-plt/sdlgo
+
+go 1.12
+
+require (
+       github.com/go-redis/redis v6.15.2+incompatible
+       github.com/onsi/ginkgo v1.8.0 // indirect
+       github.com/onsi/gomega v1.5.0 // indirect
+       github.com/stretchr/testify v1.3.0
+)
+
+replace gerrit.oran-osc.org/r/ric-plt/sdlgo/internal/sdlgoredis => ./internal/sdlgoredis
diff --git a/go.sum b/go.sum
new file mode 100644 (file)
index 0000000..a6e2f77
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,37 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4=
+github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
+github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
+github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
+github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/internal/sdlgoredis/sdlgoredis.go b/internal/sdlgoredis/sdlgoredis.go
new file mode 100644 (file)
index 0000000..01fe5f7
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+   Copyright (c) 2019 AT&T Intellectual Property.
+   Copyright (c) 2018-2019 Nokia.
+
+   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 sdlgoredis
+
+import (
+       "errors"
+       "fmt"
+       "os"
+
+       "github.com/go-redis/redis"
+)
+
+type DB struct {
+       client       *redis.Client
+       redisModules bool
+}
+
+func Create() *DB {
+       hostname := os.Getenv("DBAAS_SERVICE_HOST")
+       if hostname == "" {
+               hostname = "localhost"
+       }
+       port := os.Getenv("DBAAS_SERVICE_PORT")
+       if port == "" {
+               port = "6379"
+       }
+       redisAddress := hostname + ":" + port
+       client := redis.NewClient(&redis.Options{
+               Addr:     redisAddress,
+               Password: "", // no password set
+               DB:       0,  // use default DB
+               PoolSize: 20,
+       })
+
+       db := DB{
+               client:       client,
+               redisModules: true,
+       }
+
+       commands, err := db.client.Command().Result()
+       if err == nil {
+               redisModuleCommands := []string{"setie", "delie"}
+               for _, v := range redisModuleCommands {
+                       _, ok := commands[v]
+                       if !ok {
+                               db.redisModules = false
+                       }
+               }
+       } else {
+               fmt.Println(err)
+       }
+       return &db
+}
+
+func (db *DB) Close() error {
+       return db.client.Close()
+}
+
+func (db *DB) MSet(pairs ...interface{}) error {
+       return db.client.MSet(pairs...).Err()
+}
+
+func (db *DB) MGet(keys []string) ([]interface{}, error) {
+       val, err := db.client.MGet(keys...).Result()
+       return val, err
+}
+
+func (db *DB) Del(keys []string) error {
+       _, err := db.client.Del(keys...).Result()
+       return err
+}
+
+func (db *DB) Keys(pattern string) ([]string, error) {
+       val, err := db.client.Keys(pattern).Result()
+       return val, err
+}
+
+func (db *DB) SetIE(key string, oldData, newData interface{}) (bool, error) {
+       if !db.redisModules {
+               return false, errors.New("Redis deployment not supporting command")
+       }
+
+       result, err := db.client.Do("SETIE", key, newData, oldData).Result()
+       if err != nil {
+               return false, err
+       }
+       if result == "OK" {
+               return true, nil
+       } else {
+               return false, nil
+       }
+}
+
+func (db *DB) SetNX(key string, data interface{}) (bool, error) {
+       result, err := db.client.SetNX(key, data, 0).Result()
+       return result, err
+}
+
+func (db *DB) DelIE(key string, data interface{}) (bool, error) {
+       if !db.redisModules {
+               return false, errors.New("Redis deployment not supporting command")
+       }
+       result, err := db.client.Do("DELIE", key, data).Result()
+       if err != nil {
+               return false, err
+       }
+       if result == "1" {
+               return true, nil
+       }
+       return false, nil
+}
diff --git a/sdl.go b/sdl.go
new file mode 100644 (file)
index 0000000..04e0625
--- /dev/null
+++ b/sdl.go
@@ -0,0 +1,211 @@
+/*
+   Copyright (c) 2019 AT&T Intellectual Property.
+   Copyright (c) 2018-2019 Nokia.
+
+   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 sdlgo
+
+import (
+       "reflect"
+       "strings"
+
+       "gerrit.oran-osc.org/r/ric-plt/sdlgo/internal/sdlgoredis"
+)
+
+type iDatabase interface {
+       MSet(pairs ...interface{}) error
+       MGet(keys []string) ([]interface{}, error)
+       Close() error
+       Del(keys []string) error
+       Keys(key string) ([]string, error)
+       SetIE(key string, oldData, newData interface{}) (bool, error)
+       SetNX(key string, data interface{}) (bool, error)
+       DelIE(key string, data interface{}) (bool, error)
+}
+
+type SdlInstance struct {
+       nameSpace string
+       nsPrefix  string
+       iDatabase
+}
+
+//NewDatabase creates a connection to database that will be used
+//as a backend for the key-value storage. The returned value shall
+//be given as a parameter when calling NewKeyValStorage
+func NewDatabase() *sdlgoredis.DB {
+       db := sdlgoredis.Create()
+       return db
+}
+
+//NewSdlInstance creates a new sdl instance using the given namespace.
+//The database used as a backend is given as a parameter
+func NewSdlInstance(NameSpace string, db iDatabase) *SdlInstance {
+       s := SdlInstance{
+               nameSpace: NameSpace,
+               nsPrefix:  "{" + NameSpace + "},",
+               iDatabase: db,
+       }
+
+       return &s
+}
+
+func (s *SdlInstance) Close() error {
+       return s.Close()
+}
+
+func (s *SdlInstance) setNamespaceToKeys(pairs ...interface{}) []interface{} {
+       var retVal []interface{}
+       for i, v := range pairs {
+               if i%2 == 0 {
+                       reflectType := reflect.TypeOf(v)
+                       switch reflectType.Kind() {
+                       case reflect.Slice:
+                               x := reflect.ValueOf(v)
+                               for i2 := 0; i2 < x.Len(); i2++ {
+                                       if i2%2 == 0 {
+                                               retVal = append(retVal, s.nsPrefix+x.Index(i2).Interface().(string))
+                                       } else {
+                                               retVal = append(retVal, x.Index(i2).Interface())
+                                       }
+                               }
+                       case reflect.Array:
+                               x := reflect.ValueOf(v)
+                               for i2 := 0; i2 < x.Len(); i2++ {
+                                       if i2%2 == 0 {
+                                               retVal = append(retVal, s.nsPrefix+x.Index(i2).Interface().(string))
+                                       } else {
+                                               retVal = append(retVal, x.Index(i2).Interface())
+                                       }
+                               }
+                       default:
+                               retVal = append(retVal, s.nsPrefix+v.(string))
+                       }
+               } else {
+                       retVal = append(retVal, v)
+               }
+       }
+       return retVal
+}
+
+//Set function writes data to shared data layer storage. Writing is done
+//atomically, i.e. all succeeds or fails.
+//Data to be written is given as key-value pairs. Several key-value
+//pairs can be written with one call.
+//The key is expected to be string whereas value can be anything, string,
+//number, slice array or map
+func (s *SdlInstance) Set(pairs ...interface{}) error {
+       if len(pairs) == 0 {
+               return nil
+       }
+
+       keyAndData := s.setNamespaceToKeys(pairs...)
+       err := s.MSet(keyAndData...)
+       return err
+}
+
+//Get function atomically reads one or more keys from SDL. The returned map has the
+//requested keys as index and data as value. If the requested key is not found
+//from SDL, it's value is nil
+func (s *SdlInstance) Get(keys []string) (map[string]interface{}, error) {
+       m := make(map[string]interface{})
+       if len(keys) == 0 {
+               return m, nil
+       }
+
+       var keysWithNs []string
+       for _, v := range keys {
+               keysWithNs = append(keysWithNs, s.nsPrefix+v)
+       }
+       val, err := s.MGet(keysWithNs)
+       if err != nil {
+               return m, err
+       }
+       for i, v := range val {
+               m[keys[i]] = v
+       }
+       return m, err
+}
+
+//SetIf atomically replaces existing data with newData in SDL if data matches the oldData.
+//If replace was done successfully, true will be returned.
+func (s *SdlInstance) SetIf(key string, oldData, newData interface{}) (bool, error) {
+       status, err := s.SetIE(s.nsPrefix+key, oldData, newData)
+       if err != nil {
+               return false, err
+       }
+       return status, nil
+}
+
+//SetIfNotExists conditionally sets the value of a key. If key already exists in SDL,
+//then it's value is not changed. Checking the key existence and potential set operation
+//is done atomically.
+func (s *SdlInstance) SetIfNotExists(key string, data interface{}) (bool, error) {
+       status, err := s.SetNX(s.nsPrefix+key, data)
+       if err != nil {
+               return false, err
+       }
+       return status, nil
+}
+
+//Remove data from SDL. Operation is done atomically, i.e. either all succeeds or fails
+func (s *SdlInstance) Remove(keys []string) error {
+       if len(keys) == 0 {
+               return nil
+       }
+
+       var keysWithNs []string
+       for _, v := range keys {
+               keysWithNs = append(keysWithNs, s.nsPrefix+v)
+       }
+       err := s.Del(keysWithNs)
+       return err
+}
+
+//RemoveIf removes data from SDL conditionally. If existing data matches given data,
+//key and data are removed from SDL. If remove was done successfully, true is returned.
+func (s *SdlInstance) RemoveIf(key string, data interface{}) (bool, error) {
+       status, err := s.DelIE(s.nsPrefix+key, data)
+       if err != nil {
+               return false, err
+       }
+       return status, nil
+}
+
+//GetAll returns all keys under the namespace. No prior knowledge about the keys in the
+//given namespace exists, thus operation is not guaranteed to be atomic or isolated.
+func (s *SdlInstance) GetAll() ([]string, error) {
+       keys, err := s.Keys(s.nsPrefix + "*")
+       var retVal []string = nil
+       if err != nil {
+               return retVal, err
+       }
+       for _, v := range keys {
+               retVal = append(retVal, strings.Split(v, s.nsPrefix)[1])
+       }
+       return retVal, err
+}
+
+//RemoveAll removes all keys under the namespace. Remove operation is not atomic, thus
+//it is not guaranteed that all keys are removed.
+func (s *SdlInstance) RemoveAll() error {
+       keys, err := s.Keys(s.nsPrefix + "*")
+       if err != nil {
+               return err
+       }
+       if keys != nil {
+               err = s.Del(keys)
+       }
+       return err
+}
diff --git a/sdl_test.go b/sdl_test.go
new file mode 100644 (file)
index 0000000..75ee321
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+   Copyright (c) 2019 AT&T Intellectual Property.
+   Copyright (c) 2018-2019 Nokia.
+
+   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 sdlgo_test
+
+import (
+       "errors"
+       "testing"
+
+       "gerrit.oran-osc.org/r/ric-plt/sdlgo"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/mock"
+)
+
+type mockDB struct {
+       mock.Mock
+}
+
+func (m *mockDB) MSet(pairs ...interface{}) error {
+       a := m.Called(pairs)
+       return a.Error(0)
+}
+
+func (m *mockDB) MGet(keys []string) ([]interface{}, error) {
+       a := m.Called(keys)
+       return a.Get(0).([]interface{}), a.Error(1)
+}
+
+func (m *mockDB) Close() error {
+       a := m.Called()
+       return a.Error(0)
+}
+
+func (m *mockDB) Del(keys []string) error {
+       a := m.Called(keys)
+       return a.Error(0)
+}
+
+func (m *mockDB) Keys(pattern string) ([]string, error) {
+       a := m.Called(pattern)
+       return a.Get(0).([]string), a.Error(1)
+}
+
+func (m *mockDB) SetIE(key string, oldData, newData interface{}) (bool, error) {
+       a := m.Called(key, oldData, newData)
+       return a.Bool(0), a.Error(1)
+}
+
+func (m *mockDB) SetNX(key string, data interface{}) (bool, error) {
+       a := m.Called(key, data)
+       return a.Bool(0), a.Error(1)
+}
+
+func (m *mockDB) DelIE(key string, data interface{}) (bool, error) {
+       a := m.Called(key, data)
+       return a.Bool(0), a.Error(1)
+}
+
+func setup() (*mockDB, *sdlgo.SdlInstance) {
+       m := new(mockDB)
+       i := sdlgo.NewSdlInstance("namespace", m)
+       return m, i
+}
+
+func TestGetOneKey(t *testing.T) {
+       m, i := setup()
+
+       mgetExpected := []string{"{namespace},key"}
+       mReturn := []interface{}{"somevalue"}
+       mReturnExpected := make(map[string]interface{})
+       mReturnExpected["key"] = "somevalue"
+
+       m.On("MGet", mgetExpected).Return(mReturn, nil)
+       retVal, err := i.Get([]string{"key"})
+       assert.Nil(t, err)
+       assert.Equal(t, mReturnExpected, retVal)
+       m.AssertExpectations(t)
+}
+
+func TestGetSeveralKeys(t *testing.T) {
+       m, i := setup()
+
+       mgetExpected := []string{"{namespace},key1", "{namespace},key2", "{namespace},key3"}
+       mReturn := []interface{}{"somevalue1", 2, "someothervalue"}
+       mReturnExpected := make(map[string]interface{})
+       mReturnExpected["key1"] = "somevalue1"
+       mReturnExpected["key2"] = 2
+       mReturnExpected["key3"] = "someothervalue"
+
+       m.On("MGet", mgetExpected).Return(mReturn, nil)
+       retVal, err := i.Get([]string{"key1", "key2", "key3"})
+       assert.Nil(t, err)
+       assert.Equal(t, mReturnExpected, retVal)
+       m.AssertExpectations(t)
+}
+
+func TestGetSeveralKeysSomeFail(t *testing.T) {
+       m, i := setup()
+
+       mgetExpected := []string{"{namespace},key1", "{namespace},key2", "{namespace},key3"}
+       mReturn := []interface{}{"somevalue1", nil, "someothervalue"}
+       mReturnExpected := make(map[string]interface{})
+       mReturnExpected["key1"] = "somevalue1"
+       mReturnExpected["key2"] = nil
+       mReturnExpected["key3"] = "someothervalue"
+
+       m.On("MGet", mgetExpected).Return(mReturn, nil)
+       retVal, err := i.Get([]string{"key1", "key2", "key3"})
+       assert.Nil(t, err)
+       assert.Equal(t, mReturnExpected, retVal)
+       m.AssertExpectations(t)
+}
+
+func TestGetKeyReturnError(t *testing.T) {
+       m, i := setup()
+
+       mgetExpected := []string{"{namespace},key"}
+       mReturn := []interface{}{nil}
+       mReturnExpected := make(map[string]interface{})
+
+       m.On("MGet", mgetExpected).Return(mReturn, errors.New("Some error"))
+       retVal, err := i.Get([]string{"key"})
+       assert.NotNil(t, err)
+       assert.Equal(t, mReturnExpected, retVal)
+       m.AssertExpectations(t)
+}
+
+func TestGetEmptyList(t *testing.T) {
+       m, i := setup()
+
+       mgetExpected := []string{}
+
+       retval, err := i.Get([]string{})
+       assert.Nil(t, err)
+       assert.Len(t, retval, 0)
+       m.AssertNotCalled(t, "MGet", mgetExpected)
+}
+
+func TestWriteOneKey(t *testing.T) {
+       m, i := setup()
+
+       msetExpected := []interface{}{"{namespace},key1", "data1"}
+
+       m.On("MSet", msetExpected).Return(nil)
+       err := i.Set("key1", "data1")
+       assert.Nil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestWriteSeveralKeysSlice(t *testing.T) {
+       m, i := setup()
+
+       msetExpected := []interface{}{"{namespace},key1", "data1", "{namespace},key2", 22}
+
+       m.On("MSet", msetExpected).Return(nil)
+       err := i.Set([]interface{}{"key1", "data1", "key2", 22})
+       assert.Nil(t, err)
+       m.AssertExpectations(t)
+
+}
+
+func TestWriteSeveralKeysArray(t *testing.T) {
+       m, i := setup()
+
+       msetExpected := []interface{}{"{namespace},key1", "data1", "{namespace},key2", "data2"}
+
+       m.On("MSet", msetExpected).Return(nil)
+       err := i.Set([4]string{"key1", "data1", "key2", "data2"})
+       assert.Nil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestWriteFail(t *testing.T) {
+       m, i := setup()
+
+       msetExpected := []interface{}{"{namespace},key1", "data1"}
+
+       m.On("MSet", msetExpected).Return(errors.New("Some error"))
+       err := i.Set("key1", "data1")
+       assert.NotNil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestWriteEmptyList(t *testing.T) {
+       m, i := setup()
+
+       msetExpected := []interface{}{}
+       err := i.Set()
+       assert.Nil(t, err)
+       m.AssertNotCalled(t, "MSet", msetExpected)
+}
+
+func TestRemoveSuccessfully(t *testing.T) {
+       m, i := setup()
+
+       msetExpected := []string{"{namespace},key1", "{namespace},key2"}
+       m.On("Del", msetExpected).Return(nil)
+
+       err := i.Remove([]string{"key1", "key2"})
+       assert.Nil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestRemoveFail(t *testing.T) {
+       m, i := setup()
+
+       msetExpected := []string{"{namespace},key"}
+       m.On("Del", msetExpected).Return(errors.New("Some error"))
+
+       err := i.Remove([]string{"key"})
+       assert.NotNil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestRemoveEmptyList(t *testing.T) {
+       m, i := setup()
+
+       err := i.Remove([]string{})
+       assert.Nil(t, err)
+       m.AssertNotCalled(t, "Del", []string{})
+}
+
+func TestGetAllSuccessfully(t *testing.T) {
+       m, i := setup()
+
+       mKeysExpected := string("{namespace},*")
+       mReturnExpected := []string{"{namespace},key1", "{namespace},key2"}
+       expectedReturn := []string{"key1", "key2"}
+       m.On("Keys", mKeysExpected).Return(mReturnExpected, nil)
+       retVal, err := i.GetAll()
+       assert.Nil(t, err)
+       assert.Equal(t, expectedReturn, retVal)
+       m.AssertExpectations(t)
+}
+
+func TestGetAllFail(t *testing.T) {
+       m, i := setup()
+
+       mKeysExpected := string("{namespace},*")
+       mReturnExpected := []string{}
+       m.On("Keys", mKeysExpected).Return(mReturnExpected, errors.New("some error"))
+       retVal, err := i.GetAll()
+       assert.NotNil(t, err)
+       assert.Nil(t, retVal)
+       assert.Equal(t, len(retVal), 0)
+       m.AssertExpectations(t)
+}
+
+func TestGetAllReturnEmpty(t *testing.T) {
+       m, i := setup()
+
+       mKeysExpected := string("{namespace},*")
+       var mReturnExpected []string = nil
+       m.On("Keys", mKeysExpected).Return(mReturnExpected, nil)
+       retVal, err := i.GetAll()
+       assert.Nil(t, err)
+       assert.Nil(t, retVal)
+       assert.Equal(t, len(retVal), 0)
+       m.AssertExpectations(t)
+
+}
+
+func TestRemoveAllSuccessfully(t *testing.T) {
+       m, i := setup()
+
+       mKeysExpected := string("{namespace},*")
+       mKeysReturn := []string{"{namespace},key1", "{namespace},key2"}
+       mDelExpected := mKeysReturn
+       m.On("Keys", mKeysExpected).Return(mKeysReturn, nil)
+       m.On("Del", mDelExpected).Return(nil)
+       err := i.RemoveAll()
+       assert.Nil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestRemoveAllNoKeysFound(t *testing.T) {
+       m, i := setup()
+
+       mKeysExpected := string("{namespace},*")
+       var mKeysReturn []string = nil
+       m.On("Keys", mKeysExpected).Return(mKeysReturn, nil)
+       m.AssertNumberOfCalls(t, "Del", 0)
+       err := i.RemoveAll()
+       assert.Nil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestRemoveAllKeysReturnError(t *testing.T) {
+       m, i := setup()
+
+       mKeysExpected := string("{namespace},*")
+       var mKeysReturn []string = nil
+       m.On("Keys", mKeysExpected).Return(mKeysReturn, errors.New("Some error"))
+       m.AssertNumberOfCalls(t, "Del", 0)
+       err := i.RemoveAll()
+       assert.NotNil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestRemoveAllDelReturnError(t *testing.T) {
+       m, i := setup()
+
+       mKeysExpected := string("{namespace},*")
+       mKeysReturn := []string{"{namespace},key1", "{namespace},key2"}
+       mDelExpected := mKeysReturn
+       m.On("Keys", mKeysExpected).Return(mKeysReturn, nil)
+       m.On("Del", mDelExpected).Return(errors.New("Some Error"))
+       err := i.RemoveAll()
+       assert.NotNil(t, err)
+       m.AssertExpectations(t)
+}
+
+func TestSetIfSuccessfullyOkStatus(t *testing.T) {
+       m, i := setup()
+
+       mSetIEExpectedKey := string("{namespace},key1")
+       mSetIEExpectedOldData := interface{}("olddata")
+       mSetIEExpectedNewData := interface{}("newdata")
+       m.On("SetIE", mSetIEExpectedKey, mSetIEExpectedOldData, mSetIEExpectedNewData).Return(true, nil)
+       status, err := i.SetIf("key1", "olddata", "newdata")
+       assert.Nil(t, err)
+       assert.True(t, status)
+       m.AssertExpectations(t)
+}
+
+func TestSetIfSuccessfullyNOKStatus(t *testing.T) {
+       m, i := setup()
+
+       mSetIEExpectedKey := string("{namespace},key1")
+       mSetIEExpectedOldData := interface{}("olddata")
+       mSetIEExpectedNewData := interface{}("newdata")
+       m.On("SetIE", mSetIEExpectedKey, mSetIEExpectedOldData, mSetIEExpectedNewData).Return(false, nil)
+       status, err := i.SetIf("key1", "olddata", "newdata")
+       assert.Nil(t, err)
+       assert.False(t, status)
+       m.AssertExpectations(t)
+}
+
+func TestSetIfFailure(t *testing.T) {
+       m, i := setup()
+
+       mSetIEExpectedKey := string("{namespace},key1")
+       mSetIEExpectedOldData := interface{}("olddata")
+       mSetIEExpectedNewData := interface{}("newdata")
+       m.On("SetIE", mSetIEExpectedKey, mSetIEExpectedOldData, mSetIEExpectedNewData).Return(true, errors.New("Some error"))
+       status, err := i.SetIf("key1", "olddata", "newdata")
+       assert.NotNil(t, err)
+       assert.False(t, status)
+       m.AssertExpectations(t)
+}
+
+func TestSetIfNotExistsSuccessfullyOkStatus(t *testing.T) {
+       m, i := setup()
+
+       mSetNXExpectedKey := string("{namespace},key1")
+       mSetNXExpectedData := interface{}("data")
+       m.On("SetNX", mSetNXExpectedKey, mSetNXExpectedData).Return(true, nil)
+       status, err := i.SetIfNotExists("key1", "data")
+       assert.Nil(t, err)
+       assert.True(t, status)
+       m.AssertExpectations(t)
+}
+
+func TestSetIfNotExistsSuccessfullyNOKStatus(t *testing.T) {
+       m, i := setup()
+
+       mSetNXExpectedKey := string("{namespace},key1")
+       mSetNXExpectedData := interface{}("data")
+       m.On("SetNX", mSetNXExpectedKey, mSetNXExpectedData).Return(false, nil)
+       status, err := i.SetIfNotExists("key1", "data")
+       assert.Nil(t, err)
+       assert.False(t, status)
+       m.AssertExpectations(t)
+}
+
+func TestSetIfNotExistsFailure(t *testing.T) {
+       m, i := setup()
+
+       mSetNXExpectedKey := string("{namespace},key1")
+       mSetNXExpectedData := interface{}("data")
+       m.On("SetNX", mSetNXExpectedKey, mSetNXExpectedData).Return(true, errors.New("Some error"))
+       status, err := i.SetIfNotExists("key1", "data")
+       assert.NotNil(t, err)
+       assert.False(t, status)
+       m.AssertExpectations(t)
+}
+func TestRemoveIfSuccessfullyOkStatus(t *testing.T) {
+       m, i := setup()
+
+       mDelIEExpectedKey := string("{namespace},key1")
+       mDelIEExpectedData := interface{}("data")
+       m.On("DelIE", mDelIEExpectedKey, mDelIEExpectedData).Return(true, nil)
+       status, err := i.RemoveIf("key1", "data")
+       assert.Nil(t, err)
+       assert.True(t, status)
+       m.AssertExpectations(t)
+}
+
+func TestRemoveIfSuccessfullyNOKStatus(t *testing.T) {
+       m, i := setup()
+
+       mDelIEExpectedKey := string("{namespace},key1")
+       mDelIEExpectedData := interface{}("data")
+       m.On("DelIE", mDelIEExpectedKey, mDelIEExpectedData).Return(false, nil)
+       status, err := i.RemoveIf("key1", "data")
+       assert.Nil(t, err)
+       assert.False(t, status)
+       m.AssertExpectations(t)
+}
+
+func TestRemoveIfFailure(t *testing.T) {
+       m, i := setup()
+
+       mDelIEExpectedKey := string("{namespace},key1")
+       mDelIEExpectedData := interface{}("data")
+       m.On("DelIE", mDelIEExpectedKey, mDelIEExpectedData).Return(true, errors.New("Some error"))
+       status, err := i.RemoveIf("key1", "data")
+       assert.NotNil(t, err)
+       assert.False(t, status)
+       m.AssertExpectations(t)
+}