summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChloe Kudryavtsev <toast@toast.cafe>2019-12-17 13:47:36 -0500
committerChloe Kudryavtsev <toast@toast.cafe>2019-12-17 13:47:36 -0500
commit935f19b7222511694953a0f743bbcdaf8d4edcad (patch)
tree961888deeb70fa63bc14bd635a6e618f88708f50
parentfix: ensure interfaces are implemented buildtime (diff)
feat: add in-memory storage backend
it can't be used in the cli yet also means other backends need to be modified slightly
-rw-r--r--storage/memory.go47
-rw-r--r--storage/memory_test.go56
-rw-r--r--storage/redis.go2
-rw-r--r--storage/type.go2
4 files changed, 106 insertions, 1 deletions
diff --git a/storage/memory.go b/storage/memory.go
new file mode 100644
index 0000000..80f6579
--- /dev/null
+++ b/storage/memory.go
@@ -0,0 +1,47 @@
+package storage
+
+var _ CHR = &Memory{}
+
+// Memory is an in-memory non-persistent storage type
+// using it in production is not recommended
+type Memory struct {
+ store map[string]string
+}
+
+// Create will store a value in a key in memory
+func (r *Memory) Create(key, value string, checkcollision bool) error {
+ if !r.Healthy() {
+ return Unhealthy
+ }
+ if checkcollision {
+ if _, ok := r.store[key]; ok {
+ return Collision
+ }
+ }
+ r.store[key] = value
+ return nil
+}
+
+// Read will read a key from memory, if it's there
+func (r *Memory) Read(key string) (string, error) {
+ if !r.Healthy() {
+ return "", Unhealthy
+ }
+ if val, ok := r.store[key]; ok {
+ return val, nil
+ }
+ return "", Error("value not found")
+}
+
+// Healthy checks if the memory storage is initialized
+func (r *Memory) Healthy() bool {
+ return r.store != nil
+}
+
+// NewMemory initializes a memory backend for use
+func NewMemory() CHR {
+ m := Memory{
+ store: make(map[string]string),
+ }
+ return &m
+}
diff --git a/storage/memory_test.go b/storage/memory_test.go
new file mode 100644
index 0000000..fa0666e
--- /dev/null
+++ b/storage/memory_test.go
@@ -0,0 +1,56 @@
+package storage
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestMemory(t *testing.T) {
+ assert := assert.New(t)
+ const (
+ k = "key"
+ v1 = "val1"
+ v2 = "val2"
+ )
+
+ m := NewMemory()
+
+ err := m.Create(k, v1, false)
+ assert.Nil(err)
+
+ err = m.Create(k, v2, false)
+ assert.Nil(err)
+
+ err = m.Create(k, v1, true)
+ assert.Equal(Collision, err)
+
+ v, err := m.Read(k)
+ assert.Nil(err)
+ assert.Equal(v2, v)
+
+ _, err = m.Read(v1)
+ assert.NotNil(err)
+ assert.Equal(NotFound, err)
+}
+
+func TestUnhealthyMemory(t *testing.T) {
+ assert := assert.New(t)
+ m := &Memory{}
+
+ var (
+ e1 = m.Create("", "", false)
+ e2 = m.Create("", "", true)
+ _, e3 = m.Read("")
+ )
+
+ assert.NotNil(e1)
+ assert.NotNil(e2)
+ assert.NotNil(e3)
+
+ assert.Equal(Unhealthy, e1)
+ assert.Equal(Unhealthy, e2)
+ assert.Equal(Unhealthy, e3)
+
+ assert.False(m.Healthy())
+}
diff --git a/storage/redis.go b/storage/redis.go
index de207a5..317ee3e 100644
--- a/storage/redis.go
+++ b/storage/redis.go
@@ -29,7 +29,7 @@ func (r *Redis) Read(key string) (string, error) {
if !r.Healthy() {
return "", Unhealthy
}
- return r.Get(key).Result()
+ return r.Get(key).Result() // TODO: return NotFound conditionally
}
// Healthy determines whether redis is responding to pings
diff --git a/storage/type.go b/storage/type.go
index 4f78a46..b2d3136 100644
--- a/storage/type.go
+++ b/storage/type.go
@@ -3,6 +3,8 @@ package storage
const (
// Collision is a fatal collision error, only triggered when it fails
Collision = Error("collision detected")
+ // NotFound is a fatal error when the backend cannot find a key to read
+ NotFound = Error("value not found")
// Unhealthy is a fatal error when the backend ceases to be healthy
Unhealthy = Error("backend unhealthy")
)