Skip to content

Commit

Permalink
Use keyword parameters for init, test by importing modules, initializ…
Browse files Browse the repository at this point in the history
…er using options, mutex for non-sysV
  • Loading branch information
kyewei committed Nov 10, 2015
1 parent 486f2f6 commit c18f642
Show file tree
Hide file tree
Showing 16 changed files with 310 additions and 296 deletions.
18 changes: 18 additions & 0 deletions lib/semian.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,24 @@ def destroy(name)
def resources
@resources ||= {}
end

module ReentrantMutex
attr_reader :monitor

def self.included(base)
def base.surround_with_mutex(*names)
names.each do |name|
m = instance_method(name)
define_method(name) do |*args, &block|
@monitor ||= Monitor.new
@monitor.synchronize do
m.bind(self).call(*args, &block)
end
end
end
end
end
end
end

require 'semian/resource'
Expand Down
4 changes: 2 additions & 2 deletions lib/semian/atomic_enum.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ class AtomicEnum < SharedMemoryObject #:nodoc:
:shared?, :destroy, :acquire_memory_object, :bind_init_fn
private :shared?, :acquire_memory_object, :bind_init_fn

def initialize(name, permissions, symbol_list)
@integer = Semian::AtomicInteger.new(name, permissions)
def initialize(symbol_list, **options)
@integer = Semian::AtomicInteger.new
initialize_lookup(symbol_list)
end

Expand Down
13 changes: 12 additions & 1 deletion lib/semian/atomic_integer.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
module Semian
class AtomicInteger < SharedMemoryObject #:nodoc:
include ::Semian::ReentrantMutex
attr_accessor :value

def initialize(_name, _permissions)
def initialize(**options)
@value = 0
end

def increment(val = 1)
@value += val
end

def destroy
if shared?
super
else
@value = 0
end
end

surround_with_mutex :value, :value=, :increment
end
end
21 changes: 9 additions & 12 deletions lib/semian/circuit_breaker.rb
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
module Semian
class CircuitBreaker #:nodoc:
def initialize(name, exceptions:, success_threshold:, error_threshold:, error_timeout:, permissions: 0660)
def initialize(name, exceptions:, success_threshold:, error_threshold:, error_timeout:, permissions:)
@name = name.to_s
@success_count_threshold = success_threshold
@error_count_threshold = error_threshold
@error_timeout = error_timeout
@exceptions = exceptions

@errors = ::Semian::SysVSlidingWindow.new(
"#{name}_sliding_window",
@error_count_threshold,
permissions)
@successes = ::Semian::SysVAtomicInteger.new(
"#{name}_atomic_integer",
permissions)
@state = ::Semian::SysVAtomicEnum.new(
"#{name}_atomic_enum",
permissions,
[:closed, :half_open, :open])
@errors = ::Semian::SysVSlidingWindow.new(@error_count_threshold,
name: "#{name}_sliding_window",
permissions: permissions)
@successes = ::Semian::SysVAtomicInteger.new(name: "#{name}_atomic_integer",
permissions: permissions)
@state = ::Semian::SysVAtomicEnum.new([:closed, :half_open, :open],
name: "#{name}_atomic_enum",
permissions: permissions)
# We do not need to #reset here since initializing is handled like this:
# (0) if data is not shared, then it's zeroed already
# (1) if no one is attached to the memory, zero it
Expand Down
19 changes: 13 additions & 6 deletions lib/semian/sliding_window.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
module Semian
class SlidingWindow < SharedMemoryObject #:nodoc:
extend Forwardable
include ::Semian::ReentrantMutex

def_delegators :@window, :size, :pop, :shift, :first, :last
attr_reader :max_size

def initialize(_name, max_size, _permissions)
def initialize(max_size, **options)
@max_size = max_size
@window = []
end
Expand All @@ -31,14 +32,20 @@ def push(time_ms)
self
end

def unshift(time_ms)
@window.pop while @window.size >= @max_size
@window.unshift(time_ms)
def clear
@window = []
self
end

def clear
@window = []
def destroy
if shared?
super
else
clear
end
end

