Skip to content

Commit 0845ad3

Browse files
committed
test: added externallyAcquiredIdentifier tests
1 parent 0816471 commit 0845ad3

File tree

6 files changed

+158
-37
lines changed

6 files changed

+158
-37
lines changed

test/src/RedisMultiSemaphore.test.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import { delay } from '../../src/utils/index'
1010
import { client1 as client } from '../redisClient'
1111
import { downRedisServer, upRedisServer } from '../shell'
1212
import {
13-
catchUnhandledRejection, throwUnhandledRejection, unhandledRejectionSpy
13+
catchUnhandledRejection,
14+
throwUnhandledRejection,
15+
unhandledRejectionSpy
1416
} from '../unhandledRejection'
1517

1618
const timeoutOptions: TimeoutOptions = {
@@ -23,28 +25,28 @@ const timeoutOptions: TimeoutOptions = {
2325
describe('MultiSemaphore', () => {
2426
it('should fail on invalid arguments', () => {
2527
expect(
26-
() => new MultiSemaphore((null as unknown) as Redis, 'key', 5, 2)
28+
() => new MultiSemaphore(null as unknown as Redis, 'key', 5, 2)
2729
).to.throw('"client" is required')
2830
expect(
29-
() => new MultiSemaphore(({} as unknown) as Redis, 'key', 5, 2)
31+
() => new MultiSemaphore({} as unknown as Redis, 'key', 5, 2)
3032
).to.throw('"client" must be instance of ioredis client')
3133
expect(() => new MultiSemaphore(client, '', 5, 2)).to.throw(
3234
'"key" is required'
3335
)
3436
expect(
35-
() => new MultiSemaphore(client, (1 as unknown) as string, 5, 2)
37+
() => new MultiSemaphore(client, 1 as unknown as string, 5, 2)
3638
).to.throw('"key" must be a string')
3739
expect(() => new MultiSemaphore(client, 'key', 0, 2)).to.throw(
3840
'"limit" is required'
3941
)
4042
expect(
41-
() => new MultiSemaphore(client, 'key', ('10' as unknown) as number, 2)
43+
() => new MultiSemaphore(client, 'key', '10' as unknown as number, 2)
4244
).to.throw('"limit" must be a number')
4345
expect(() => new MultiSemaphore(client, 'key', 5, 0)).to.throw(
4446
'"permits" is required'
4547
)
4648
expect(
47-
() => new MultiSemaphore(client, 'key', 5, ('2' as unknown) as number)
49+
() => new MultiSemaphore(client, 'key', 5, '2' as unknown as number)
4850
).to.throw('"permits" must be a number')
4951
})
5052
it('should acquire and release semaphore', async () => {
@@ -136,6 +138,25 @@ describe('MultiSemaphore', () => {
136138
.and.not.include(ids1[1])
137139
.and.not.include(ids1[2])
138140
})
141+
it('should support externally acquired semaphore', async () => {
142+
const externalSemaphore = new MultiSemaphore(client, 'key', 3, 2, {
143+
...timeoutOptions,
144+
refreshInterval: 0
145+
})
146+
const localSemaphore = new MultiSemaphore(client, 'key', 3, 2, {
147+
...timeoutOptions,
148+
externallyAcquiredIdentifier: externalSemaphore.identifier
149+
})
150+
await externalSemaphore.acquire()
151+
await localSemaphore.acquire()
152+
await delay(400)
153+
expect(await client.zrange('semaphore:key', 0, -1)).to.be.eql([
154+
localSemaphore.identifier + '_0',
155+
localSemaphore.identifier + '_1'
156+
])
157+
await localSemaphore.release()
158+
expect(await client.zcard('semaphore:key')).to.be.eql(0)
159+
})
139160
describe('lost lock case', () => {
140161
beforeEach(() => {
141162
catchUnhandledRejection()

test/src/RedisMutex.test.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import { delay } from '../../src/utils/index'
99
import { client1 as client } from '../redisClient'
1010
import { downRedisServer, upRedisServer } from '../shell'
1111
import {
12-
catchUnhandledRejection, throwUnhandledRejection, unhandledRejectionSpy
12+
catchUnhandledRejection,
13+
throwUnhandledRejection,
14+
unhandledRejectionSpy
1315
} from '../unhandledRejection'
1416

1517
const timeoutOptions: TimeoutOptions = {
@@ -21,14 +23,14 @@ const timeoutOptions: TimeoutOptions = {
2123

2224
describe('Mutex', () => {
2325
it('should fail on invalid arguments', () => {
24-
expect(() => new Mutex((null as unknown) as Redis, 'key')).to.throw(
26+
expect(() => new Mutex(null as unknown as Redis, 'key')).to.throw(
2527
'"client" is required'
2628
)
27-
expect(() => new Mutex(({} as unknown) as Redis, 'key')).to.throw(
29+
expect(() => new Mutex({} as unknown as Redis, 'key')).to.throw(
2830
'"client" must be instance of ioredis client'
2931
)
3032
expect(() => new Mutex(client, '')).to.throw('"key" is required')
31-
expect(() => new Mutex(client, (1 as unknown) as string)).to.throw(
33+
expect(() => new Mutex(client, 1 as unknown as string)).to.throw(
3234
'"key" must be a string'
3335
)
3436
})
@@ -92,6 +94,22 @@ describe('Mutex', () => {
9294
await mutex.release()
9395
expect(await client.get('mutex:key')).to.be.eql(null)
9496
})
97+
it('should support externally acquired mutex', async () => {
98+
const externalMutex = new Mutex(client, 'key', {
99+
...timeoutOptions,
100+
refreshInterval: 0
101+
})
102+
const localMutex = new Mutex(client, 'key', {
103+
...timeoutOptions,
104+
externallyAcquiredIdentifier: externalMutex.identifier
105+
})
106+
await externalMutex.acquire()
107+
await localMutex.acquire()
108+
await delay(400)
109+
expect(await client.get('mutex:key')).to.be.eql(localMutex.identifier)
110+
await localMutex.release()
111+
expect(await client.get('mutex:key')).to.be.eql(null)
112+
})
95113
describe('lost lock case', () => {
96114
beforeEach(() => {
97115
catchUnhandledRejection()

test/src/RedisSemaphore.test.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import { delay } from '../../src/utils/index'
99
import { client1 as client } from '../redisClient'
1010
import { downRedisServer, upRedisServer } from '../shell'
1111
import {
12-
catchUnhandledRejection, throwUnhandledRejection, unhandledRejectionSpy
12+
catchUnhandledRejection,
13+
throwUnhandledRejection,
14+
unhandledRejectionSpy
1315
} from '../unhandledRejection'
1416

1517
const timeoutOptions: TimeoutOptions = {
@@ -21,21 +23,21 @@ const timeoutOptions: TimeoutOptions = {
2123

2224
describe('Semaphore', () => {
2325
it('should fail on invalid arguments', () => {
24-
expect(() => new Semaphore((null as unknown) as Redis, 'key', 5)).to.throw(
26+
expect(() => new Semaphore(null as unknown as Redis, 'key', 5)).to.throw(
2527
'"client" is required'
2628
)
27-
expect(() => new Semaphore(({} as unknown) as Redis, 'key', 5)).to.throw(
29+
expect(() => new Semaphore({} as unknown as Redis, 'key', 5)).to.throw(
2830
'"client" must be instance of ioredis client'
2931
)
3032
expect(() => new Semaphore(client, '', 5)).to.throw('"key" is required')
31-
expect(() => new Semaphore(client, (1 as unknown) as string, 5)).to.throw(
33+
expect(() => new Semaphore(client, 1 as unknown as string, 5)).to.throw(
3234
'"key" must be a string'
3335
)
3436
expect(() => new Semaphore(client, 'key', 0)).to.throw(
3537
'"limit" is required'
3638
)
3739
expect(
38-
() => new Semaphore(client, 'key', ('10' as unknown) as number)
40+
() => new Semaphore(client, 'key', '10' as unknown as number)
3941
).to.throw('"limit" must be a number')
4042
})
4143
it('should acquire and release semaphore', async () => {
@@ -125,6 +127,24 @@ describe('Semaphore', () => {
125127
.and.not.include(ids1[1])
126128
.and.not.include(ids1[2])
127129
})
130+
it('should support externally acquired semaphore', async () => {
131+
const externalSemaphore = new Semaphore(client, 'key', 3, {
132+
...timeoutOptions,
133+
refreshInterval: 0
134+
})
135+
const localSemaphore = new Semaphore(client, 'key', 3, {
136+
...timeoutOptions,
137+
externallyAcquiredIdentifier: externalSemaphore.identifier
138+
})
139+
await externalSemaphore.acquire()
140+
await localSemaphore.acquire()
141+
await delay(400)
142+
expect(await client.zrange('semaphore:key', 0, -1)).to.have.members([
143+
localSemaphore.identifier
144+
])
145+
await localSemaphore.release()
146+
expect(await client.zcard('semaphore:key')).to.be.eql(0)
147+
})
128148
describe('lost lock case', () => {
129149
beforeEach(() => {
130150
catchUnhandledRejection()

test/src/RedlockMultiSemaphore.test.ts

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import { delay } from '../../src/utils/index'
1010
import { allClients, client1, client2, client3 } from '../redisClient'
1111
import { downRedisServer, upRedisServer } from '../shell'
1212
import {
13-
catchUnhandledRejection, throwUnhandledRejection, unhandledRejectionSpy
13+
catchUnhandledRejection,
14+
throwUnhandledRejection,
15+
unhandledRejectionSpy
1416
} from '../unhandledRejection'
1517

1618
const timeoutOptions: TimeoutOptions = {
@@ -52,17 +54,16 @@ async function expectZCardAllEql(key: string, count: number) {
5254
describe('RedlockMultiSemaphore', () => {
5355
it('should fail on invalid arguments', () => {
5456
expect(
55-
() => new RedlockMultiSemaphore((null as unknown) as Redis[], 'key', 5, 2)
57+
() => new RedlockMultiSemaphore(null as unknown as Redis[], 'key', 5, 2)
5658
).to.throw('"clients" array is required')
5759
expect(
58-
() => new RedlockMultiSemaphore(([{}] as unknown) as Redis[], 'key', 5, 2)
60+
() => new RedlockMultiSemaphore([{}] as unknown as Redis[], 'key', 5, 2)
5961
).to.throw('"client" must be instance of ioredis client')
6062
expect(() => new RedlockMultiSemaphore(allClients, '', 5, 2)).to.throw(
6163
'"key" is required'
6264
)
6365
expect(
64-
() =>
65-
new RedlockMultiSemaphore(allClients, (1 as unknown) as string, 5, 2)
66+
() => new RedlockMultiSemaphore(allClients, 1 as unknown as string, 5, 2)
6667
).to.throw('"key" must be a string')
6768
expect(() => new RedlockMultiSemaphore(allClients, 'key', 0, 2)).to.throw(
6869
'"limit" is required'
@@ -72,7 +73,7 @@ describe('RedlockMultiSemaphore', () => {
7273
new RedlockMultiSemaphore(
7374
allClients,
7475
'key',
75-
('10' as unknown) as number,
76+
'10' as unknown as number,
7677
2
7778
)
7879
).to.throw('"limit" must be a number')
@@ -85,7 +86,7 @@ describe('RedlockMultiSemaphore', () => {
8586
allClients,
8687
'key',
8788
5,
88-
('2' as unknown) as number
89+
'2' as unknown as number
8990
)
9091
).to.throw('"permits" must be a number')
9192
})
@@ -214,6 +215,31 @@ describe('RedlockMultiSemaphore', () => {
214215
])
215216
await expectZCardAllEql('semaphore:key', 3)
216217
})
218+
it('should support externally acquired semaphore', async () => {
219+
const externalSemaphore = new RedlockMultiSemaphore(
220+
allClients,
221+
'key',
222+
3,
223+
2,
224+
{
225+
...timeoutOptions,
226+
refreshInterval: 0
227+
}
228+
)
229+
const localSemaphore = new RedlockMultiSemaphore(allClients, 'key', 3, 2, {
230+
...timeoutOptions,
231+
externallyAcquiredIdentifier: externalSemaphore.identifier
232+
})
233+
await externalSemaphore.acquire()
234+
await localSemaphore.acquire()
235+
await delay(400)
236+
await expectZRangeAllHaveMembers('semaphore:key', [
237+
localSemaphore.identifier + '_0',
238+
localSemaphore.identifier + '_1'
239+
])
240+
await localSemaphore.release()
241+
await expectZCardAllEql('semaphore:key', 0)
242+
})
217243
describe('lost lock case', () => {
218244
beforeEach(() => {
219245
catchUnhandledRejection()

test/src/RedlockMutex.test.ts

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import { delay } from '../../src/utils/index'
99
import { allClients, client1, client2, client3 } from '../redisClient'
1010
import { downRedisServer, upRedisServer } from '../shell'
1111
import {
12-
catchUnhandledRejection, throwUnhandledRejection, unhandledRejectionSpy
12+
catchUnhandledRejection,
13+
throwUnhandledRejection,
14+
unhandledRejectionSpy
1315
} from '../unhandledRejection'
1416

1517
const timeoutOptions: TimeoutOptions = {
@@ -27,16 +29,16 @@ async function expectGetAll(key: string, value: string | null) {
2729

2830
describe('RedlockMutex', () => {
2931
it('should fail on invalid arguments', () => {
30-
expect(
31-
() => new RedlockMutex((null as unknown) as Redis[], 'key')
32-
).to.throw('"clients" array is required')
33-
expect(
34-
() => new RedlockMutex(([{}] as unknown) as Redis[], 'key')
35-
).to.throw('"client" must be instance of ioredis client')
32+
expect(() => new RedlockMutex(null as unknown as Redis[], 'key')).to.throw(
33+
'"clients" array is required'
34+
)
35+
expect(() => new RedlockMutex([{}] as unknown as Redis[], 'key')).to.throw(
36+
'"client" must be instance of ioredis client'
37+
)
3638
expect(() => new RedlockMutex(allClients, '')).to.throw('"key" is required')
37-
expect(
38-
() => new RedlockMutex(allClients, (1 as unknown) as string)
39-
).to.throw('"key" must be a string')
39+
expect(() => new RedlockMutex(allClients, 1 as unknown as string)).to.throw(
40+
'"key" must be a string'
41+
)
4042
})
4143
it('should acquire and release lock', async () => {
4244
const mutex = new RedlockMutex(allClients, 'key')
@@ -75,6 +77,22 @@ describe('RedlockMutex', () => {
7577
await delay(400)
7678
await expectGetAll('mutex:key', null)
7779
})
80+
it('should support externally acquired mutex', async () => {
81+
const externalMutex = new RedlockMutex(allClients, 'key', {
82+
...timeoutOptions,
83+
refreshInterval: 0
84+
})
85+
const localMutex = new RedlockMutex(allClients, 'key', {
86+
...timeoutOptions,
87+
externallyAcquiredIdentifier: externalMutex.identifier
88+
})
89+
await externalMutex.acquire()
90+
await localMutex.acquire()
91+
await delay(400)
92+
await expectGetAll('mutex:key', localMutex.identifier)
93+
await localMutex.release()
94+
await expectGetAll('mutex:key', null)
95+
})
7896
describe('lost lock case', () => {
7997
beforeEach(() => {
8098
catchUnhandledRejection()

test/src/RedlockSemaphore.test.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import { delay } from '../../src/utils/index'
99
import { allClients, client1, client2, client3 } from '../redisClient'
1010
import { downRedisServer, upRedisServer } from '../shell'
1111
import {
12-
catchUnhandledRejection, throwUnhandledRejection, unhandledRejectionSpy
12+
catchUnhandledRejection,
13+
throwUnhandledRejection,
14+
unhandledRejectionSpy
1315
} from '../unhandledRejection'
1416

1517
const timeoutOptions: TimeoutOptions = {
@@ -51,22 +53,22 @@ async function expectZCardAllEql(key: string, count: number) {
5153
describe('RedlockSemaphore', () => {
5254
it('should fail on invalid arguments', () => {
5355
expect(
54-
() => new RedlockSemaphore((null as unknown) as Redis[], 'key', 5)
56+
() => new RedlockSemaphore(null as unknown as Redis[], 'key', 5)
5557
).to.throw('"clients" array is required')
5658
expect(
57-
() => new RedlockSemaphore(([{}] as unknown) as Redis[], 'key', 5)
59+
() => new RedlockSemaphore([{}] as unknown as Redis[], 'key', 5)
5860
).to.throw('"client" must be instance of ioredis client')
5961
expect(() => new RedlockSemaphore(allClients, '', 5)).to.throw(
6062
'"key" is required'
6163
)
6264
expect(
63-
() => new RedlockSemaphore(allClients, (1 as unknown) as string, 5)
65+
() => new RedlockSemaphore(allClients, 1 as unknown as string, 5)
6466
).to.throw('"key" must be a string')
6567
expect(() => new RedlockSemaphore(allClients, 'key', 0)).to.throw(
6668
'"limit" is required'
6769
)
6870
expect(
69-
() => new RedlockSemaphore(allClients, 'key', ('10' as unknown) as number)
71+
() => new RedlockSemaphore(allClients, 'key', '10' as unknown as number)
7072
).to.throw('"limit" must be a number')
7173
})
7274
it('should acquire and release semaphore', async () => {
@@ -178,6 +180,22 @@ describe('RedlockSemaphore', () => {
178180
])
179181
await expectZCardAllEql('semaphore:key', 3)
180182
})
183+
it('should support externally acquired semaphore', async () => {
184+
const externalSemaphore = new RedlockSemaphore(allClients, 'key', 3, {
185+
...timeoutOptions,
186+
refreshInterval: 0
187+
})
188+
const localSemaphore = new RedlockSemaphore(allClients, 'key', 3, {
189+
...timeoutOptions,
190+
externallyAcquiredIdentifier: externalSemaphore.identifier
191+
})
192+
await externalSemaphore.acquire()
193+
await localSemaphore.acquire()
194+
await delay(400)
195+
await expectZRangeAllEql('semaphore:key', [localSemaphore.identifier])
196+
await localSemaphore.release()
197+
await expectZCardAllEql('semaphore:key', 0)
198+
})
181199
describe('lost lock case', () => {
182200
beforeEach(() => {
183201
catchUnhandledRejection()

0 commit comments

Comments
 (0)