Skip to content

Commit

Permalink
Add specs for expire-related commands options nx, xx, lt and …
Browse files Browse the repository at this point in the history
…`gt`
  • Loading branch information
viralpraxis committed Nov 19, 2023
1 parent 7c071ff commit b5ea96a
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 4 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
- '3.2'
redis-version:
- '6.2'
- '7.0'

services:
redis:
Expand All @@ -41,7 +42,7 @@ jobs:
bundler-cache: true

- name: Run tests
run: bundle exec rspec
run: bundle exec rspec --tag redis:${{ matrix.redis-version }}

- name: Code coverage reporting
uses: coverallsapp/github-action@master
Expand Down
77 changes: 77 additions & 0 deletions spec/commands/expire_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@
expect(@redises.expire(@key.to_sym, 9)).to eq(true)
end

it 'works with options', redis: '7.0' do
expect(@redises.expire(@key, 20)).to eq(true)
expect(@redises.expire(@key, 10, lt: true)).to eq(true)
expect(@redises.expire(@key, 15, lt: true)).to eq(false)
expect(@redises.expire(@key, 20, gt: true)).to eq(true)
expect(@redises.expire(@key, 15, gt: true)).to eq(false)
expect(@redises.expire(@key, 10, xx: true)).to eq(true)
expect(@redises.expire(@key, 10, nx: true)).to eq(false)
expect(@redises.persist(@key)).to eq(true)
expect(@redises.expire(@key, 10, xx: true)).to eq(false)
expect(@redises.expire(@key, 10, nx: true)).to eq(true)
end

context '[mock only]' do
# These are mock-only since we can't actually manipulate time in
# the real Redis.
Expand All @@ -42,6 +55,8 @@
allow(Time).to receive(:now).and_return(@now)
end

it_should_behave_like 'raises on invalid expire command options', :expire

it 'removes keys after enough time has passed' do
@mock.expire(@key, 5)
allow(Time).to receive(:now).and_return(@now + 5)
Expand Down Expand Up @@ -107,5 +122,67 @@
expect(@mock.get(other_key)).to be_nil
end
end

context 'with `nx` option' do
it do
@mock.set(@key, 'string')

expect(@mock.expire(@key, 10)).to eq(true)
expect(@mock.expire(@key, 10, nx: true)).to eq(false)

@mock.persist(@key)

expect(@mock.expire(@key, 10, nx: true)).to eq(true)
end
end

context 'with `xx` option' do
it do
@mock.set(@key, 'string')

expect(@mock.expire(@key, 10)).to eq(true)
expect(@mock.expire(@key, 10, xx: true)).to eq(true)

@mock.persist(@key)

expect(@mock.expire(@key, 10, xx: true)).to eq(false)
end
end

context 'with `gt` option' do
it do
@mock.set(@key, 'string')

expect(@mock.expire(@key, 10)).to eq(true)
expect(@mock.expire(@key, 5, gt: true)).to eq(false)
expect(@mock.ttl(@key)).to eq(10)
expect(@mock.expire(@key, 20, gt: true)).to eq(true)
expect(@mock.ttl(@key)).to eq(20)
end

it 'behaves correcly with non-volatile key' do
@mock.set(@key, 'string')

expect(@mock.expire(@key, 20, gt: true)).to eq(false)
end
end

context 'with `lt` option' do
it do
@mock.set(@key, 'string')

expect(@mock.expire(@key, 10)).to eq(true)
expect(@mock.expire(@key, 20, lt: true)).to eq(false)
expect(@mock.ttl(@key)).to eq(10)
expect(@mock.expire(@key, 5, lt: true)).to eq(true)
expect(@mock.ttl(@key)).to eq(5)
end

it 'behaves correcly with non-volatile key' do
@mock.set(@key, 'string')

expect(@mock.expire(@key, 20, lt: true)).to eq(true)
end
end
end
end
15 changes: 15 additions & 0 deletions spec/commands/expireat_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,19 @@
end.to raise_error(Redis::CommandError)
end

it 'works with options', redis: '7.0' do
expect(@redises.expire(@key, Time.now.to_i + 20)).to eq(true)
expect(@redises.expire(@key, Time.now.to_i + 10, lt: true)).to eq(true)
expect(@redises.expire(@key, Time.now.to_i + 15, lt: true)).to eq(false)
expect(@redises.expire(@key, Time.now.to_i + 20, gt: true)).to eq(true)
expect(@redises.expire(@key, Time.now.to_i + 15, gt: true)).to eq(false)
expect(@redises.expire(@key, Time.now.to_i + 10, xx: true)).to eq(true)
expect(@redises.expire(@key, Time.now.to_i + 10, nx: true)).to eq(false)
expect(@redises.persist(@key)).to eq(true)
expect(@redises.expire(@key, Time.now.to_i + 10, xx: true)).to eq(false)
expect(@redises.expire(@key, Time.now.to_i + 10, nx: true)).to eq(true)
end

context '[mock only]' do
# These are mock-only since we can't actually manipulate time in
# the real Redis.
Expand All @@ -38,6 +51,8 @@
allow(Time).to receive(:now).and_return(@now)
end