surround_with_mutex :size, :pop, :shift, :first, :last, :max_size,
:resize_to, :<<, :push, :clear
end
end
4 changes: 2 additions & 2 deletions lib/semian/sysv_atomic_enum.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Semian
class SysVAtomicEnum < AtomicEnum #:nodoc:
def initialize(name, permissions, symbol_list)
@integer = Semian::SysVAtomicInteger.new(name, permissions)
def initialize(symbol_list, name:, permissions:)
@integer = Semian::SysVAtomicInteger.new(name: name, permissions: permissions)
initialize_lookup(symbol_list)
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/semian/sysv_atomic_integer.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Semian
class SysVAtomicInteger < AtomicInteger #:nodoc:
def initialize(name, permissions)
def initialize(name:, permissions:)
data_layout = [:int]
super unless acquire_memory_object(name, data_layout, permissions)
end
Expand Down
2 changes: 1 addition & 1 deletion lib/semian/sysv_sliding_window.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Semian
class SysVSlidingWindow < SlidingWindow #:nodoc:
def initialize(name, max_size, permissions)
def initialize(max_size, name:, permissions:)
data_layout = [:int, :int].concat(Array.new(max_size, :long))
super unless acquire_memory_object(name, data_layout, permissions)
end
Expand Down
57 changes: 36 additions & 21 deletions test/atomic_enum_test.rb
Original file line number Diff line number Diff line change
@@ -1,35 +1,50 @@
require 'test_helper'

class TestAtomicEnum < MiniTest::Unit::TestCase
def test_functionality
run_test_with_atomic_enum_classes do
CLASS = ::Semian::AtomicEnum

def setup
@enum = CLASS.new([:one, :two, :three],
name: 'TestAtomicEnum',
permissions: 0660)
end

def teardown
@enum.destroy
end

module AtomicEnumTestCases
def test_assigning
old = @enum.value
@enum.value = @enum.value
assert_equal old, @enum.value
@enum.value = :two
assert_equal :two, @enum.value
end
end

def test_will_throw_error_when_invalid_symbol_given
run_test_with_atomic_enum_classes do
def test_iterate_enum
@enum.value = :one
@enum.increment
assert_equal :two, @enum.value
@enum.increment
assert_equal :three, @enum.value
@enum.increment
assert_equal :one, @enum.value
@enum.increment(2)
assert_equal :three, @enum.value
@enum.increment(4)
assert_equal :one, @enum.value
@enum.increment(0)
assert_equal :one, @enum.value
end

def test_will_throw_error_when_invalid_symbol_given
assert_raises KeyError do
@enum.value = :four
end
end
end

private

def atomic_enum_classes
@classes ||= [::Semian::AtomicEnum]
end

def run_test_with_atomic_enum_classes(klasses = atomic_enum_classes)
klasses.each do |klass|
begin
@enum = klass.new('TestAtomicEnum', 0660, [:one, :two, :three])
yield(klass)
ensure
@enum.destroy
end
end
end
include AtomicEnumTestCases
end

37 changes: 15 additions & 22 deletions test/atomic_integer_test.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
require 'test_helper'

class TestAtomicInteger < MiniTest::Unit::TestCase
def test_access_value
run_test_with_atomic_integer_classes do
CLASS = ::Semian::AtomicInteger

def setup
@integer = CLASS.new(name: 'TestAtomicInteger', permissions: 0660)
@integer.value = 0
end

def teardown
@integer.destroy
end

module AtomicIntegerTestCases
def test_access_value
@integer.value = 0
assert_equal(0, @integer.value)
@integer.value = 99
Expand All @@ -15,10 +26,8 @@ def test_access_value
@integer.value = 6
assert_equal(6, @integer.value)
end
end

def test_increment
run_test_with_atomic_integer_classes do
def test_increment
@integer.value = 0
@integer.increment(4)
assert_equal(4, @integer.value)
Expand All @@ -29,21 +38,5 @@ def test_increment
end
end

private

def atomic_integer_classes
@classes ||= [::Semian::AtomicInteger]
end

