Repository: alicebob/miniredis (go)

Issue:
BLMOVE to the same single-element list causes TTL to be lost
This sequence of Redis commands:

```
LPUSH test 1
EXPIRE test 1000
TTL test  # outputs TTL > 0
BLMOVE test test LEFT LEFT 1
TTL test  # should continue outputting TTL > 0
```

works with Redis, but not Miniredis: The final `TTL test` in Miniredis will return -1, since I think blmove's implementation in Miniredis will cause Miniredis to delete and recreate the `test` list, losing the TTL in the process.

Pull request description:
keep the TTL in BLMOVE
Fixes #402

Patch:
diff --git a/cmd_list.go b/cmd_list.go
index 0683ccc..d224275 100644
--- a/cmd_list.go
+++ b/cmd_list.go
@@ -1022,7 +1022,10 @@ func (m *Miniredis) cmdBlmove(c *server.Peer, cmd string, args []string) {
 				return true
 			}
 
-			var elem string
+			var (
+				elem string
+				ttl  = db.ttl[opts.src] // in case we empty the array (deletes the entry)
+			)
 			switch opts.srcDir {
 			case "left":
 				elem = db.listLpop(opts.src)
@@ -1042,6 +1045,9 @@ func (m *Miniredis) cmdBlmove(c *server.Peer, cmd string, args []string) {
 				c.WriteError(msgSyntaxError)
 				return true
 			}
+			if ttl > 0 {
+				db.ttl[opts.dst] = ttl
+			}
 
 			c.WriteBulk(elem)
 			return true


Test patch:
diff --git a/integration/list_test.go b/integration/list_test.go
index 8644b01..6164461 100644
--- a/integration/list_test.go
+++ b/integration/list_test.go
@@ -628,6 +628,13 @@ func TestBlmove(t *testing.T) {
 		c.Do("BLMOVE", "round", "round", "RIGHT", "RIGHT", "0")
 		c.Do("LRANGE", "round", "0", "-1")
 
+		// TTL
+		c.Do("LPUSH", "test", "1")
+		c.Do("EXPIRE", "test", "1000")
+		c.Do("TTL", "test")
+		c.Do("BLMOVE", "test", "test", "LEFT", "LEFT", "1")
+		c.Do("TTL", "test")
+
 		// failure cases
 		c.Do("RPUSH", "chk", "aap", "noot", "mies")
 		c.Error("wrong number", "LMOVE")