-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlock_test.go
145 lines (137 loc) · 3.53 KB
/
lock_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package redis_lock
import (
"context"
"errors"
"github.com/alehua/redis-lock/mocks"
"github.com/redis/go-redis/v9"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"testing"
"time"
)
func TestClient_TryLock(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
testCases := []struct {
name string
mock func() redis.Cmdable
key string
expiration time.Duration
wantLock *Lock
wantErr error
}{
{
// 加锁成功
name: "locked",
key: "locked-key",
expiration: time.Minute,
mock: func() redis.Cmdable {
res := mocks.NewMockCmdable(ctrl)
res.EXPECT().SetNX(gomock.Any(), "locked-key", gomock.Any(), time.Minute).
Return(redis.NewBoolResult(true, nil))
return res
},
wantLock: &Lock{
key: "locked-key",
expiration: time.Minute,
},
},
{
// mock 网络错误
name: "network error",
key: "network-key",
expiration: time.Minute,
mock: func() redis.Cmdable {
res := mocks.NewMockCmdable(ctrl)
res.EXPECT().SetNX(gomock.Any(), "network-key", gomock.Any(), time.Minute).
Return(redis.NewBoolResult(false, errors.New("network error")))
return res
},
wantErr: errors.New("network error"),
},
{
name: "failed",
key: "failed-key",
expiration: time.Minute,
mock: func() redis.Cmdable {
res := mocks.NewMockCmdable(ctrl)
res.EXPECT().SetNX(gomock.Any(), "failed-key", gomock.Any(), time.Minute).
Return(redis.NewBoolResult(false, nil))
return res
},
wantErr: ErrFailedToPreemptLock,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mockRedisCmd := tc.mock()
client := NewClient(mockRedisCmd)
l, err := client.TryLock(context.Background(), tc.key, tc.expiration)
assert.Equal(t, tc.wantErr, err)
if err != nil {
return
}
assert.Equal(t, mockRedisCmd, l.client)
assert.Equal(t, tc.key, l.key)
assert.Equal(t, tc.expiration, l.expiration)
assert.NotEmpty(t, l.value)
})
}
}
func TestLock_Unlock(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
testCases := []struct {
name string
mock func() redis.Cmdable
wantErr error
}{
{
// 解锁成功
name: "unlocked",
mock: func() redis.Cmdable {
rdb := mocks.NewMockCmdable(ctrl)
cmd := redis.NewCmd(context.Background())
cmd.SetVal(int64(1))
rdb.EXPECT().Eval(gomock.Any(), luaUnLock, gomock.Any(), gomock.Any()).
Return(cmd)
return rdb
},
},
{
// 解锁失败,因为网络问题
name: "network error",
mock: func() redis.Cmdable {
rdb := mocks.NewMockCmdable(ctrl)
cmd := redis.NewCmd(context.Background())
cmd.SetErr(errors.New("network error"))
rdb.EXPECT().Eval(gomock.Any(), luaUnLock, gomock.Any(), gomock.Any()).
Return(cmd)
return rdb
},
wantErr: errors.New("network error"),
},
{
// 解锁失败,锁已经过期,或者被人删了
// 或者是别人的锁
name: "lock not exist",
mock: func() redis.Cmdable {
rdb := mocks.NewMockCmdable(ctrl)
cmd := redis.NewCmd(context.Background())
cmd.SetVal(int64(0))
rdb.EXPECT().Eval(gomock.Any(), luaUnLock, gomock.Any(), gomock.Any()).
Return(cmd)
return rdb
},
wantErr: ErrLockNotHold,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
l := newLock(tc.mock(), "mock-key", "mock value", time.Minute)
err := l.UnLock(context.Background())
require.Equal(t, tc.wantErr, err)
})
}
}