mirror of
https://github.com/dkam/suo.git
synced 2025-01-29 07:42:43 +00:00
refactor class methods into instance methods
This commit is contained in:
@@ -1,206 +1,188 @@
|
|||||||
module Suo
|
module Suo
|
||||||
module Client
|
module Client
|
||||||
class Base
|
class Base
|
||||||
|
|
||||||
DEFAULT_OPTIONS = {
|
DEFAULT_OPTIONS = {
|
||||||
retry_timeout: 0.1,
|
acquisition_timeout: 0.1,
|
||||||
retry_delay: 0.01,
|
acquisition_delay: 0.01,
|
||||||
stale_lock_expiration: 3600
|
stale_lock_expiration: 3600
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
|
attr_accessor :client
|
||||||
|
|
||||||
|
include MonitorMixin
|
||||||
|
|
||||||
def initialize(options = {})
|
def initialize(options = {})
|
||||||
@options = self.class.merge_defaults(options)
|
fail "Client required" unless options[:client]
|
||||||
|
@options = DEFAULT_OPTIONS.merge(options)
|
||||||
|
@retry_count = (@options[:acquisition_timeout] / @options[:acquisition_delay].to_f).ceil
|
||||||
|
@client = @options[:client]
|
||||||
|
super()
|
||||||
end
|
end
|
||||||
|
|
||||||
def lock(key, resources = 1, options = {})
|
def lock(key, resources = 1)
|
||||||
options = self.class.merge_defaults(@options.merge(options))
|
token = acquire_lock(key, resources)
|
||||||
token = self.class.lock(key, resources, options)
|
|
||||||
|
|
||||||
if token
|
if block_given? && token
|
||||||
begin
|
begin
|
||||||
yield if block_given?
|
yield
|
||||||
ensure
|
ensure
|
||||||
self.class.unlock(key, token, options)
|
unlock(key, token)
|
||||||
end
|
end
|
||||||
|
|
||||||
true
|
|
||||||
else
|
else
|
||||||
false
|
token
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def locked?(key, resources = 1)
|
def locked?(key, resources = 1)
|
||||||
self.class.locked?(key, resources, @options)
|
locks(key).size >= resources
|
||||||
end
|
end
|
||||||
|
|
||||||
class << self
|
def locks(key)
|
||||||
def lock(key, resources = 1, options = {})
|
val, _ = get(key)
|
||||||
options = merge_defaults(options)
|
locks = deserialize_locks(val)
|
||||||
acquisition_token = nil
|
|
||||||
token = SecureRandom.base64(16)
|
|
||||||
|
|
||||||
retry_with_timeout(key, options) do
|
locks
|
||||||
val, cas = get(key, options)
|
end
|
||||||
|
|
||||||
if val.nil?
|
def refresh(key, acquisition_token)
|
||||||
set_initial(key, options)
|
retry_with_timeout(key) do
|
||||||
next
|
val, cas = get(key)
|
||||||
end
|
|
||||||
|
|
||||||
locks = deserialize_and_clear_locks(val, options)
|
if val.nil?
|
||||||
|
set_initial(key)
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
if locks.size < resources
|
locks = deserialize_and_clear_locks(val)
|
||||||
add_lock(locks, token)
|
|
||||||
|
|
||||||
newval = serialize_locks(locks)
|
refresh_lock(locks, acquisition_token)
|
||||||
|
|
||||||
if set(key, newval, cas, options)
|
break if set(key, serialize_locks(locks), cas)
|
||||||
acquisition_token = token
|
end
|
||||||
break
|
end
|
||||||
end
|
|
||||||
|
def unlock(key, acquisition_token)
|
||||||
|
return unless acquisition_token
|
||||||
|
|
||||||
|
retry_with_timeout(key) do
|
||||||
|
val, cas = get(key)
|
||||||
|
|
||||||
|
break if val.nil?
|
||||||
|
|
||||||
|
locks = deserialize_and_clear_locks(val)
|
||||||
|
|
||||||
|
acquisition_lock = remove_lock(locks, acquisition_token)
|
||||||
|
|
||||||
|
break unless acquisition_lock
|
||||||
|
break if set(key, serialize_locks(locks), cas)
|
||||||
|
end
|
||||||
|
rescue LockClientError => _ # rubocop:disable Lint/HandleExceptions
|
||||||
|
# ignore - assume success due to optimistic locking
|
||||||
|
end
|
||||||
|
|
||||||
|
def clear(key) # rubocop:disable Lint/UnusedMethodArgument
|
||||||
|
fail NotImplementedError
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def acquire_lock(key, resources = 1)
|
||||||
|
acquisition_token = nil
|
||||||
|
token = SecureRandom.base64(16)
|
||||||
|
|
||||||
|
retry_with_timeout(key) do
|
||||||
|
val, cas = get(key)
|
||||||
|
|
||||||
|
if val.nil?
|
||||||
|
set_initial(key)
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
locks = deserialize_and_clear_locks(val)
|
||||||
|
|
||||||
|
if locks.size < resources
|
||||||
|
add_lock(locks, token)
|
||||||
|
|
||||||
|
newval = serialize_locks(locks)
|
||||||
|
|
||||||
|
if set(key, newval, cas)
|
||||||
|
acquisition_token = token
|
||||||
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
acquisition_token
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def locked?(key, resources = 1, options = {})
|
acquisition_token
|
||||||
locks(key, options).size >= resources
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def locks(key, options)
|
def get(key) # rubocop:disable Lint/UnusedMethodArgument
|
||||||
options = merge_defaults(options)
|
fail NotImplementedError
|
||||||
val, _ = get(key, options)
|
end
|
||||||
locks = deserialize_locks(val)
|
|
||||||
|
|
||||||
locks
|
def set(key, newval, oldval) # rubocop:disable Lint/UnusedMethodArgument
|
||||||
end
|
fail NotImplementedError
|
||||||
|
end
|
||||||
|
|
||||||
def refresh(key, acquisition_token, options = {})
|
def set_initial(key) # rubocop:disable Lint/UnusedMethodArgument
|
||||||
options = merge_defaults(options)
|
fail NotImplementedError
|
||||||
|
end
|
||||||
|
|
||||||
retry_with_timeout(key, options) do
|
def synchronize(key) # rubocop:disable Lint/UnusedMethodArgument
|
||||||
val, cas = get(key, options)
|
mon_synchronize { yield }
|
||||||
|
end
|
||||||
|
|
||||||
if val.nil?
|
def retry_with_timeout(key)
|
||||||
set_initial(key, options)
|
start = Time.now.to_f
|
||||||
next
|
|
||||||
end
|
|
||||||
|
|
||||||
locks = deserialize_and_clear_locks(val, options)
|
@retry_count.times do
|
||||||
|
now = Time.now.to_f
|
||||||
|
break if now - start > @options[:acquisition_timeout]
|
||||||
|
|
||||||
refresh_lock(locks, acquisition_token)
|
synchronize(key) do
|
||||||
|
yield
|
||||||
break if set(key, serialize_locks(locks), cas, options)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sleep(rand(@options[:acquisition_delay] * 1000).to_f / 1000)
|
||||||
end
|
end
|
||||||
|
rescue => _
|
||||||
|
raise LockClientError
|
||||||
|
end
|
||||||
|
|
||||||
def unlock(key, acquisition_token, options = {})
|
def serialize_locks(locks)
|
||||||
options = merge_defaults(options)
|
MessagePack.pack(locks.map { |time, token| [time.to_f, token] })
|
||||||
|
end
|
||||||
|
|
||||||
return unless acquisition_token
|
def deserialize_and_clear_locks(val)
|
||||||
|
clear_expired_locks(deserialize_locks(val))
|
||||||
|
end
|
||||||
|
|
||||||
retry_with_timeout(key, options) do
|
def deserialize_locks(val)
|
||||||
val, cas = get(key, options)
|
unpacked = (val.nil? || val == "") ? [] : MessagePack.unpack(val)
|
||||||
|
|
||||||
break if val.nil?
|
unpacked.map do |time, token|
|
||||||
|
[Time.at(time), token]
|
||||||
locks = deserialize_and_clear_locks(val, options)
|
|
||||||
|
|
||||||
acquisition_lock = remove_lock(locks, acquisition_token)
|
|
||||||
|
|
||||||
break unless acquisition_lock
|
|
||||||
break if set(key, serialize_locks(locks), cas, options)
|
|
||||||
end
|
|
||||||
rescue LockClientError => _ # rubocop:disable Lint/HandleExceptions
|
|
||||||
# ignore - assume success due to optimistic locking
|
|
||||||
end
|
end
|
||||||
|
rescue EOFError => _
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
def clear(key, options = {}) # rubocop:disable Lint/UnusedMethodArgument
|
def clear_expired_locks(locks)
|
||||||
fail NotImplementedError
|
expired = Time.now - @options[:stale_lock_expiration]
|
||||||
end
|
locks.reject { |time, _| time < expired }
|
||||||
|
end
|
||||||
|
|
||||||
def merge_defaults(options = {})
|
def add_lock(locks, token)
|
||||||
options = self::DEFAULT_OPTIONS.merge(options)
|
locks << [Time.now.to_f, token]
|
||||||
|
end
|
||||||
|
|
||||||
fail "Client required" unless options[:client]
|
def remove_lock(locks, acquisition_token)
|
||||||
|
lock = locks.find { |_, token| token == acquisition_token }
|
||||||
|
locks.delete(lock)
|
||||||
|
end
|
||||||
|
|
||||||
options
|
def refresh_lock(locks, acquisition_token)
|
||||||
end
|
remove_lock(locks, acquisition_token)
|
||||||
|
add_lock(locks, token)
|
||||||
private
|
|
||||||
|
|
||||||
def get(key, options) # rubocop:disable Lint/UnusedMethodArgument
|
|
||||||
fail NotImplementedError
|
|
||||||
end
|
|
||||||
|
|
||||||
def set(key, newval, oldval, options) # rubocop:disable Lint/UnusedMethodArgument
|
|
||||||
fail NotImplementedError
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_initial(key, options) # rubocop:disable Lint/UnusedMethodArgument
|
|
||||||
fail NotImplementedError
|
|
||||||
end
|
|
||||||
|
|
||||||
def synchronize(key, options)
|
|
||||||
yield(key, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
def retry_with_timeout(key, options)
|
|
||||||
count = (options[:retry_timeout] / options[:retry_delay].to_f).ceil
|
|
||||||
|
|
||||||
start = Time.now.to_f
|
|
||||||
|
|
||||||
count.times do
|
|
||||||
now = Time.now.to_f
|
|
||||||
break if now - start > options[:retry_timeout]
|
|
||||||
|
|
||||||
synchronize(key, options) do
|
|
||||||
yield
|
|
||||||
end
|
|
||||||
|
|
||||||
sleep(rand(options[:retry_delay] * 1000).to_f / 1000)
|
|
||||||
end
|
|
||||||
rescue => _
|
|
||||||
raise LockClientError
|
|
||||||
end
|
|
||||||
|
|
||||||
def serialize_locks(locks)
|
|
||||||
MessagePack.pack(locks.map { |time, token| [time.to_f, token] })
|
|
||||||
end
|
|
||||||
|
|
||||||
def deserialize_and_clear_locks(val, options)
|
|
||||||
clear_expired_locks(deserialize_locks(val), options)
|
|
||||||
end
|
|
||||||
|
|
||||||
def deserialize_locks(val)
|
|
||||||
unpacked = (val.nil? || val == "") ? [] : MessagePack.unpack(val)
|
|
||||||
|
|
||||||
unpacked.map do |time, token|
|
|
||||||
[Time.at(time), token]
|
|
||||||
end
|
|
||||||
rescue EOFError => _
|
|
||||||
[]
|
|
||||||
end
|
|
||||||
|
|
||||||
def clear_expired_locks(locks, options)
|
|
||||||
expired = Time.now - options[:stale_lock_expiration]
|
|
||||||
locks.reject { |time, _| time < expired }
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_lock(locks, token)
|
|
||||||
locks << [Time.now.to_f, token]
|
|
||||||
end
|
|
||||||
|
|
||||||
def remove_lock(locks, acquisition_token)
|
|
||||||
lock = locks.find { |_, token| token == acquisition_token }
|
|
||||||
locks.delete(lock)
|
|
||||||
end
|
|
||||||
|
|
||||||
def refresh_lock(locks, acquisition_token)
|
|
||||||
remove_lock(locks, acquisition_token)
|
|
||||||
add_lock(locks, token)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -6,25 +6,22 @@ module Suo
|
|||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
class << self
|
def clear(key)
|
||||||
def clear(key, options = {})
|
@client.delete(key)
|
||||||
options = merge_defaults(options)
|
end
|
||||||
options[:client].delete(key)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def get(key, options)
|
def get(key)
|
||||||
options[:client].get_cas(key)
|
@client.get_cas(key)
|
||||||
end
|
end
|
||||||
|
|
||||||
def set(key, newval, cas, options)
|
def set(key, newval, cas)
|
||||||
options[:client].set_cas(key, newval, cas)
|
@client.set_cas(key, newval, cas)
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_initial(key, options)
|
def set_initial(key)
|
||||||
options[:client].set(key, "")
|
@client.set(key, "")
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -6,37 +6,34 @@ module Suo
|
|||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
class << self
|
def clear(key)
|
||||||
def clear(key, options = {})
|
@client.del(key)
|
||||||
options = merge_defaults(options)
|
end
|
||||||
options[:client].del(key)
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def get(key)
|
||||||
|
[@client.get(key), nil]
|
||||||
|
end
|
||||||
|
|
||||||
|
def set(key, newval, _)
|
||||||
|
ret = @client.multi do |multi|
|
||||||
|
multi.set(key, newval)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
ret[0] == "OK"
|
||||||
|
end
|
||||||
|
|
||||||
def get(key, options)
|
def synchronize(key)
|
||||||
[options[:client].get(key), nil]
|
@client.watch(key) do
|
||||||
|
yield
|
||||||
end
|
end
|
||||||
|
ensure
|
||||||
|
@client.unwatch
|
||||||
|
end
|
||||||
|
|
||||||
def set(key, newval, _, options)
|
def set_initial(key)
|
||||||
ret = options[:client].multi do |multi|
|
@client.set(key, "")
|
||||||
multi.set(key, newval)
|
|
||||||
end
|
|
||||||
|
|
||||||
ret[0] == "OK"
|
|
||||||
end
|
|
||||||
|
|
||||||
def synchronize(key, options)
|
|
||||||
options[:client].watch(key) do
|
|
||||||
yield
|
|
||||||
end
|
|
||||||
ensure
|
|
||||||
options[:client].unwatch
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_initial(key, options)
|
|
||||||
options[:client].set(key, "")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,62 +3,55 @@ require "test_helper"
|
|||||||
TEST_KEY = "suo_test_key".freeze
|
TEST_KEY = "suo_test_key".freeze
|
||||||
|
|
||||||
module ClientTests
|
module ClientTests
|
||||||
def test_requires_client
|
|
||||||
exception = assert_raises(RuntimeError) do
|
|
||||||
@klass.lock(TEST_KEY, 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_equal "Client required", exception.message
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_throws_failed_error_on_bad_client
|
def test_throws_failed_error_on_bad_client
|
||||||
assert_raises(Suo::LockClientError) do
|
assert_raises(Suo::LockClientError) do
|
||||||
@klass.lock(TEST_KEY, 1, client: {})
|
client = @client.class.new(client: {})
|
||||||
|
client.lock(TEST_KEY, 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_class_single_resource_locking
|
def test_class_single_resource_locking
|
||||||
lock1 = @klass.lock(TEST_KEY, 1, client: @klass_client)
|
lock1 = @client.lock(TEST_KEY, 1)
|
||||||
refute_nil lock1
|
refute_nil lock1
|
||||||
|
|
||||||
locked = @klass.locked?(TEST_KEY, 1, client: @klass_client)
|
locked = @client.locked?(TEST_KEY, 1)
|
||||||
assert_equal true, locked
|
assert_equal true, locked
|
||||||
|
|
||||||
lock2 = @klass.lock(TEST_KEY, 1, client: @klass_client)
|
lock2 = @client.lock(TEST_KEY, 1)
|
||||||
assert_nil lock2
|
assert_nil lock2
|
||||||
|
|
||||||
@klass.unlock(TEST_KEY, lock1, client: @klass_client)
|
@client.unlock(TEST_KEY, lock1)
|
||||||
|
|
||||||
locked = @klass.locked?(TEST_KEY, 1, client: @klass_client)
|
locked = @client.locked?(TEST_KEY, 1)
|
||||||
|
|
||||||
assert_equal false, locked
|
assert_equal false, locked
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_class_multiple_resource_locking
|
def test_class_multiple_resource_locking
|
||||||
lock1 = @klass.lock(TEST_KEY, 2, client: @klass_client)
|
lock1 = @client.lock(TEST_KEY, 2)
|
||||||
refute_nil lock1
|
refute_nil lock1
|
||||||
|
|
||||||
locked = @klass.locked?(TEST_KEY, 2, client: @klass_client)
|
locked = @client.locked?(TEST_KEY, 2)
|
||||||
assert_equal false, locked
|
assert_equal false, locked
|
||||||
|
|
||||||
lock2 = @klass.lock(TEST_KEY, 2, client: @klass_client)
|
lock2 = @client.lock(TEST_KEY, 2)
|
||||||
refute_nil lock2
|
refute_nil lock2
|
||||||
|
|
||||||
locked = @klass.locked?(TEST_KEY, 2, client: @klass_client)
|
locked = @client.locked?(TEST_KEY, 2)
|
||||||
assert_equal true, locked
|
assert_equal true, locked
|
||||||
|
|
||||||
@klass.unlock(TEST_KEY, lock1, client: @klass_client)
|
@client.unlock(TEST_KEY, lock1)
|
||||||
|
|
||||||
locked = @klass.locked?(TEST_KEY, 1, client: @klass_client)
|
locked = @client.locked?(TEST_KEY, 1)
|
||||||
assert_equal true, locked
|
assert_equal true, locked
|
||||||
|
|
||||||
@klass.unlock(TEST_KEY, lock2, client: @klass_client)
|
@client.unlock(TEST_KEY, lock2)
|
||||||
|
|
||||||
locked = @klass.locked?(TEST_KEY, 1, client: @klass_client)
|
locked = @client.locked?(TEST_KEY, 1)
|
||||||
assert_equal false, locked
|
assert_equal false, locked
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_instance_single_resource_locking
|
def test_block_single_resource_locking
|
||||||
locked = false
|
locked = false
|
||||||
|
|
||||||
@client.lock(TEST_KEY, 1) { locked = true }
|
@client.lock(TEST_KEY, 1) { locked = true }
|
||||||
@@ -66,22 +59,45 @@ module ClientTests
|
|||||||
assert_equal true, locked
|
assert_equal true, locked
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_instance_unlocks_on_exception
|
def test_block_unlocks_on_exception
|
||||||
assert_raises(RuntimeError) do
|
assert_raises(RuntimeError) do
|
||||||
@client.lock(TEST_KEY, 1) { fail "Test" }
|
@client.lock(TEST_KEY, 1) { fail "Test" }
|
||||||
end
|
end
|
||||||
|
|
||||||
locked = @klass.locked?(TEST_KEY, 1, client: @klass_client)
|
locked = @client.locked?(TEST_KEY, 1)
|
||||||
assert_equal false, locked
|
assert_equal false, locked
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_readme_example
|
||||||
|
output = Queue.new
|
||||||
|
threads = []
|
||||||
|
|
||||||
|
threads << Thread.new { @client.lock(TEST_KEY, 2) { output << "One"; sleep 2 } }
|
||||||
|
threads << Thread.new { @client.lock(TEST_KEY, 2) { output << "Two"; sleep 2 } }
|
||||||
|
threads << Thread.new { @client.lock(TEST_KEY, 2) { output << "Three" } }
|
||||||
|
|
||||||
|
threads.map(&:join)
|
||||||
|
|
||||||
|
ret = []
|
||||||
|
|
||||||
|
ret << output.pop
|
||||||
|
ret << output.pop
|
||||||
|
|
||||||
|
ret.sort!
|
||||||
|
|
||||||
|
assert_equal 0, output.size
|
||||||
|
assert_equal ["One", "Two"], ret
|
||||||
|
end
|
||||||
|
|
||||||
def test_instance_multiple_resource_locking
|
def test_instance_multiple_resource_locking
|
||||||
success_counter = Queue.new
|
success_counter = Queue.new
|
||||||
failure_counter = Queue.new
|
failure_counter = Queue.new
|
||||||
|
|
||||||
50.times.map do |i|
|
client = @client.class.new(acquisition_timeout: 0.9, client: @client.client)
|
||||||
|
|
||||||
|
100.times.map do |i|
|
||||||
Thread.new do
|
Thread.new do
|
||||||
success = @client.lock(TEST_KEY, 25, retry_timeout: 0.9) do
|
success = @client.lock(TEST_KEY, 50) do
|
||||||
sleep(3)
|
sleep(3)
|
||||||
success_counter << i
|
success_counter << i
|
||||||
end
|
end
|
||||||
@@ -90,17 +106,19 @@ module ClientTests
|
|||||||
end
|
end
|
||||||
end.map(&:join)
|
end.map(&:join)
|
||||||
|
|
||||||
assert_equal 25, success_counter.size
|
assert_equal 50, success_counter.size
|
||||||
assert_equal 25, failure_counter.size
|
assert_equal 50, failure_counter.size
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_instance_multiple_resource_locking_longer_timeout
|
def test_instance_multiple_resource_locking_longer_timeout
|
||||||
success_counter = Queue.new
|
success_counter = Queue.new
|
||||||
failure_counter = Queue.new
|
failure_counter = Queue.new
|
||||||
|
|
||||||
50.times.map do |i|
|
client = @client.class.new(acquisition_timeout: 3, client: @client.client)
|
||||||
|
|
||||||
|
100.times.map do |i|
|
||||||
Thread.new do
|
Thread.new do
|
||||||
success = @client.lock(TEST_KEY, 25, retry_timeout: 2) do
|
success = client.lock(TEST_KEY, 50) do
|
||||||
sleep(0.5)
|
sleep(0.5)
|
||||||
success_counter << i
|
success_counter << i
|
||||||
end
|
end
|
||||||
@@ -109,19 +127,19 @@ module ClientTests
|
|||||||
end
|
end
|
||||||
end.map(&:join)
|
end.map(&:join)
|
||||||
|
|
||||||
assert_equal 50, success_counter.size
|
assert_equal 100, success_counter.size
|
||||||
assert_equal 0, failure_counter.size
|
assert_equal 0, failure_counter.size
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class TestBaseClient < Minitest::Test
|
class TestBaseClient < Minitest::Test
|
||||||
def setup
|
def setup
|
||||||
@klass = Suo::Client::Base
|
@client = Suo::Client::Base.new(client: {})
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_not_implemented
|
def test_not_implemented
|
||||||
assert_raises(NotImplementedError) do
|
assert_raises(NotImplementedError) do
|
||||||
@klass.send(:get, TEST_KEY, {})
|
@client.send(:get, TEST_KEY)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -130,13 +148,12 @@ class TestMemcachedClient < Minitest::Test
|
|||||||
include ClientTests
|
include ClientTests
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
@klass = Suo::Client::Memcached
|
@dalli = Dalli::Client.new("127.0.0.1:11211")
|
||||||
@client = @klass.new
|
@client = Suo::Client::Memcached.new
|
||||||
@klass_client = Dalli::Client.new("127.0.0.1:11211")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def teardown
|
def teardown
|
||||||
@klass_client.delete(TEST_KEY)
|
@dalli.delete(TEST_KEY)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -144,13 +161,12 @@ class TestRedisClient < Minitest::Test
|
|||||||
include ClientTests
|
include ClientTests
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
@klass = Suo::Client::Redis
|
@redis = Redis.new
|
||||||
@client = @klass.new
|
@client = Suo::Client::Redis.new
|
||||||
@klass_client = Redis.new
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def teardown
|
def teardown
|
||||||
@klass_client.del(TEST_KEY)
|
@redis.del(TEST_KEY)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user