# encoding: utf-8 require File.dirname(__FILE__) + '/spec_helper' describe "redis" do @redis_version = Gem::Version.new(Redis.current.info["redis_version"]) let(:redis_client) { @redis.respond_to?(:_client) ? @redis._client : @redis.client} before(:all) do # use database 15 for testing so we dont accidentally step on your real data @redis = Redis.new :db => 15 end before(:each) do @namespaced = Redis::Namespace.new(:ns, :redis => @redis) @redis.flushdb @redis.set('foo', 'bar') end after(:each) do @redis.flushdb end after(:all) do @redis.quit end # redis-rb 3.3.4+ it "should inject :namespace into connection info" do info = @redis.connection.merge(:namespace => :ns) expect(@namespaced.connection).to eq(info) end it "proxies `client` to the _client and deprecated" do expect(@namespaced.client).to eq(redis_client) end it "proxies `_client` to the _client" do expect(@namespaced._client).to eq(redis_client) end it "should be able to use a namespace" do expect(@namespaced.get('foo')).to eq(nil) @namespaced.set('foo', 'chris') expect(@namespaced.get('foo')).to eq('chris') @redis.set('foo', 'bob') expect(@redis.get('foo')).to eq('bob') @namespaced.incrby('counter', 2) expect(@namespaced.get('counter').to_i).to eq(2) expect(@redis.get('counter')).to eq(nil) expect(@namespaced.type('counter')).to eq('string') end context 'when sending capital commands (issue 68)' do it 'should be able to use a namespace' do @namespaced.send('SET', 'fubar', 'quux') expect(@redis.get('fubar')).to be_nil expect(@namespaced.get('fubar')).to eq 'quux' end end it "should be able to use a namespace with bpop" do @namespaced.rpush "foo", "string" @namespaced.rpush "foo", "ns:string" @namespaced.rpush "foo", "string_no_timeout" expect(@namespaced.blpop("foo", 1)).to eq(["foo", "string"]) expect(@namespaced.blpop("foo", 1)).to eq(["foo", "ns:string"]) expect(@namespaced.blpop("foo")).to eq(["foo", "string_no_timeout"]) expect(@namespaced.blpop("foo", 1)).to eq(nil) end it "should be able to use a namespace with del" do @namespaced.set('foo', 1000) @namespaced.set('bar', 2000) @namespaced.set('baz', 3000) @namespaced.del 'foo' expect(@namespaced.get('foo')).to eq(nil) @namespaced.del 'bar', 'baz' expect(@namespaced.get('bar')).to eq(nil) expect(@namespaced.get('baz')).to eq(nil) end it "should be able to use a namespace with unlink" do @namespaced.set('foo', 1000) @namespaced.set('bar', 2000) @namespaced.set('baz', 3000) @namespaced.unlink 'foo' expect(@namespaced.get('foo')).to eq(nil) @namespaced.unlink 'bar', 'baz' expect(@namespaced.get('bar')).to eq(nil) expect(@namespaced.get('baz')).to eq(nil) end it 'should be able to use a namespace with append' do @namespaced.set('foo', 'bar') expect(@namespaced.append('foo','n')).to eq(4) expect(@namespaced.get('foo')).to eq('barn') expect(@redis.get('foo')).to eq('bar') end it 'should be able to use a namespace with brpoplpush' do @namespaced.lpush('foo','bar') expect(@namespaced.brpoplpush('foo','bar',0)).to eq('bar') expect(@namespaced.lrange('foo',0,-1)).to eq([]) expect(@namespaced.lrange('bar',0,-1)).to eq(['bar']) end it 'should be able to use a namespace with getbit' do @namespaced.set('foo','bar') expect(@namespaced.getbit('foo',1)).to eq(1) end it 'should be able to use a namespace with getrange' do @namespaced.set('foo','bar') expect(@namespaced.getrange('foo',0,-1)).to eq('bar') end it 'should be able to use a namespace with linsert' do @namespaced.rpush('foo','bar') @namespaced.rpush('foo','barn') @namespaced.rpush('foo','bart') expect(@namespaced.linsert('foo','BEFORE','barn','barf')).to eq(4) expect(@namespaced.lrange('foo',0,-1)).to eq(['bar','barf','barn','bart']) end it 'should be able to use a namespace with lpushx' do expect(@namespaced.lpushx('foo','bar')).to eq(0) @namespaced.lpush('foo','boo') expect(@namespaced.lpushx('foo','bar')).to eq(2) expect(@namespaced.lrange('foo',0,-1)).to eq(['bar','boo']) end it 'should be able to use a namespace with rpushx' do expect(@namespaced.rpushx('foo','bar')).to eq(0) @namespaced.lpush('foo','boo') expect(@namespaced.rpushx('foo','bar')).to eq(2) expect(@namespaced.lrange('foo',0,-1)).to eq(['boo','bar']) end it 'should be able to use a namespace with setbit' do @namespaced.setbit('virgin_key', 1, 1) expect(@namespaced.exists('virgin_key')).to be true expect(@namespaced.get('virgin_key')).to eq(@namespaced.getrange('virgin_key',0,-1)) end it 'should be able to use a namespace with bitpos' do @namespaced.setbit('bit_map', 42, 1) expect(@namespaced.bitpos('bit_map', 0)).to eq(0) expect(@namespaced.bitpos('bit_map', 1)).to eq(42) end it 'should be able to use a namespace with setrange' do @namespaced.setrange('foo', 0, 'bar') expect(@namespaced.get('foo')).to eq('bar') @namespaced.setrange('bar', 2, 'foo') expect(@namespaced.get('bar')).to eq("\000\000foo") end it "should be able to use a namespace with mget" do @namespaced.set('foo', 1000) @namespaced.set('bar', 2000) expect(@namespaced.mapped_mget('foo', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000' }) expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({'foo'=>'1000', 'bar'=>'2000', 'baz' => nil}) end it "should be able to use a namespace with mset" do @namespaced.mset('foo', '1000', 'bar', '2000') expect(@namespaced.mapped_mget('foo', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000' }) expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000', 'baz' => nil}) @namespaced.mapped_mset('foo' => '3000', 'bar' => '5000') expect(@namespaced.mapped_mget('foo', 'bar')).to eq({ 'foo' => '3000', 'bar' => '5000' }) expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({ 'foo' => '3000', 'bar' => '5000', 'baz' => nil}) end it "should be able to use a namespace with msetnx" do @namespaced.msetnx('foo', '1000', 'bar', '2000') expect(@namespaced.mapped_mget('foo', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000' }) expect(@namespaced.mapped_mget('foo', 'baz', 'bar')).to eq({ 'foo' => '1000', 'bar' => '2000', 'baz' => nil}) end it "should be able to use a namespace with mapped_msetnx" do @namespaced.set('foo','1') expect(@namespaced.mapped_msetnx('foo'=>'1000', 'bar'=>'2000')).to be false expect(@namespaced.mapped_mget('foo', 'bar')).to eq({ 'foo' => '1', 'bar' => nil }) expect(@namespaced.mapped_msetnx('bar'=>'2000', 'baz'=>'1000')).to be true expect(@namespaced.mapped_mget('foo', 'bar')).to eq({ 'foo' => '1', 'bar' => '2000' }) end it "should be able to use a namespace with hashes" do @namespaced.hset('foo', 'key', 'value') @namespaced.hset('foo', 'key1', 'value1') expect(@namespaced.hget('foo', 'key')).to eq('value') expect(@namespaced.hgetall('foo')).to eq({'key' => 'value', 'key1' => 'value1'}) expect(@namespaced.hlen('foo')).to eq(2) expect(@namespaced.hkeys('foo')).to eq(['key', 'key1']) @namespaced.hmset('bar', 'key', 'value', 'key1', 'value1') @namespaced.hmget('bar', 'key', 'key1') @namespaced.hmset('bar', 'a_number', 1) expect(@namespaced.hmget('bar', 'a_number')).to eq(['1']) @namespaced.hincrby('bar', 'a_number', 3) expect(@namespaced.hmget('bar', 'a_number')).to eq(['4']) expect(@namespaced.hgetall('bar')).to eq({'key' => 'value', 'key1' => 'value1', 'a_number' => '4'}) expect(@namespaced.hsetnx('foonx','nx',10)).to be true expect(@namespaced.hsetnx('foonx','nx',12)).to be false expect(@namespaced.hget('foonx','nx')).to eq("10") expect(@namespaced.hkeys('foonx')).to eq(%w{ nx }) expect(@namespaced.hvals('foonx')).to eq(%w{ 10 }) @namespaced.mapped_hmset('baz', {'key' => 'value', 'key1' => 'value1', 'a_number' => 4}) expect(@namespaced.mapped_hmget('baz', 'key', 'key1', 'a_number')).to eq({'key' => 'value', 'key1' => 'value1', 'a_number' => '4'}) expect(@namespaced.hgetall('baz')).to eq({'key' => 'value', 'key1' => 'value1', 'a_number' => '4'}) end it "should properly intersect three sets" do @namespaced.sadd('foo', 1) @namespaced.sadd('foo', 2) @namespaced.sadd('foo', 3) @namespaced.sadd('bar', 2) @namespaced.sadd('bar', 3) @namespaced.sadd('bar', 4) @namespaced.sadd('baz', 3) expect(@namespaced.sinter('foo', 'bar', 'baz')).to eq(%w( 3 )) end it "should properly union two sets" do @namespaced.sadd('foo', 1) @namespaced.sadd('foo', 2) @namespaced.sadd('bar', 2) @namespaced.sadd('bar', 3) @namespaced.sadd('bar', 4) expect(@namespaced.sunion('foo', 'bar').sort).to eq(%w( 1 2 3 4 )) end it "should properly union two sorted sets with options" do @namespaced.zadd('sort1', 1, 1) @namespaced.zadd('sort1', 2, 2) @namespaced.zadd('sort2', 2, 2) @namespaced.zadd('sort2', 3, 3) @namespaced.zadd('sort2', 4, 4) @namespaced.zunionstore('union', ['sort1', 'sort2'], :weights => [2, 1]) expect(@namespaced.zrevrange('union', 0, -1)).to eq(%w( 2 4 3 1 )) end it "should properly union two sorted sets without options" do @namespaced.zadd('sort1', 1, 1) @namespaced.zadd('sort1', 2, 2) @namespaced.zadd('sort2', 2, 2) @namespaced.zadd('sort2', 3, 3) @namespaced.zadd('sort2', 4, 4) @namespaced.zunionstore('union', ['sort1', 'sort2']) expect(@namespaced.zrevrange('union', 0, -1)).to eq(%w( 4 2 3 1 )) end it "should properly intersect two sorted sets without options" do @namespaced.zadd('food', 1, 'orange') @namespaced.zadd('food', 2, 'banana') @namespaced.zadd('food', 3, 'eggplant') @namespaced.zadd('color', 2, 'orange') @namespaced.zadd('color', 3, 'yellow') @namespaced.zadd('color', 4, 'eggplant') @namespaced.zinterstore('inter', ['food', 'color']) inter_values = @namespaced.zrevrange('inter', 0, -1, :with_scores => true) expect(inter_values).to match_array([['orange', 3.0], ['eggplant', 7.0]]) end it "should properly intersect two sorted sets with options" do @namespaced.zadd('food', 1, 'orange') @namespaced.zadd('food', 2, 'banana') @namespaced.zadd('food', 3, 'eggplant') @namespaced.zadd('color', 2, 'orange') @namespaced.zadd('color', 3, 'yellow') @namespaced.zadd('color', 4, 'eggplant') @namespaced.zinterstore('inter', ['food', 'color'], :aggregate => "min") inter_values = @namespaced.zrevrange('inter', 0, -1, :with_scores => true) expect(inter_values).to match_array([['orange', 1.0], ['eggplant', 3.0]]) end it "should return lexicographical range for sorted set" do @namespaced.zadd('food', 0, 'orange') @namespaced.zadd('food', 0, 'banana') @namespaced.zadd('food', 0, 'eggplant') values = @namespaced.zrangebylex('food', '[b', '(o') expect(values).to match_array(['banana', 'eggplant']) end it "should return the number of elements removed from the set" do @namespaced.zadd('food', 0, 'orange') @namespaced.zadd('food', 0, 'banana') @namespaced.zadd('food', 0, 'eggplant') removed = @namespaced.zremrangebylex('food', '[b', '(o') expect(removed).to eq(2) values = @namespaced.zrange('food', 0, -1) expect(values).to eq(['orange']) end it "should return reverce lexicographical range for sorted set" do @namespaced.zadd('food', 0, 'orange') @namespaced.zadd('food', 0, 'banana') @namespaced.zadd('food', 0, 'eggplant') values = @namespaced.zrevrangebylex('food', '(o', '[b') expect(values).to match_array(['banana', 'eggplant']) end it "should add namespace to sort" do @namespaced.sadd('foo', 1) @namespaced.sadd('foo', 2) @namespaced.set('weight_1', 2) @namespaced.set('weight_2', 1) @namespaced.set('value_1', 'a') @namespaced.set('value_2', 'b') expect(@namespaced.sort('foo')).to eq(%w( 1 2 )) expect(@namespaced.sort('foo', :limit => [0, 1])).to eq(%w( 1 )) expect(@namespaced.sort('foo', :order => 'desc')).to eq(%w( 2 1 )) expect(@namespaced.sort('foo', :by => 'weight_*')).to eq(%w( 2 1 )) expect(@namespaced.sort('foo', :get => 'value_*')).to eq(%w( a b )) expect(@namespaced.sort('foo', :get => '#')).to eq(%w( 1 2 )) expect(@namespaced.sort('foo', :get => ['#', 'value_*'])).to eq([["1", "a"], ["2", "b"]]) @namespaced.sort('foo', :store => 'result') expect(@namespaced.lrange('result', 0, -1)).to eq(%w( 1 2 )) end it "should yield the correct list of keys" do @namespaced.set("foo", 1) @namespaced.set("bar", 2) @namespaced.set("baz", 3) expect(@namespaced.keys("*").sort).to eq(%w( bar baz foo )) expect(@namespaced.keys.sort).to eq(%w( bar baz foo )) end it "should add namepsace to multi blocks" do @namespaced.mapped_hmset "foo", {"key" => "value"} @namespaced.multi do |r| r.del "foo" r.mapped_hmset "foo", {"key1" => "value1"} end expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"}) end it "should pass through multi commands without block" do @namespaced.mapped_hmset "foo", {"key" => "value"} @namespaced.multi @namespaced.del "foo" @namespaced.mapped_hmset "foo", {"key1" => "value1"} @namespaced.exec expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"}) end it 'should return futures without attempting to remove namespaces' do @namespaced.multi do @future = @namespaced.keys('*') end expect(@future.class).to be(Redis::Future) end it "should add namespace to pipelined blocks" do @namespaced.mapped_hmset "foo", {"key" => "value"} @namespaced.pipelined do |r| r.del "foo" r.mapped_hmset "foo", {"key1" => "value1"} end expect(@namespaced.hgetall("foo")).to eq({"key1" => "value1"}) end it "should returned response array from pipelined block" do @namespaced.mset "foo", "bar", "key", "value" result = @namespaced.pipelined do |r| r.get("foo") r.get("key") end expect(result).to eq(["bar", "value"]) end it "should add namespace to strlen" do @namespaced.set("mykey", "123456") expect(@namespaced.strlen("mykey")).to eq(6) end it "should not add namespace to echo" do expect(@namespaced.echo(123)).to eq("123") end it 'should not add namespace to disconnect!' do expect(@redis).to receive(:disconnect!).with(no_args).and_call_original expect(@namespaced.disconnect!).to be nil end it "can change its namespace" do expect(@namespaced.get('foo')).to eq(nil) @namespaced.set('foo', 'chris') expect(@namespaced.get('foo')).to eq('chris') expect(@namespaced.namespace).to eq(:ns) @namespaced.namespace = :spec expect(@namespaced.namespace).to eq(:spec) expect(@namespaced.get('foo')).to eq(nil) @namespaced.set('foo', 'chris') expect(@namespaced.get('foo')).to eq('chris') end it "can accept a temporary namespace" do expect(@namespaced.namespace).to eq(:ns) expect(@namespaced.get('foo')).to eq(nil) @namespaced.namespace(:spec) do |temp_ns| expect(temp_ns.namespace).to eq(:spec) expect(temp_ns.get('foo')).to eq(nil) temp_ns.set('foo', 'jake') expect(temp_ns.get('foo')).to eq('jake') end expect(@namespaced.namespace).to eq(:ns) expect(@namespaced.get('foo')).to eq(nil) end it "should respond to :namespace=" do expect(@namespaced.respond_to?(:namespace=)).to eq(true) end it "should respond to :warning=" do expect(@namespaced.respond_to?(:warning=)).to eq(true) end it "should raise an exception when an unknown command is passed" do expect { @namespaced.unknown('foo') }.to raise_exception NoMethodError end # Redis 2.6 RC reports its version as 2.5. if @redis_version >= Gem::Version.new("2.5.0") describe "redis 2.6 commands" do it "should namespace bitcount" do @redis.set('ns:foo', 'foobar') expect(@namespaced.bitcount('foo')).to eq 26 expect(@namespaced.bitcount('foo', 0, 0)).to eq 4 expect(@namespaced.bitcount('foo', 1, 1)).to eq 6 expect(@namespaced.bitcount('foo', 3, 5)).to eq 10 end it "should namespace bitop" do try_encoding('UTF-8') do @redis.set("ns:foo", "a") @redis.set("ns:bar", "b") @namespaced.bitop(:and, "foo&bar", "foo", "bar") @namespaced.bitop(:or, "foo|bar", "foo", "bar") @namespaced.bitop(:xor, "foo^bar", "foo", "bar") @namespaced.bitop(:not, "~foo", "foo") expect(@redis.get("ns:foo&bar")).to eq "\x60" expect(@redis.get("ns:foo|bar")).to eq "\x63" expect(@redis.get("ns:foo^bar")).to eq "\x03" expect(@redis.get("ns:~foo")).to eq "\x9E" end end it "should namespace dump and restore" do @redis.set("ns:foo", "a") v = @namespaced.dump("foo") @redis.del("ns:foo") expect(@namespaced.restore("foo", 1000, v)).to be_truthy expect(@redis.get("ns:foo")).to eq 'a' expect(@redis.ttl("ns:foo")).to satisfy {|v| (0..1).include?(v) } @redis.rpush("ns:bar", %w(b c d)) w = @namespaced.dump("bar") @redis.del("ns:bar") expect(@namespaced.restore("bar", 1000, w)).to be_truthy expect(@redis.lrange('ns:bar', 0, -1)).to eq %w(b c d) expect(@redis.ttl("ns:foo")).to satisfy {|v| (0..1).include?(v) } end it "should namespace hincrbyfloat" do @namespaced.hset('mykey', 'field', 10.50) expect(@namespaced.hincrbyfloat('mykey', 'field', 0.1)).to eq(10.6) end it "should namespace incrbyfloat" do @namespaced.set('mykey', 10.50) expect(@namespaced.incrbyfloat('mykey', 0.1)).to eq(10.6) end it "should namespace object" do @namespaced.set('foo', 1000) expect(@namespaced.object('encoding', 'foo')).to eq('int') end it "should namespace persist" do @namespaced.set('mykey', 'Hello') @namespaced.expire('mykey', 60) expect(@namespaced.persist('mykey')).to eq(true) expect(@namespaced.ttl('mykey')).to eq(-1) end it "should namespace pexpire" do @namespaced.set('mykey', 'Hello') expect(@namespaced.pexpire('mykey', 60000)).to eq(true) end it "should namespace pexpireat" do @namespaced.set('mykey', 'Hello') expect(@namespaced.pexpire('mykey', 1555555555005)).to eq(true) end it "should namespace psetex" do expect(@namespaced.psetex('mykey', 10000, 'Hello')).to eq('OK') expect(@namespaced.get('mykey')).to eq('Hello') end it "should namespace pttl" do @namespaced.set('mykey', 'Hello') @namespaced.expire('mykey', 1) expect(@namespaced.pttl('mykey')).to be >= 0 end it "should namespace eval keys passed in as array args" do expect(@namespaced. eval("return {KEYS[1], KEYS[2]}", %w[k1 k2], %w[arg1 arg2])). to eq(%w[ns:k1 ns:k2]) end it "should namespace eval keys passed in as hash args" do expect(@namespaced. eval("return {KEYS[1], KEYS[2]}", :keys => %w[k1 k2], :argv => %w[arg1 arg2])). to eq(%w[ns:k1 ns:k2]) end it "should namespace eval keys passed in as hash args unmodified" do args = { :keys => %w[k1 k2], :argv => %w[arg1 arg2] } args.freeze expect(@namespaced. eval("return {KEYS[1], KEYS[2]}", args)). to eq(%w[ns:k1 ns:k2]) end context '#evalsha' do let!(:sha) do @redis.script(:load, "return {KEYS[1], KEYS[2]}") end it "should namespace evalsha keys passed in as array args" do expect(@namespaced. evalsha(sha, %w[k1 k2], %w[arg1 arg2])). to eq(%w[ns:k1 ns:k2]) end it "should namespace evalsha keys passed in as hash args" do expect(@namespaced. evalsha(sha, :keys => %w[k1 k2], :argv => %w[arg1 arg2])). to eq(%w[ns:k1 ns:k2]) end it "should namespace evalsha keys passed in as hash args unmodified" do args = { :keys => %w[k1 k2], :argv => %w[arg1 arg2] } args.freeze expect(@namespaced. evalsha(sha, args)). to eq(%w[ns:k1 ns:k2]) end end context "in a nested namespace" do let(:nested_namespace) { Redis::Namespace.new(:nest, :redis => @namespaced) } let(:sha) { @redis.script(:load, "return {KEYS[1], KEYS[2]}") } it "should namespace eval keys passed in as hash args" do expect(nested_namespace. eval("return {KEYS[1], KEYS[2]}", :keys => %w[k1 k2], :argv => %w[arg1 arg2])). to eq(%w[ns:nest:k1 ns:nest:k2]) end it "should namespace evalsha keys passed in as hash args" do expect(nested_namespace.evalsha(sha, :keys => %w[k1 k2], :argv => %w[arg1 arg2])). to eq(%w[ns:nest:k1 ns:nest:k2]) end end end end # Redis 2.8 RC reports its version as 2.7. if @redis_version >= Gem::Version.new("2.7.105") describe "redis 2.8 commands" do context 'keyspace scan methods' do let(:keys) do %w(alpha ns:beta gamma ns:delta ns:epsilon ns:zeta:one ns:zeta:two ns:theta) end let(:namespaced_keys) do keys.map{|k| k.dup.sub!(/\Ans:/,'') }.compact.sort end before(:each) do keys.each do |key| @redis.set(key, key) end end let(:matching_namespaced_keys) do namespaced_keys.select{|k| k[/\Azeta:/] }.compact.sort end context '#scan' do context 'when :match supplied' do it 'should retrieve the proper keys' do _, result = @namespaced.scan(0, :match => 'zeta:*', :count => 1000) expect(result).to match_array(matching_namespaced_keys) end end context 'without :match supplied' do it 'should retrieve the proper keys' do _, result = @namespaced.scan(0, :count => 1000) expect(result).to match_array(namespaced_keys) end end end if Redis.current.respond_to?(:scan) context '#scan_each' do context 'when :match supplied' do context 'when given a block' do it 'should yield unnamespaced' do results = [] @namespaced.scan_each(:match => 'zeta:*', :count => 1000) {|k| results << k } expect(results).to match_array(matching_namespaced_keys) end end context 'without a block' do it 'should return an Enumerator that un-namespaces' do enum = @namespaced.scan_each(:match => 'zeta:*', :count => 1000) expect(enum.to_a).to match_array(matching_namespaced_keys) end end end context 'without :match supplied' do context 'when given a block' do it 'should yield unnamespaced' do results = [] @namespaced.scan_each(:count => 1000){ |k| results << k } expect(results).to match_array(namespaced_keys) end end context 'without a block' do it 'should return an Enumerator that un-namespaces' do enum = @namespaced.scan_each(:count => 1000) expect(enum.to_a).to match_array(namespaced_keys) end end end end if Redis.current.respond_to?(:scan_each) end context 'hash scan methods' do before(:each) do @redis.mapped_hmset('hsh', {'zeta:wrong:one' => 'WRONG', 'wrong:two' => 'WRONG'}) @redis.mapped_hmset('ns:hsh', hash) end let(:hash) do {'zeta:one' => 'OK', 'zeta:two' => 'OK', 'three' => 'OKAY'} end let(:hash_matching_subset) do # select is not consistent from 1.8.7 -> 1.9.2 :( hash.reject {|k,v| !k[/\Azeta:/] } end context '#hscan' do context 'when supplied :match' do it 'should retrieve the proper keys' do _, results = @namespaced.hscan('hsh', 0, :match => 'zeta:*') expect(results).to match_array(hash_matching_subset.to_a) end end context 'without :match supplied' do it 'should retrieve all hash keys' do _, results = @namespaced.hscan('hsh', 0) expect(results).to match_array(@redis.hgetall('ns:hsh').to_a) end end end if Redis.current.respond_to?(:hscan) context '#hscan_each' do context 'when :match supplied' do context 'when given a block' do it 'should yield the correct hash keys unchanged' do results = [] @namespaced.hscan_each('hsh', :match => 'zeta:*', :count => 1000) { |kv| results << kv} expect(results).to match_array(hash_matching_subset.to_a) end end context 'without a block' do it 'should return an Enumerator that yields the correct hash keys unchanged' do enum = @namespaced.hscan_each('hsh', :match => 'zeta:*', :count => 1000) expect(enum.to_a).to match_array(hash_matching_subset.to_a) end end end context 'without :match supplied' do context 'when given a block' do it 'should yield all hash keys unchanged' do results = [] @namespaced.hscan_each('hsh', :count => 1000){ |k| results << k } expect(results).to match_array(hash.to_a) end end context 'without a block' do it 'should return an Enumerator that yields all keys unchanged' do enum = @namespaced.hscan_each('hsh', :count => 1000) expect(enum.to_a).to match_array(hash.to_a) end end end end if Redis.current.respond_to?(:hscan_each) end context 'set scan methods' do before(:each) do set.each { |elem| @namespaced.sadd('set', elem) } @redis.sadd('set', 'WRONG') end let(:set) do %w(zeta:one zeta:two three) end let(:matching_subset) do set.select { |e| e[/\Azeta:/] } end context '#sscan' do context 'when supplied :match' do it 'should retrieve the matching set members from the proper set' do _, results = @namespaced.sscan('set', 0, :match => 'zeta:*', :count => 1000) expect(results).to match_array(matching_subset) end end context 'without :match supplied' do it 'should retrieve all set members from the proper set' do _, results = @namespaced.sscan('set', 0, :count => 1000) expect(results).to match_array(set) end end end if Redis.current.respond_to?(:sscan) context '#sscan_each' do context 'when :match supplied' do context 'when given a block' do it 'should yield the correct hset elements unchanged' do results = [] @namespaced.sscan_each('set', :match => 'zeta:*', :count => 1000) { |kv| results << kv} expect(results).to match_array(matching_subset) end end context 'without a block' do it 'should return an Enumerator that yields the correct set elements unchanged' do enum = @namespaced.sscan_each('set', :match => 'zeta:*', :count => 1000) expect(enum.to_a).to match_array(matching_subset) end end end context 'without :match supplied' do context 'when given a block' do it 'should yield all set elements unchanged' do results = [] @namespaced.sscan_each('set', :count => 1000){ |k| results << k } expect(results).to match_array(set) end end context 'without a block' do it 'should return an Enumerator that yields all set elements unchanged' do enum = @namespaced.sscan_each('set', :count => 1000) expect(enum.to_a).to match_array(set) end end end end if Redis.current.respond_to?(:sscan_each) end context 'zset scan methods' do before(:each) do hash.each {|member, score| @namespaced.zadd('zset', score, member)} @redis.zadd('zset', 123.45, 'WRONG') end let(:hash) do {'zeta:one' => 1, 'zeta:two' => 2, 'three' => 3} end let(:hash_matching_subset) do # select is not consistent from 1.8.7 -> 1.9.2 :( hash.reject {|k,v| !k[/\Azeta:/] } end context '#zscan' do context 'when supplied :match' do it 'should retrieve the matching set elements and their scores' do results = [] @namespaced.zscan_each('zset', :match => 'zeta:*', :count => 1000) { |ms| results << ms } expect(results).to match_array(hash_matching_subset.to_a) end end context 'without :match supplied' do it 'should retrieve all set elements and their scores' do results = [] @namespaced.zscan_each('zset', :count => 1000) { |ms| results << ms } expect(results).to match_array(hash.to_a) end end end if Redis.current.respond_to?(:zscan) context '#zscan_each' do context 'when :match supplied' do context 'when given a block' do it 'should yield the correct set elements and scores unchanged' do results = [] @namespaced.zscan_each('zset', :match => 'zeta:*', :count => 1000) { |ms| results << ms} expect(results).to match_array(hash_matching_subset.to_a) end end context 'without a block' do it 'should return an Enumerator that yields the correct set elements and scoresunchanged' do enum = @namespaced.zscan_each('zset', :match => 'zeta:*', :count => 1000) expect(enum.to_a).to match_array(hash_matching_subset.to_a) end end end context 'without :match supplied' do context 'when given a block' do it 'should yield all set elements and scores unchanged' do results = [] @namespaced.zscan_each('zset', :count => 1000){ |ms| results << ms } expect(results).to match_array(hash.to_a) end end context 'without a block' do it 'should return an Enumerator that yields all set elements and scores unchanged' do enum = @namespaced.zscan_each('zset', :count => 1000) expect(enum.to_a).to match_array(hash.to_a) end end end end if Redis.current.respond_to?(:zscan_each) end end end if @redis_version >= Gem::Version.new("2.8.9") it 'should namespace pfadd' do 5.times { |n| @namespaced.pfadd("pf", n) } expect(@redis.pfcount("ns:pf")).to eq(5) end it 'should namespace pfcount' do 5.times { |n| @redis.pfadd("ns:pf", n) } expect(@namespaced.pfcount("pf")).to eq(5) end it 'should namespace pfmerge' do 5.times do |n| @redis.pfadd("ns:pfa", n) @redis.pfadd("ns:pfb", n+5) end @namespaced.pfmerge("pfc", "pfa", "pfb") expect(@redis.pfcount("ns:pfc")).to eq(10) end end describe :full_namespace do it "should return the full namespace including sub namespaces" do sub_namespaced = Redis::Namespace.new(:sub1, :redis => @namespaced) sub_sub_namespaced = Redis::Namespace.new(:sub2, :redis => sub_namespaced) expect(@namespaced.full_namespace).to eql("ns") expect(sub_namespaced.full_namespace).to eql("ns:sub1") expect(sub_sub_namespaced.full_namespace).to eql("ns:sub1:sub2") end end end