def run_test_with_atomic_integer_classes(klasses = atomic_integer_classes)
klasses.each do |klass|
begin
@integer = klass.new('TestAtomicInteger', 0660)
@integer.value = 0
yield(klass)
ensure
@integer.destroy
end
end
end
include AtomicIntegerTestCases
end
5 changes: 0 additions & 5 deletions test/helpers/class_test_helper.rb

This file was deleted.

70 changes: 34 additions & 36 deletions test/sliding_window_test.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
require 'test_helper'

class TestSlidingWindow < MiniTest::Unit::TestCase
def test_slidinv_window_push
run_test_with_sliding_window_classes do
CLASS = ::Semian::SlidingWindow

def setup
@sliding_window = CLASS.new(6,
name: 'TestSlidingWindow',
permissions: 0660)
@sliding_window.clear
end

def teardown
@sliding_window.destroy
end

module SlidingWindowTestCases
def test_sliding_window_push
assert_equal(0, @sliding_window.size)
@sliding_window << 1
assert_correct_first_and_last_and_size(@sliding_window, 1, 1, 1, 6)
@sliding_window << 5
assert_correct_first_and_last_and_size(@sliding_window, 1, 5, 2, 6)
end
end

def test_sliding_window_resize
run_test_with_sliding_window_classes do
def test_sliding_window_resize
assert_equal(0, @sliding_window.size)
@sliding_window << 1 << 2 << 3 << 4 << 5 << 6
assert_correct_first_and_last_and_size(@sliding_window, 1, 6, 6, 6)
Expand All @@ -23,49 +34,36 @@ def test_sliding_window_resize
@sliding_window.resize_to 6
assert_correct_first_and_last_and_size(@sliding_window, 2, 6, 5, 6)
end
end

def test_sliding_window_edge_falloff
run_test_with_sliding_window_classes do
def test_sliding_window_edge_falloff
assert_equal(0, @sliding_window.size)
@sliding_window << 0 << 1 << 2 << 3 << 4 << 5 << 6 << 7
assert_correct_first_and_last_and_size(@sliding_window, 2, 7, 6, 6)
@sliding_window.shift
assert_correct_first_and_last_and_size(@sliding_window, 3, 7, 5, 6)
@sliding_window.clear
end
end

private

def sliding_window_classes
@classes ||= [::Semian::SlidingWindow]
end
module SlidingWindowUtilityMethods
def assert_correct_first_and_last_and_size(sliding_window, first, last, size, max_size)
assert_equal(first, sliding_window.first)
assert_equal(last, sliding_window.last)
assert_equal(size, sliding_window.size)
assert_equal(max_size, sliding_window.max_size)
end

def run_test_with_sliding_window_classes(klasses = sliding_window_classes)
klasses.each do |klass|
begin
@sliding_window = klass.new('TestSlidingWindow', 6, 0660)
@sliding_window.clear
yield(klass)
ensure
@sliding_window.destroy
end
def assert_sliding_windows_in_sync(sliding_window_1, sliding_window_2)
# it only exposes ends, size, and max_size, so can only check those
assert_equal(sliding_window_1.first, sliding_window_2.first)
assert_equal(sliding_window_1.last, sliding_window_2.last)
assert_equal(sliding_window_1.size, sliding_window_2.size)
assert_equal(sliding_window_1.max_size, sliding_window_2.max_size)
end
end

def assert_correct_first_and_last_and_size(sliding_window, first, last, size, max_size)
assert_equal(first, sliding_window.first)
assert_equal(last, sliding_window.last)
assert_equal(size, sliding_window.size)
assert_equal(max_size, sliding_window.max_size)
end
include SlidingWindowTestCases

def assert_sliding_windows_in_sync(sliding_window_1, sliding_window_2)
# it only exposes ends, size, and max_size, so can only check those
assert_equal(sliding_window_1.first, sliding_window_2.first)
assert_equal(sliding_window_1.last, sliding_window_2.last)
assert_equal(sliding_window_1.size, sliding_window_2.size)
assert_equal(sliding_window_1.max_size, sliding_window_2.max_size)
end
private

include SlidingWindowUtilityMethods
end
Loading

0 comments on commit c18f642

Please sign in to comment.