redstruct 0.1.7 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +15 -11
- data/Rakefile +5 -5
- data/lib/redstruct/all.rb +14 -0
- data/lib/redstruct/configuration.rb +9 -6
- data/lib/redstruct/connection_proxy.rb +123 -0
- data/lib/redstruct/counter.rb +96 -0
- data/lib/redstruct/error.rb +2 -0
- data/lib/redstruct/factory/object.rb +31 -0
- data/lib/redstruct/factory.rb +94 -55
- data/lib/redstruct/hash.rb +123 -0
- data/lib/redstruct/list.rb +315 -0
- data/lib/redstruct/lock.rb +183 -0
- data/lib/redstruct/script.rb +104 -0
- data/lib/redstruct/set.rb +155 -0
- data/lib/redstruct/sorted_set/slice.rb +124 -0
- data/lib/redstruct/sorted_set.rb +153 -0
- data/lib/redstruct/string.rb +66 -0
- data/lib/redstruct/struct.rb +87 -0
- data/lib/redstruct/utils/coercion.rb +14 -8
- data/lib/redstruct/utils/inspectable.rb +8 -4
- data/lib/redstruct/utils/iterable.rb +52 -0
- data/lib/redstruct/utils/scriptable.rb +32 -6
- data/lib/redstruct/version.rb +4 -1
- data/lib/redstruct.rb +17 -51
- data/lib/yard/defscript_handler.rb +5 -3
- data/test/redstruct/configuration_test.rb +13 -0
- data/test/redstruct/connection_proxy_test.rb +85 -0
- data/test/redstruct/counter_test.rb +108 -0
- data/test/redstruct/factory/object_test.rb +21 -0
- data/test/redstruct/factory_test.rb +136 -0
- data/test/redstruct/hash_test.rb +138 -0
- data/test/redstruct/list_test.rb +244 -0
- data/test/redstruct/lock_test.rb +108 -0
- data/test/redstruct/script_test.rb +53 -0
- data/test/redstruct/set_test.rb +219 -0
- data/test/redstruct/sorted_set/slice_test.rb +10 -0
- data/test/redstruct/sorted_set_test.rb +219 -0
- data/test/redstruct/string_test.rb +8 -0
- data/test/redstruct/struct_test.rb +61 -0
- data/test/redstruct/utils/coercion_test.rb +33 -0
- data/test/redstruct/utils/inspectable_test.rb +31 -0
- data/test/redstruct/utils/iterable_test.rb +94 -0
- data/test/redstruct/utils/scriptable_test.rb +67 -0
- data/test/redstruct_test.rb +14 -0
- data/test/test_helper.rb +77 -1
- metadata +58 -26
- data/lib/redstruct/connection.rb +0 -47
- data/lib/redstruct/factory/creation.rb +0 -95
- data/lib/redstruct/factory/deserialization.rb +0 -7
- data/lib/redstruct/hls/lock.rb +0 -175
- data/lib/redstruct/hls/queue.rb +0 -29
- data/lib/redstruct/hls.rb +0 -2
- data/lib/redstruct/types/base.rb +0 -36
- data/lib/redstruct/types/counter.rb +0 -65
- data/lib/redstruct/types/hash.rb +0 -72
- data/lib/redstruct/types/list.rb +0 -76
- data/lib/redstruct/types/script.rb +0 -56
- data/lib/redstruct/types/set.rb +0 -96
- data/lib/redstruct/types/sorted_set.rb +0 -129
- data/lib/redstruct/types/string.rb +0 -64
- data/lib/redstruct/types/struct.rb +0 -58
- data/lib/releaser/logger.rb +0 -15
- data/lib/releaser/repository.rb +0 -32
- data/lib/tasks/release.rake +0 -49
- data/test/redstruct/restruct_test.rb +0 -4
@@ -0,0 +1,138 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
module Redstruct
|
6
|
+
class HashTest < Redstruct::Test
|
7
|
+
def setup
|
8
|
+
super
|
9
|
+
@factory = create_factory
|
10
|
+
@hash = @factory.hashmap('hash')
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_brackets
|
14
|
+
value = SecureRandom.hex(4)
|
15
|
+
assert_nil @hash['test'], 'should return nil for non-existent element'
|
16
|
+
@hash['test'] = value
|
17
|
+
assert_equal value, @hash['test'], 'should return the correct value'
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_get_one
|
21
|
+
value = SecureRandom.hex(4)
|
22
|
+
assert_nil @hash.get('a'), 'should return nil for non-existent element'
|
23
|
+
@hash['a'] = value
|
24
|
+
assert_equal value, @hash.get('a'), 'should return correct value'
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_get_multiple
|
28
|
+
hash = { 'a' => SecureRandom.hex(4), 'b' => SecureRandom.hex(4) }
|
29
|
+
assert_equal({}, @hash.get('a', 'b'), 'should return a empty hash for non existent keys')
|
30
|
+
@hash.update(hash)
|
31
|
+
assert_equal hash, @hash.get('a', 'b'), 'should return the correct hash for requested keys'
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_set
|
35
|
+
value = SecureRandom.hex(4)
|
36
|
+
assert_nil @hash['a'], 'should return nothing'
|
37
|
+
@hash.set('a', value)
|
38
|
+
assert_equal value, @hash['a'], 'should return the correct value'
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_set_overwrite
|
42
|
+
initial = SecureRandom.hex(4)
|
43
|
+
updated = SecureRandom.hex(4)
|
44
|
+
|
45
|
+
@hash.set('a', initial)
|
46
|
+
@hash.set('a', updated, overwrite: false)
|
47
|
+
assert_equal initial, @hash['a'], 'should not have overwritten the initial value'
|
48
|
+
@hash.set('a', updated, overwrite: true)
|
49
|
+
assert_equal updated, @hash['a'], 'should have overwritten the initial value'
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_update
|
53
|
+
initial = { 'a' => SecureRandom.hex(4), 'b' => SecureRandom.hex(4) }
|
54
|
+
assert @hash.empty?, 'initial should be empty'
|
55
|
+
@hash.update(initial)
|
56
|
+
assert_equal initial, @hash.to_h, 'should have been updated accordingly'
|
57
|
+
|
58
|
+
updated = { 'a' => SecureRandom.hex(4), 'c' => SecureRandom.hex(4) }
|
59
|
+
@hash.update(updated)
|
60
|
+
assert_equal initial.merge(updated), @hash.to_h, 'should have been updated correctly'
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_empty?
|
64
|
+
assert @hash.empty?, 'should initially be empty'
|
65
|
+
@hash['a'] = 1
|
66
|
+
refute @hash.empty?, 'should not be empty with one element'
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_remove
|
70
|
+
@hash['a'] = 'a'
|
71
|
+
assert @hash.key?('a'), 'should contain something for key a'
|
72
|
+
@hash.remove('a')
|
73
|
+
refute @hash.key?('a'), 'should not contain the key a anymore'
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_key?
|
77
|
+
refute @hash.key?('a'), 'should not contain the key a initially'
|
78
|
+
@hash['a'] = 1
|
79
|
+
assert @hash.key?('a'), 'should now contain the key a'
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_increment
|
83
|
+
assert_equal 1, @hash.increment('a'), 'initial increment should return 1'
|
84
|
+
assert_equal 2, @hash.increment('a'), 'second increment should return 2'
|
85
|
+
assert_equal 3.5, @hash.increment('a', by: 1.5), 'should return 3.5'
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_decrement
|
89
|
+
assert_equal(-1, @hash.decrement('a'), 'initial decrement should return -1')
|
90
|
+
assert_equal(-2, @hash.decrement('a'), 'second decrement should return -2')
|
91
|
+
assert_equal(-3.5, @hash.decrement('a', by: 1.5), 'should return -3.5')
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_keys
|
95
|
+
hash = { 'a' => 'b', 'b' => 'a' }
|
96
|
+
assert_equal [], @hash.keys, 'should initially return no keys initially'
|
97
|
+
@hash.update(hash)
|
98
|
+
assert_equal hash.keys, @hash.keys, 'should return the same keys after an update'
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_values
|
102
|
+
hash = { 'a' => 'b', 'b' => 'a' }
|
103
|
+
assert_equal [], @hash.values, 'should initially return no values initially'
|
104
|
+
@hash.update(hash)
|
105
|
+
assert_equal hash.values, @hash.values, 'should return the same values after an update'
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_to_h
|
109
|
+
hash = { 'a' => 'b', 'b' => 'a' }
|
110
|
+
assert_equal({}, @hash.to_h, 'should be an empty hash initially')
|
111
|
+
@hash.update(hash)
|
112
|
+
assert_equal hash, @hash.to_h, 'should return the whole hash as a standard ruby hash'
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_size
|
116
|
+
hash = { 'a' => 'b', 'b' => 'a' }
|
117
|
+
assert_equal 0, @hash.size, 'should be an empty hash initially'
|
118
|
+
@hash.update(hash)
|
119
|
+
assert_equal 2, @hash.size, 'should return the correct amount of pairs'
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_each
|
123
|
+
hash = { 'a' => 'b', 'b' => 'a' }
|
124
|
+
keys = hash.keys
|
125
|
+
values = hash.values
|
126
|
+
|
127
|
+
@hash.update(hash)
|
128
|
+
@hash.each do |key, value|
|
129
|
+
keys.delete(key)
|
130
|
+
values.delete(value)
|
131
|
+
assert_equal hash[key], value, 'should return the correct key-value-pair'
|
132
|
+
end
|
133
|
+
|
134
|
+
assert_empty keys, 'should have no more keys left to match'
|
135
|
+
assert_empty values, 'should have no more values to match'
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
module Redstruct
|
6
|
+
class ListTest < Redstruct::Test
|
7
|
+
def setup
|
8
|
+
super
|
9
|
+
@factory = create_factory
|
10
|
+
@list = @factory.list('list')
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_clear
|
14
|
+
@list.append(1, 2, 3)
|
15
|
+
refute @list.empty?, 'should not be empty'
|
16
|
+
@list.clear
|
17
|
+
assert @list.empty?, 'should be empty after a clear operation'
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_empty?
|
21
|
+
assert @list.empty?, 'should be initially empty'
|
22
|
+
@list.push(1)
|
23
|
+
refute @list.empty?, 'should not be empty anymore'
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_brackets
|
27
|
+
(0..2).each do |i|
|
28
|
+
value = SecureRandom.hex(4)
|
29
|
+
assert_nil @list[i], 'should return nothing initially'
|
30
|
+
@list[i] = value
|
31
|
+
assert_equal value, @list[i], 'should return the correct value'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_insert_single
|
36
|
+
initial = SecureRandom.hex(4)
|
37
|
+
assert_raises(Redis::CommandError, 'should fail (out of bounds)') do
|
38
|
+
@list.insert(initial, 1)
|
39
|
+
end
|
40
|
+
|
41
|
+
assert @list.insert(initial, 0), 'should insert correctly first element'
|
42
|
+
assert_equal initial, @list[0]
|
43
|
+
|
44
|
+
assert @list.insert(initial, 1), 'should insert correctly second element'
|
45
|
+
assert_equal initial, @list[1]
|
46
|
+
|
47
|
+
value = SecureRandom.hex(4)
|
48
|
+
assert @list.insert(value, 1), 'should insert correctly between both'
|
49
|
+
assert_equal value, @list[1], 'should have new value at index 1'
|
50
|
+
assert_equal initial, @list[0], 'should still have correct value as index 0'
|
51
|
+
assert_equal initial, @list[2], 'should still have correct value as index 2'
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_append
|
55
|
+
values = %w[1 2]
|
56
|
+
assert_equal values.size, @list.append(*values), 'should have successfully appended'
|
57
|
+
assert_equal values, @list.to_a, 'should have the correct values stored'
|
58
|
+
|
59
|
+
appended = %w[3 4]
|
60
|
+
expected = values + appended
|
61
|
+
assert_equal expected.size, @list.append(*appended), 'should have successfully appended'
|
62
|
+
assert_equal expected, @list.to_a, 'should have the correct values stored'
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_append_exists
|
66
|
+
values = %w[1 2]
|
67
|
+
refute @list.append(*values, exists: true), 'should not append since the list does not exist'
|
68
|
+
|
69
|
+
@list[0] = 'a'
|
70
|
+
assert @list.append(*values, exists: true), 'should have appended once the list existed'
|
71
|
+
assert_equal %w[a 1 2], @list.to_a, 'should contain correct values'
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_append_max
|
75
|
+
values = %w[1 2]
|
76
|
+
assert @list.append(*values, max: 2), 'should append all elements'
|
77
|
+
assert_equal values, @list.to_a, 'should append all elements'
|
78
|
+
|
79
|
+
assert_equal 2, @list.append(3, max: 2), 'should still return the actual size of the list'
|
80
|
+
assert_equal values, @list.to_a, 'should not have appended the last element'
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_prepend
|
84
|
+
values = %w[1 2]
|
85
|
+
assert_equal values.size, @list.prepend(*values), 'should have successfully prepended'
|
86
|
+
assert_equal values, @list.to_a, 'should have the correct values stored'
|
87
|
+
|
88
|
+
prepended = %w[3 4]
|
89
|
+
expected = prepended + values
|
90
|
+
assert_equal expected.size, @list.prepend(*prepended), 'should have successfully prepended'
|
91
|
+
assert_equal expected, @list.to_a, 'should have the correct values stored'
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_prepend_exists
|
95
|
+
values = %w[1 2]
|
96
|
+
refute @list.prepend(*values, exists: true), 'should not prepend since the list does not exist'
|
97
|
+
|
98
|
+
@list[0] = 'a'
|
99
|
+
assert @list.prepend(*values, exists: true), 'should have prepended once the list existed'
|
100
|
+
assert_equal %w[1 2 a], @list.to_a, 'should contain correct values'
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_prepend_max
|
104
|
+
values = %w[1 2]
|
105
|
+
assert @list.prepend(*values, max: 2), 'should prepend all elements'
|
106
|
+
assert_equal values, @list.to_a, 'should append all elements'
|
107
|
+
|
108
|
+
assert_equal 2, @list.prepend(3, max: 2), 'should still return the actual size of the list'
|
109
|
+
assert_equal %w[3 1], @list.to_a, 'should not have prepended the last element'
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_pop_single
|
113
|
+
assert @list.empty?, 'should be empty initially'
|
114
|
+
@list.append('a', 'b')
|
115
|
+
|
116
|
+
assert_equal 'b', @list.pop, 'should have popped the last element'
|
117
|
+
assert_equal %w[a], @list.to_a, 'should have only one element left'
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_pop_multiple
|
121
|
+
assert @list.empty?, 'should be empty initially'
|
122
|
+
@list.append('a', 'b', 'c')
|
123
|
+
|
124
|
+
assert_equal %w[b c], @list.pop(2), 'should have popped the last 2 elements'
|
125
|
+
assert_equal %w[a], @list.to_a, 'should have only one element left'
|
126
|
+
end
|
127
|
+
|
128
|
+
# TODO: not the ideal way to test this, but what would be a better way?
|
129
|
+
def test_pop_timeout
|
130
|
+
assert @list.empty?, 'should be empty initially'
|
131
|
+
|
132
|
+
Thread.new do
|
133
|
+
sleep 0.2
|
134
|
+
@list.push('a', 'b')
|
135
|
+
end
|
136
|
+
|
137
|
+
assert_equal 'b', @list.pop(timeout: 3), 'should have returned the correct element'
|
138
|
+
assert_raises(ArgumentError, 'should not allow timeout with size > 1') do
|
139
|
+
@list.pop(5, timeout: 1)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_shift_single
|
144
|
+
assert @list.empty?, 'should be empty initially'
|
145
|
+
@list.append('a', 'b')
|
146
|
+
|
147
|
+
assert_equal 'a', @list.shift, 'should have shifted the first element'
|
148
|
+
assert_equal %w[b], @list.to_a, 'should have only one element left'
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_shift_multiple
|
152
|
+
assert @list.empty?, 'should be empty initially'
|
153
|
+
@list.append('a', 'b', 'c')
|
154
|
+
|
155
|
+
assert_equal %w[a b], @list.shift(2), 'should have shifted the first 2 elements'
|
156
|
+
assert_equal %w[c], @list.to_a, 'should have only one element left'
|
157
|
+
end
|
158
|
+
|
159
|
+
# TODO: not the ideal way to test this, but what would be a better way?
|
160
|
+
def test_shift_timeout
|
161
|
+
assert @list.empty?, 'should be empty initially'
|
162
|
+
|
163
|
+
Thread.new do
|
164
|
+
sleep 0.2
|
165
|
+
@list.push('a', 'b')
|
166
|
+
end
|
167
|
+
|
168
|
+
assert_equal 'a', @list.shift(timeout: 3), 'should have returned the correct element'
|
169
|
+
assert_raises(ArgumentError, 'should not allow timeout with size > 1') do
|
170
|
+
@list.shift(5, timeout: 1)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_remove_left
|
175
|
+
@list.append('a', 'b', 'a', 'b', 'a', 'b')
|
176
|
+
assert_equal 1, @list.remove('a', count: 1), 'should remove 1 element equal to the value from left'
|
177
|
+
assert_equal %w[b a b a b], @list.to_a, 'should have removed first a only'
|
178
|
+
assert_equal 2, @list.remove('b', count: 2), 'should remove both bs'
|
179
|
+
assert_equal %w[a a b], @list.to_a, 'should have only the last b left'
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_remove_right
|
183
|
+
@list.append('a', 'b', 'a', 'b', 'a', 'b')
|
184
|
+
assert_equal 1, @list.remove('a', count: -1), 'should remove 1 element equal to the value from the right'
|
185
|
+
assert_equal %w[a b a b b], @list.to_a, 'should have removed last a only'
|
186
|
+
assert_equal 2, @list.remove('b', count: -2), 'should remove the last 2 bs'
|
187
|
+
assert_equal %w[a b a], @list.to_a, 'should have only the middle b left'
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_remove_all
|
191
|
+
@list.append('a', 'b', 'b', 'a')
|
192
|
+
assert_equal 2, @list.remove('a', count: 0), 'should remove all elements equal to the given value'
|
193
|
+
assert_equal %w[b b], @list.to_a, 'should have only the other values left'
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_size
|
197
|
+
assert_equal 0, @list.size, 'should have size 0 initially'
|
198
|
+
@list.push(1, 2)
|
199
|
+
assert_equal 2, @list.size, 'should have the same amount that was pushed'
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_to_a
|
203
|
+
expected = %w[a b c]
|
204
|
+
assert_equal [], @list.to_a, 'should return empty array initially'
|
205
|
+
@list.push(*expected)
|
206
|
+
assert_equal expected, @list.to_a, 'should return what was pushed'
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_slice_positive
|
210
|
+
values = %w[a b c d e f g]
|
211
|
+
assert_equal [], @list.slice, 'should return nothing initially'
|
212
|
+
@list.push(*values)
|
213
|
+
|
214
|
+
assert_equal values.slice(0, 1), @list.slice(start: 0, length: 1), 'should return the same as Array#slice'
|
215
|
+
assert_equal values.slice(2, 3), @list.slice(start: 2, length: 3), 'should return the same as Array#slice'
|
216
|
+
end
|
217
|
+
|
218
|
+
def test_slice_negative
|
219
|
+
values = %w[a b c d e f g]
|
220
|
+
assert_equal [], @list.slice, 'should return nothing initially'
|
221
|
+
@list.push(*values)
|
222
|
+
|
223
|
+
assert_equal values, @list.slice(start: 0, length: -1), 'should return the same as Array#slice'
|
224
|
+
assert_equal values[2..-2], @list.slice(start: 2, length: -2), 'should return the same as Array#slice'
|
225
|
+
end
|
226
|
+
|
227
|
+
# Blocking is not tested as I'm still unsure what's a good way to test it
|
228
|
+
def test_popshift
|
229
|
+
assert_raises(ArgumentError, 'should not be able to push on something that is not a list') do
|
230
|
+
@list.popshift(2)
|
231
|
+
end
|
232
|
+
|
233
|
+
values = %w[a b c]
|
234
|
+
list2 = @factory.list('list2')
|
235
|
+
|
236
|
+
@list.push(*values)
|
237
|
+
assert_equal 'c', @list.popshift(list2), 'should have popped the last element'
|
238
|
+
assert_equal %w[c], list2.to_a, 'should contain the popped element'
|
239
|
+
|
240
|
+
assert_equal 'b', @list.popshift(list2), 'should have popped the last element'
|
241
|
+
assert_equal %w[b c], list2.to_a, 'should contain the new popped element as its first element'
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
module Redstruct
|
6
|
+
class LockTest < Redstruct::Test
|
7
|
+
def setup
|
8
|
+
super
|
9
|
+
@factory = create_factory
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_initialize
|
13
|
+
resource = 'resource'
|
14
|
+
lock = create(resource)
|
15
|
+
|
16
|
+
assert_equal resource, lock.resource, 'should be locking the correct resource'
|
17
|
+
assert_nil lock.token, 'should not hold any tokens at the moment'
|
18
|
+
assert_equal Redstruct::Lock::DEFAULT_EXPIRY, lock.expiry, 'should have the default expiry'
|
19
|
+
assert_equal Redstruct::Lock::DEFAULT_TIMEOUT, lock.timeout, 'should have the default timeout'
|
20
|
+
|
21
|
+
expiry = rand
|
22
|
+
timeout = rand(10)
|
23
|
+
lock = create(timeout: timeout, expiry: expiry)
|
24
|
+
assert_equal expiry, lock.expiry, 'should have the correct expiry'
|
25
|
+
assert_equal timeout, lock.timeout, 'should have the correct timeout'
|
26
|
+
|
27
|
+
lock = create(timeout: Float::INFINITY)
|
28
|
+
assert_equal 0, lock.timeout, 'should have a timeout of 0 when given infinity'
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_acquire
|
32
|
+
resource = 'resource'
|
33
|
+
lock = create(resource)
|
34
|
+
|
35
|
+
f1 = Fiber.new do
|
36
|
+
lock1 = create(resource)
|
37
|
+
Fiber.yield lock1.acquire
|
38
|
+
Fiber.yield lock1.release
|
39
|
+
Fiber.yield lock1.acquire
|
40
|
+
end
|
41
|
+
|
42
|
+
f2 = Fiber.new do
|
43
|
+
lock2 = create(resource)
|
44
|
+
Fiber.yield lock2.acquire
|
45
|
+
Fiber.yield lock2.acquire
|
46
|
+
Fiber.yield lock2.release
|
47
|
+
end
|
48
|
+
|
49
|
+
assert f1.resume, 'should have successfully acquired the lock'
|
50
|
+
refute f2.resume, 'should have failed to acquire the lock'
|
51
|
+
assert f1.resume, 'should have released the lock'
|
52
|
+
assert f2.resume, 'should have acquired the lock'
|
53
|
+
refute f1.resume, 'should have failed to acquire the lock'
|
54
|
+
refute lock.acquire, 'should have failed to acquire the lock'
|
55
|
+
assert f2.resume, 'should have released the lock'
|
56
|
+
assert lock.acquire, 'should have successfully acquired the lock'
|
57
|
+
assert lock.release, 'should have released the lock'
|
58
|
+
end
|
59
|
+
|
60
|
+
# To avoid actually blocking, we simply test that the method is called
|
61
|
+
# without actually calling it. The non-blocking tests should be
|
62
|
+
# sufficient for the actual locking logic.
|
63
|
+
def test_acquire_blocking
|
64
|
+
resource = 'resource'
|
65
|
+
lock = create(resource, expiry: 1)
|
66
|
+
lock2 = create(resource, timeout: 1)
|
67
|
+
|
68
|
+
tokens = lock2.instance_eval { @tokens }
|
69
|
+
ensure_command_called(tokens, :brpop, { timeout: lock2.timeout }, allow: false).and_return(nil)
|
70
|
+
|
71
|
+
assert lock.acquire, 'should have acquired the lock'
|
72
|
+
refute lock2.acquire
|
73
|
+
refute lock2.release, 'should not release something not acquired'
|
74
|
+
assert lock.release, 'should release what was acquired'
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_release
|
78
|
+
lock = create
|
79
|
+
refute lock.release, 'should not be able to release if nothing was acquired'
|
80
|
+
assert lock.acquire, 'should acquire the lock'
|
81
|
+
refute_nil lock.token, 'should have some token'
|
82
|
+
assert lock.release, 'should release the acquired lock'
|
83
|
+
assert_nil lock.token, 'should have no token once released'
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_locked
|
87
|
+
resource = 'resource'
|
88
|
+
lock = create(resource)
|
89
|
+
lock2 = create(resource)
|
90
|
+
|
91
|
+
assert lock2.acquire, 'should be able to acquire free lock'
|
92
|
+
refute(lock.locked { raise 'should not have been able to lock!' })
|
93
|
+
assert lock2.release, 'should be able to release acquired lock'
|
94
|
+
|
95
|
+
executed = false
|
96
|
+
assert(lock.locked { executed = true }, 'should have acquired the lock')
|
97
|
+
assert executed, 'should have executed inner block'
|
98
|
+
assert_nil lock.token, 'should have released previous token'
|
99
|
+
refute lock.release, 'should not be able to release lock since it was already released'
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def create(resource = nil, **options)
|
105
|
+
return @factory.lock(resource || SecureRandom.hex(4), **options)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
module Redstruct
|
6
|
+
class ScriptTest < Redstruct::Test
|
7
|
+
def setup
|
8
|
+
super
|
9
|
+
@value = @@counter.incr
|
10
|
+
@code = "return #{@value}"
|
11
|
+
@factory = create_factory
|
12
|
+
@script = @factory.script(@code)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_initialize
|
16
|
+
assert_equal @code, @script.script, 'should have correct script'
|
17
|
+
assert_equal Digest::SHA1.hexdigest(@code), @script.sha1, 'should have correct sha1'
|
18
|
+
assert_equal @factory.connection, @script.connection, 'should have correct connection'
|
19
|
+
|
20
|
+
script = @factory.script(@code, sha1: 'dummy sha1')
|
21
|
+
assert_equal 'dummy sha1', script.sha1, 'should have accepted our dummy sha1 even if incorrect'
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_script=
|
25
|
+
lua = 'return -1'
|
26
|
+
old_sha1 = @script.sha1
|
27
|
+
new_sha1 = Digest::SHA1.hexdigest(lua)
|
28
|
+
|
29
|
+
@script.script = lua
|
30
|
+
assert_equal lua, @script.script, 'should have correctly assigned the new code'
|
31
|
+
assert_equal new_sha1, @script.sha1, 'should have updated the sha1'
|
32
|
+
refute_equal old_sha1, @script.sha1, 'should have a different sha1 now'
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_exists?
|
36
|
+
refute @script.exists?, 'should not initially exists'
|
37
|
+
@script.load
|
38
|
+
assert @script.exists?, 'script should exists after loading it'
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_load
|
42
|
+
refute @script.exists?, 'should not initially exists'
|
43
|
+
assert_equal @script.sha1, @script.load, 'should return the sha1 of the script'
|
44
|
+
assert @script.exists?, 'should exist after load'
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_eval
|
48
|
+
refute @script.exists?, 'should not exist initially'
|
49
|
+
assert_equal @value, @script.eval, "should execute the script (which returns #{@value})"
|
50
|
+
assert @script.exists?, 'should exist after first evaluation'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|