fakeredis 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +40 -0
- data/Rakefile +26 -0
- data/fakeredis.gemspec +23 -0
- data/lib/fakeredis.rb +26 -0
- data/lib/fakeredis/connection.rb +25 -0
- data/lib/fakeredis/hashes.rb +98 -0
- data/lib/fakeredis/keys.rb +82 -0
- data/lib/fakeredis/lists.rb +108 -0
- data/lib/fakeredis/server.rb +65 -0
- data/lib/fakeredis/sets.rb +122 -0
- data/lib/fakeredis/sorted_sets.rb +108 -0
- data/lib/fakeredis/strings.rb +112 -0
- data/lib/fakeredis/transactions.rb +13 -0
- data/lib/fakeredis/version.rb +3 -0
- data/spec/connection_spec.rb +22 -0
- data/spec/hashes_spec.rb +98 -0
- data/spec/keys_spec.rb +95 -0
- data/spec/lists_spec.rb +134 -0
- data/spec/server_spec.rb +28 -0
- data/spec/sets_spec.rb +153 -0
- data/spec/sorted_sets_spec.rb +81 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/strings_spec.rb +140 -0
- data/spec/transactions_spec.rb +19 -0
- metadata +102 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
module FakeRedis
|
2
|
+
class Redis
|
3
|
+
module ServerMethods
|
4
|
+
|
5
|
+
def bgreriteaof ; end
|
6
|
+
|
7
|
+
def bgsave ; end
|
8
|
+
|
9
|
+
def config_get(param) ; end
|
10
|
+
|
11
|
+
def config_set(param, value) ; end
|
12
|
+
|
13
|
+
def config_resetstat ; end
|
14
|
+
|
15
|
+
def dbsize
|
16
|
+
@data.keys.count
|
17
|
+
end
|
18
|
+
|
19
|
+
def debug_object(key)
|
20
|
+
return @data[key].inspect
|
21
|
+
end
|
22
|
+
|
23
|
+
def flushdb
|
24
|
+
@data = {}
|
25
|
+
@expires = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
alias flushall flushdb
|
29
|
+
|
30
|
+
def info
|
31
|
+
server_info = {
|
32
|
+
"redis_version" => "0.07",
|
33
|
+
"connected_clients" => "1",
|
34
|
+
"connected_slaves" => "0",
|
35
|
+
"used_memory" => "3187",
|
36
|
+
"changes_since_last_save" => "0",
|
37
|
+
"last_save_time" => "1237655729",
|
38
|
+
"total_connections_received" => "1",
|
39
|
+
"total_commands_processed" => "1",
|
40
|
+
"uptime_in_seconds" => "36000",
|
41
|
+
"uptime_in_days" => 0
|
42
|
+
}
|
43
|
+
return server_info
|
44
|
+
end
|
45
|
+
|
46
|
+
def lastsave
|
47
|
+
Time.now.to_i
|
48
|
+
end
|
49
|
+
|
50
|
+
def monitor ; end
|
51
|
+
|
52
|
+
def save ; end
|
53
|
+
|
54
|
+
def shutdown ; end
|
55
|
+
|
56
|
+
def slaveof(host, port) ; end
|
57
|
+
|
58
|
+
def sync ; end
|
59
|
+
|
60
|
+
alias reset flushdb
|
61
|
+
end
|
62
|
+
|
63
|
+
include ServerMethods
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module FakeRedis
|
2
|
+
class Redis
|
3
|
+
module SetsMethods
|
4
|
+
def sadd(key, value)
|
5
|
+
fail_unless_set(key)
|
6
|
+
case set = @data[key]
|
7
|
+
when nil then @data[key] = Set.new([value.to_s])
|
8
|
+
when Set then set.add(value.to_s)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def scard(key)
|
13
|
+
fail_unless_set(key)
|
14
|
+
case set = @data[key]
|
15
|
+
when nil then 0
|
16
|
+
when Set then set.size
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def sdiff(key1, *keys)
|
21
|
+
[key1, *keys].each { |k| fail_unless_set(k) }
|
22
|
+
keys = keys.map { |k| @data[k] || Set.new }
|
23
|
+
keys.inject(@data[key1]) do |memo, set|
|
24
|
+
memo - set
|
25
|
+
end.to_a
|
26
|
+
end
|
27
|
+
|
28
|
+
def sdiffstore(destination, key1, *keys)
|
29
|
+
fail_unless_set(destination)
|
30
|
+
result = sdiff(key1, *keys)
|
31
|
+
@data[destination] = Set.new(result)
|
32
|
+
end
|
33
|
+
|
34
|
+
def sinter(*keys)
|
35
|
+
keys.each { |k| fail_unless_set(k) }
|
36
|
+
return Set.new if keys.any? { |k| @data[k].nil? }
|
37
|
+
keys = keys.map { |k| @data[k] || Set.new }
|
38
|
+
keys.inject do |set, key|
|
39
|
+
set & key
|
40
|
+
end.to_a
|
41
|
+
end
|
42
|
+
|
43
|
+
def sinterstore(destination, *keys)
|
44
|
+
fail_unless_set(destination)
|
45
|
+
result = sinter(*keys)
|
46
|
+
@data[destination] = Set.new(result)
|
47
|
+
end
|
48
|
+
|
49
|
+
def sismember(key, value)
|
50
|
+
fail_unless_set(key)
|
51
|
+
case set = @data[key]
|
52
|
+
when nil then false
|
53
|
+
when Set then set.include?(value.to_s)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def smembers(key)
|
58
|
+
fail_unless_set(key)
|
59
|
+
case set = @data[key]
|
60
|
+
when nil then []
|
61
|
+
when Set then set.to_a
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def smove(source, destination, value)
|
66
|
+
fail_unless_set(destination)
|
67
|
+
if elem = self.srem(source, value)
|
68
|
+
self.sadd(destination, value)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def spop(key)
|
73
|
+
fail_unless_set(key)
|
74
|
+
elem = srandmember(key)
|
75
|
+
srem(key, elem)
|
76
|
+
elem
|
77
|
+
end
|
78
|
+
|
79
|
+
def srandmember(key)
|
80
|
+
fail_unless_set(key)
|
81
|
+
case set = @data[key]
|
82
|
+
when nil then nil
|
83
|
+
when Set then set.to_a[rand(set.size)]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def srem(key, value)
|
88
|
+
fail_unless_set(key)
|
89
|
+
case set = @data[key]
|
90
|
+
when nil then return
|
91
|
+
when Set then set.delete(value.to_s)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def sunion(*keys)
|
96
|
+
keys.each { |k| fail_unless_set(k) }
|
97
|
+
keys = keys.map { |k| @data[k] || Set.new }
|
98
|
+
keys.inject(Set.new) do |set, key|
|
99
|
+
set | key
|
100
|
+
end.to_a
|
101
|
+
end
|
102
|
+
|
103
|
+
def sunionstore(destination, *keys)
|
104
|
+
fail_unless_set(destination)
|
105
|
+
result = sunion(*keys)
|
106
|
+
@data[destination] = Set.new(result)
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def is_a_set?(key)
|
112
|
+
@data[key].is_a?(Set) || @data[key].nil?
|
113
|
+
end
|
114
|
+
|
115
|
+
def fail_unless_set(key)
|
116
|
+
fail "Not a set" unless is_a_set?(key)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
include SetsMethods
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module FakeRedis
|
2
|
+
class Redis
|
3
|
+
module SortedSetsMethods
|
4
|
+
class Elem < String
|
5
|
+
attr_accessor :score
|
6
|
+
def initialize(str="", score)
|
7
|
+
super(str)
|
8
|
+
@score = score
|
9
|
+
end
|
10
|
+
def <=>(other)
|
11
|
+
@score <=> other.score
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class CustomSortedSet < SortedSet
|
16
|
+
attr_accessor :indexed_set
|
17
|
+
def add(o)
|
18
|
+
super(o)
|
19
|
+
@indexed_set ||= Set.new
|
20
|
+
@indexed_set.add(o)
|
21
|
+
end
|
22
|
+
|
23
|
+
def delete(o)
|
24
|
+
super(o)
|
25
|
+
@indexed_set ||= Set.new
|
26
|
+
@indexed_set.delete(o)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def zadd(key, score, value)
|
31
|
+
fail_unless_sorted_set(key)
|
32
|
+
case set = @data[key]
|
33
|
+
when nil then @data[key] = CustomSortedSet.new([Elem.new(value.to_s, score)])
|
34
|
+
when CustomSortedSet then set.delete(value.to_s) ; set.add(Elem.new(value.to_s, score))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def zcard(key)
|
39
|
+
fail_unless_sorted_set(key)
|
40
|
+
case set = @data[key]
|
41
|
+
when nil then 0
|
42
|
+
when CustomSortedSet then set.size
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def zcount(key, min, max)
|
47
|
+
fail_unless_sorted_set(key)
|
48
|
+
case set = @data[key]
|
49
|
+
when nil then 0
|
50
|
+
when CustomSortedSet then set.select{|x| x.score >= min && x.score <= max }.size
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def zincrby(key, incr, value)
|
55
|
+
fail_unless_sorted_set(key)
|
56
|
+
case set = @data[key]
|
57
|
+
when nil then @data[key] = CustomSortedSet.new([Elem.new(value.to_s, incr)])
|
58
|
+
when CustomSortedSet then
|
59
|
+
score = set.to_a.select{|x| x == value.to_s}.first.score
|
60
|
+
set.delete(value.to_s)
|
61
|
+
set.add(Elem.new(value.to_s, score+incr))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def zrange(key, start, stop)
|
66
|
+
fail_unless_sorted_set(key)
|
67
|
+
case set = @data[key]
|
68
|
+
when nil then []
|
69
|
+
when CustomSortedSet then set.indexed_set.to_a[start..stop]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def zrangescore(key, start, stop)
|
74
|
+
fail_unless_sorted_set(key)
|
75
|
+
case set = @data[key]
|
76
|
+
when nil then []
|
77
|
+
when CustomSortedSet then set.to_a.reverse[start..stop]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def zrank(key, value)
|
82
|
+
fail_unless_sorted_set(key)
|
83
|
+
case set = @data[key]
|
84
|
+
when nil then nil
|
85
|
+
when CustomSortedSet then set.to_a.index(value)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def zscore(key, value)
|
90
|
+
case set = @data[key]
|
91
|
+
when nil then 0
|
92
|
+
when CustomSortedSet then set.to_a.select{|x| x == value.to_s}.first.score
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def is_a_sorted_set?(key)
|
99
|
+
@data[key].is_a?(CustomSortedSet) || @data[key].nil?
|
100
|
+
end
|
101
|
+
|
102
|
+
def fail_unless_sorted_set(key)
|
103
|
+
fail "Not a sorted set" unless is_a_sorted_set?(key)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
include SortedSetsMethods
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module FakeRedis
|
2
|
+
class Redis
|
3
|
+
module StringsMethods
|
4
|
+
|
5
|
+
def append(key, value)
|
6
|
+
@data[key] = (@data[key] || "")
|
7
|
+
@data[key] = @data[key] + value.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def decr(key)
|
11
|
+
@data[key] = (@data[key] || "0")
|
12
|
+
@data[key] = (@data[key].to_i - 1).to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def decrby(key, by)
|
16
|
+
@data[key] = (@data[key] || "0")
|
17
|
+
@data[key] = (@data[key].to_i - by.to_i).to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
def get(key)
|
21
|
+
#return if expired?(key)
|
22
|
+
@data[key]
|
23
|
+
end
|
24
|
+
|
25
|
+
def getbit(key, offset)
|
26
|
+
#return if expired?(key)
|
27
|
+
return unless @data[key]
|
28
|
+
@data[key].unpack('B8')[0].split("")[offset]
|
29
|
+
end
|
30
|
+
|
31
|
+
def getrange(key, start, ending)
|
32
|
+
return unless @data[key]
|
33
|
+
@data[key][start..ending]
|
34
|
+
end
|
35
|
+
|
36
|
+
def getset(key, value)
|
37
|
+
return unless @data[key]
|
38
|
+
old_value = @data[key]
|
39
|
+
@data[key] = value
|
40
|
+
return old_value
|
41
|
+
end
|
42
|
+
|
43
|
+
def incr(key)
|
44
|
+
@data[key] = (@data[key] || "0")
|
45
|
+
@data[key] = (@data[key].to_i + 1).to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
def incrby(key, by)
|
49
|
+
@data[key] = (@data[key] || "0")
|
50
|
+
@data[key] = (@data[key].to_i + by.to_i).to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
def mget(*keys)
|
54
|
+
@data.values_at(*keys)
|
55
|
+
end
|
56
|
+
|
57
|
+
def mset(*pairs)
|
58
|
+
pairs.each_slice(2) do |pair|
|
59
|
+
@data[pair[0].to_s] = pair[1].to_s
|
60
|
+
end
|
61
|
+
"OK"
|
62
|
+
end
|
63
|
+
|
64
|
+
def msetnx(*pairs)
|
65
|
+
keys = []
|
66
|
+
pairs.each_with_index{|item, index| keys << item.to_s if index % 2 == 0}
|
67
|
+
return if keys.any?{|key| @data.key?(key) }
|
68
|
+
mset(*pairs)
|
69
|
+
true
|
70
|
+
end
|
71
|
+
|
72
|
+
def set(key, value)
|
73
|
+
@data[key] = value.to_s
|
74
|
+
"OK"
|
75
|
+
end
|
76
|
+
|
77
|
+
def setbit(key, offset, bit)
|
78
|
+
return unless @data[key]
|
79
|
+
old_val = @data[key].unpack('B*')[0].split("")
|
80
|
+
old_val[offset] = bit.to_s
|
81
|
+
new_val = ""
|
82
|
+
old_val.each_slice(8){|b| new_val = new_val + b.join("").to_i(2).chr }
|
83
|
+
@data[key] = new_val
|
84
|
+
end
|
85
|
+
|
86
|
+
def setex(key, seconds, value)
|
87
|
+
@data[key] = value
|
88
|
+
expire(key, seconds)
|
89
|
+
end
|
90
|
+
|
91
|
+
def setnx(key, value)
|
92
|
+
set(key, value) unless @data.key?(key)
|
93
|
+
end
|
94
|
+
|
95
|
+
def setrange(key, offset, value)
|
96
|
+
return unless @data[key]
|
97
|
+
s = @data[key][offset,value.size]
|
98
|
+
@data[key][s] = value
|
99
|
+
end
|
100
|
+
|
101
|
+
def strlen(key)
|
102
|
+
return unless @data[key]
|
103
|
+
@data[key].size
|
104
|
+
end
|
105
|
+
|
106
|
+
alias [] get
|
107
|
+
alias []= set
|
108
|
+
end
|
109
|
+
|
110
|
+
include StringsMethods
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module FakeRedis
|
4
|
+
describe "ConnectionMethods" do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@client = FakeRedis::Redis.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should authenticate to the server" do
|
11
|
+
@client.auth("pass").should == true
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should echo the given string" do
|
15
|
+
@client.echo("something").should == "something"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should ping the server" do
|
19
|
+
@client.ping.should == "PONG"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|