it_should_behave_like 'raises on invalid expire command options', :expireat

it 'removes keys after enough time has passed' do
@mock.expireat(@key, @now.to_i + 5)
allow(Time).to receive(:now).and_return(@now + 5)
Expand Down
15 changes: 15 additions & 0 deletions spec/commands/pexpire_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,19 @@
end.to raise_error(Redis::CommandError)
end

it 'works with options', redis: '7.0' do
expect(@redises.expire(@key, 20)).to eq(true)
expect(@redises.expire(@key, 10, lt: true)).to eq(true)
expect(@redises.expire(@key, 15, lt: true)).to eq(false)
expect(@redises.expire(@key, 20, gt: true)).to eq(true)
expect(@redises.expire(@key, 15, gt: true)).to eq(false)
expect(@redises.expire(@key, 10, xx: true)).to eq(true)
expect(@redises.expire(@key, 10, nx: true)).to eq(false)
expect(@redises.persist(@key)).to eq(true)
expect(@redises.expire(@key, 10, xx: true)).to eq(false)
expect(@redises.expire(@key, 10, nx: true)).to eq(true)
end

it 'stringifies key' do
expect(@redises.pexpire(@key.to_sym, 9)).to eq(true)
end
Expand All @@ -42,6 +55,8 @@
allow(Time).to receive(:now).and_return(@now)
end

it_should_behave_like 'raises on invalid expire command options', :pexpire

it 'removes keys after enough time has passed' do
@mock.pexpire(@key, 5)
allow(Time).to receive(:now).and_return(@now + Rational(6, 1000))
Expand Down
25 changes: 22 additions & 3 deletions spec/commands/pexpireat_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@
@redises.set(@key, 'spork')
end

def now_ms
(Time.now.to_f * 1000).to_i
end

it 'returns true for a key that exists' do
expect(@redises.pexpireat(@key, (Time.now.to_f * 1000).to_i + 1)).to eq(true)
expect(@redises.pexpireat(@key, now_ms + 1)).to eq(true)
end

it 'returns false for a key that does not exist' do
expect(@redises.pexpireat('mock-redis-test:nonesuch',
(Time.now.to_f * 1000).to_i + 1)).to eq(false)
now_ms + 1)).to eq(false)
end

it 'removes a key immediately when timestamp is now' do
@redises.pexpireat(@key, (Time.now.to_f * 1000).to_i)
@redises.pexpireat(@key, now_ms)
expect(@redises.get(@key)).to be_nil
end

Expand All @@ -26,6 +30,19 @@
end.to raise_error(Redis::CommandError)
end

it 'works with options', redis: '7.0' do
expect(@redises.expire(@key, now_ms + 20)).to eq(true)
expect(@redises.expire(@key, now_ms + 10, lt: true)).to eq(true)
expect(@redises.expire(@key, now_ms + 15, lt: true)).to eq(false)
expect(@redises.expire(@key, now_ms + 20, gt: true)).to eq(true)
expect(@redises.expire(@key, now_ms + 15, gt: true)).to eq(false)
expect(@redises.expire(@key, now_ms + 10, xx: true)).to eq(true)
expect(@redises.expire(@key, now_ms + 10, nx: true)).to eq(false)
expect(@redises.persist(@key)).to eq(true)
expect(@redises.expire(@key, now_ms + 10, xx: true)).to eq(false)
expect(@redises.expire(@key, now_ms + 10, nx: true)).to eq(true)
end

context '[mock only]' do
# These are mock-only since we can't actually manipulate time in
# the real Redis.
Expand All @@ -39,6 +56,8 @@
allow(Time).to receive(:now).and_return(@now)
end

it_should_behave_like 'raises on invalid expire command options', :pexpireat

it 'removes keys after enough time has passed' do
@mock.pexpireat(@key, (@now.to_f * 1000).to_i + 5)
allow(Time).to receive(:now).and_return(@now + 0.006)
Expand Down
5 changes: 5 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,9 @@ def args_for_method(method)
end
@redises._gsub_clear
end

# By default, all the specs are considered to be compatible with redis 6,
# specs for redis 7 should be marked with `redis: 7.0` tag.
config.run_all_when_everything_filtered = true
config.filter_run_excluding redis: 7.0
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
RSpec.shared_examples_for 'raises on invalid expire command options' do |command|
[%i[nx xx], %i[nx lt], %i[nx gt], %i[lt gt]].each do |options|
context "with `#{options[0]}` and `#{options[1]}` options" do
it 'raises `Redis::CommandError`' do
expect { @mock.public_send(command, @key, 1, **options.zip([true, true]).to_h) }
.to raise_error(
Redis::CommandError,
'ERR NX and XX, GT or LT options at the same time are not compatible'
)
end
end

context 'with unexpected key' do
it 'raises `ArgumentError`' do
expect { @mock.public_send(command, @key, 1, foo: true) }
.to raise_error(ArgumentError)
end
end
end
end

0 comments on commit b5ea96a

Please sign in to comment.