Skip to content

Commit ccb2260

Browse files
committed
Add compatibility test
1 parent fe0f750 commit ccb2260

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

src/Symfony/Component/Lock/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
5.1.0
5+
-----
6+
7+
* added support for shared locks
8+
49
5.1.0
510
-----
611

src/Symfony/Component/Lock/Tests/Store/AbstractRedisStoreTest.php

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111

1212
namespace Symfony\Component\Lock\Tests\Store;
1313

14+
use Symfony\Component\Cache\Traits\RedisClusterProxy;
15+
use Symfony\Component\Cache\Traits\RedisProxy;
16+
use Symfony\Component\Lock\Exception\InvalidArgumentException;
17+
use Symfony\Component\Lock\Exception\LockConflictedException;
18+
use Symfony\Component\Lock\Key;
1419
use Symfony\Component\Lock\PersistingStoreInterface;
1520
use Symfony\Component\Lock\Store\RedisStore;
1621

@@ -43,4 +48,99 @@ public function getStore(): PersistingStoreInterface
4348
{
4449
return new RedisStore($this->getRedisConnection());
4550
}
51+
52+
public function testBackwardCompatibilityForward()
53+
{
54+
$resource = uniqid(__METHOD__, true);
55+
$key1 = new Key($resource);
56+
$key2 = new Key($resource);
57+
58+
$oldStore = new Symfony51Store($this->getRedisConnection());
59+
$newStore = $this->getStore();
60+
61+
$oldStore->save($key1);
62+
$this->assertTrue($oldStore->exists($key1));
63+
64+
$this->expectException(LockConflictedException::class);
65+
$newStore->save($key2);
66+
}
67+
68+
public function testBackwardCompatibilityBackward()
69+
{
70+
$resource = uniqid(__METHOD__, true);
71+
$key1 = new Key($resource);
72+
$key2 = new Key($resource);
73+
74+
$oldStore = new Symfony51Store($this->getRedisConnection());
75+
$newStore = $this->getStore();
76+
77+
$newStore->save($key1);
78+
$this->assertTrue($newStore->exists($key1));
79+
80+
$this->expectException(LockConflictedException::class);
81+
$oldStore->save($key2);
82+
}
83+
}
84+
85+
class Symfony51Store
86+
{
87+
private $redis;
88+
89+
public function __construct($redis)
90+
{
91+
$this->redis = $redis;
92+
}
93+
94+
public function save(Key $key)
95+
{
96+
$script = '
97+
if redis.call("GET", KEYS[1]) == ARGV[1] then
98+
return redis.call("PEXPIRE", KEYS[1], ARGV[2])
99+
elseif redis.call("SET", KEYS[1], ARGV[1], "NX", "PX", ARGV[2]) then
100+
return 1
101+
else
102+
return 0
103+
end
104+
';
105+
if (!$this->evaluate($script, (string) $key, [$this->getUniqueToken($key), (int) ceil(5 * 1000)])) {
106+
throw new LockConflictedException();
107+
}
108+
}
109+
110+
public function exists(Key $key)
111+
{
112+
return $this->redis->get((string) $key) === $this->getUniqueToken($key);
113+
}
114+
115+
private function evaluate(string $script, string $resource, array $args)
116+
{
117+
if (
118+
$this->redis instanceof \Redis ||
119+
$this->redis instanceof \RedisCluster ||
120+
$this->redis instanceof RedisProxy ||
121+
$this->redis instanceof RedisClusterProxy
122+
) {
123+
return $this->redis->eval($script, array_merge([$resource], $args), 1);
124+
}
125+
126+
if ($this->redis instanceof \RedisArray) {
127+
return $this->redis->_instance($this->redis->_target($resource))->eval($script, array_merge([$resource], $args), 1);
128+
}
129+
130+
if ($this->redis instanceof \Predis\ClientInterface) {
131+
return $this->redis->eval(...array_merge([$script, 1, $resource], $args));
132+
}
133+
134+
throw new InvalidArgumentException(sprintf('"%s()" expects being initialized with a Redis, RedisArray, RedisCluster or Predis\ClientInterface, "%s" given.', __METHOD__, get_debug_type($this->redis)));
135+
}
136+
137+
private function getUniqueToken(Key $key): string
138+
{
139+
if (!$key->hasState(__CLASS__)) {
140+
$token = base64_encode(random_bytes(32));
141+
$key->setState(__CLASS__, $token);
142+
}
143+
144+
return $key->getState(__CLASS__);
145+
}
46146
}

0 commit comments

Comments
 (0)