test: cover Excache.StoreOpsRegressionTest
This commit is contained in:
1 parent
5839570919
commit
fb085d0d90
1 file changed
+158
@@ -0,0 +1,158 @@
|
||||
defmodule Excache.StoreOpsRegressionTest do
|
||||
use Excache.Test.ServerCase, async: false
|
||||
|
||||
alias Excache.Store
|
||||
|
||||
describe "SMOVE must not drop the member when the destination has the wrong type" do
|
||||
test "the member stays in the source and the caller is told about the type clash" do
|
||||
source = "regr:smove:src"
|
||||
dest = "regr:smove:dst-string"
|
||||
|
||||
assert {:ok, 1} = Store.sadd(source, ["alpha"])
|
||||
assert :ok = Store.set(dest, "not-a-set", [])
|
||||
|
||||
assert {:error, :wrongtype} = Store.smove(source, dest, "alpha")
|
||||
assert {:ok, ["alpha"]} = Store.smembers(source)
|
||||
assert {:ok, "not-a-set"} = Store.get(dest)
|
||||
end
|
||||
|
||||
test "the destination type is checked before the source is touched" do
|
||||
source = "regr:smove:absent-src"
|
||||
dest = "regr:smove:dst-list"
|
||||
|
||||
assert {:ok, 1} = Store.rpush(dest, ["element"])
|
||||
|
||||
assert {:error, :wrongtype} = Store.smove(source, dest, "alpha")
|
||||
assert {:ok, ["element"]} = Store.lrange(dest, 0, -1)
|
||||
end
|
||||
|
||||
test "a wrong type on the source is reported and the destination is left alone" do
|
||||
source = "regr:smove:src-string"
|
||||
dest = "regr:smove:dst-set"
|
||||
|
||||
assert :ok = Store.set(source, "not-a-set", [])
|
||||
assert {:ok, 1} = Store.sadd(dest, ["beta"])
|
||||
|
||||
assert {:error, :wrongtype} = Store.smove(source, dest, "alpha")
|
||||
assert {:ok, ["beta"]} = Store.smembers(dest)
|
||||
end
|
||||
|
||||
test "a healthy move across two shards still transfers the member exactly once" do
|
||||
source = "regr:smove:move-src"
|
||||
dest = keyInOtherShard("regr:smove:move-dst-", source)
|
||||
|
||||
assert {:ok, 2} = Store.sadd(source, ["alpha", "gamma"])
|
||||
assert {:ok, 1} = Store.sadd(dest, ["beta"])
|
||||
|
||||
assert {:ok, 1} = Store.smove(source, dest, "alpha")
|
||||
assert {:ok, ["gamma"]} = Store.smembers(source)
|
||||
assert {:ok, members} = Store.smembers(dest)
|
||||
assert Enum.sort(members) == ["alpha", "beta"]
|
||||
end
|
||||
|
||||
test "moving a member the source does not hold reports zero and adds nothing" do
|
||||
source = "regr:smove:miss-src"
|
||||
dest = "regr:smove:miss-dst"
|
||||
|
||||
assert {:ok, 1} = Store.sadd(source, ["alpha"])
|
||||
assert {:ok, 1} = Store.sadd(dest, ["beta"])
|
||||
|
||||
assert {:ok, 0} = Store.smove(source, dest, "nothing-like-this")
|
||||
assert {:ok, ["alpha"]} = Store.smembers(source)
|
||||
assert {:ok, ["beta"]} = Store.smembers(dest)
|
||||
end
|
||||
|
||||
test "SMOVE over RESP reports WRONGTYPE and keeps the member", %{conn: conn} do
|
||||
assert {1, conn} = Client.command(conn, ["SADD", "regr:smove:resp-src", "alpha"])
|
||||
assert {{:simple, "OK"}, conn} = Client.command(conn, ["SET", "regr:smove:resp-dst", "s"])
|
||||
|
||||
assert {{:error, "WRONGTYPE" <> _}, conn} =
|
||||
Client.command(conn, [
|
||||
"SMOVE",
|
||||
"regr:smove:resp-src",
|
||||
"regr:smove:resp-dst",
|
||||
"alpha"
|
||||
])
|
||||
|
||||
assert {["alpha"], _conn} = Client.command(conn, ["SMEMBERS", "regr:smove:resp-src"])
|
||||
end
|
||||
end
|
||||
|
||||
describe "RPOPLPUSH must not drop the element when the destination has the wrong type" do
|
||||
test "the element stays at the tail of the source and the caller sees the error" do
|
||||
source = "regr:rpoplpush:src"
|
||||
dest = "regr:rpoplpush:dst-string"
|
||||
|
||||
assert {:ok, 2} = Store.rpush(source, ["head", "tail"])
|
||||
assert :ok = Store.set(dest, "not-a-list", [])
|
||||
|
||||
assert {:error, :wrongtype} = Store.rpoplpush(source, dest)
|
||||
assert {:ok, ["head", "tail"]} = Store.lrange(source, 0, -1)
|
||||
assert {:ok, "not-a-list"} = Store.get(dest)
|
||||
end
|
||||
|
||||
test "the destination type is checked before the source is popped" do
|
||||
source = "regr:rpoplpush:absent-src"
|
||||
dest = "regr:rpoplpush:dst-set"
|
||||
|
||||
assert {:ok, 1} = Store.sadd(dest, ["beta"])
|
||||
|
||||
assert {:error, :wrongtype} = Store.rpoplpush(source, dest)
|
||||
assert {:ok, ["beta"]} = Store.smembers(dest)
|
||||
end
|
||||
|
||||
test "a healthy rotation across two shards moves the tail to the head" do
|
||||
source = "regr:rpoplpush:rot-src"
|
||||
dest = keyInOtherShard("regr:rpoplpush:rot-dst-", source)
|
||||
|
||||
assert {:ok, 2} = Store.rpush(source, ["head", "tail"])
|
||||
assert {:ok, 1} = Store.rpush(dest, ["existing"])
|
||||
|
||||
assert {:ok, "tail"} = Store.rpoplpush(source, dest)
|
||||
assert {:ok, ["head"]} = Store.lrange(source, 0, -1)
|
||||
assert {:ok, ["tail", "existing"]} = Store.lrange(dest, 0, -1)
|
||||
end
|
||||
|
||||
test "an empty source yields nil and never creates the destination" do
|
||||
source = "regr:rpoplpush:empty-src"
|
||||
dest = "regr:rpoplpush:empty-dst"
|
||||
|
||||
assert {:ok, nil} = Store.rpoplpush(source, dest)
|
||||
assert 0 == Store.exists([dest])
|
||||
end
|
||||
|
||||
test "RPOPLPUSH over RESP reports WRONGTYPE and keeps the element", %{conn: conn} do
|
||||
assert {1, conn} = Client.command(conn, ["RPUSH", "regr:rpoplpush:resp-src", "tail"])
|
||||
|
||||
assert {{:simple, "OK"}, conn} =
|
||||
Client.command(conn, ["SET", "regr:rpoplpush:resp-dst", "s"])
|
||||
|
||||
assert {{:error, "WRONGTYPE" <> _}, conn} =
|
||||
Client.command(conn, [
|
||||
"RPOPLPUSH",
|
||||
"regr:rpoplpush:resp-src",
|
||||
"regr:rpoplpush:resp-dst"
|
||||
])
|
||||
|
||||
assert {["tail"], _conn} =
|
||||
Client.command(conn, ["LRANGE", "regr:rpoplpush:resp-src", "0", "-1"])
|
||||
end
|
||||
end
|
||||
|
||||
describe "LPOS with a nil count must not crash the shard" do
|
||||
test "a nil count means the first match and the shard survives the call" do
|
||||
key = "regr:lpos:nil-count"
|
||||
assert {:ok, 4} = Store.rpush(key, ["a", "b", "c", "b"])
|
||||
shardBefore = shardPid(key)
|
||||
|
||||
assert {:ok, 1} = Store.lpos(key, "b", 1, nil, 0)
|
||||
|
||||
assert shardPid(key) == shardBefore
|
||||
assert Process.alive?(shardBefore)
|
||||
assert {:ok, ["a", "b", "c", "b"]} = Store.lrange(key, 0, -1)
|
||||
end
|
||||
|
||||
test "a nil count must not take the shard down and wipe its other keys" do
|
||||
key = "regr:lpos:blast-radius"
|
||||
neighbour = keyInSameShard("regr:lpos:neighbour-", key)
|
||||
|
||||
Reference in new issue
Block a user