Mocking an object method within a Thread? - ruby

In the situation below the #crawl object DOES RECEIVE the crawl call, but the method mock fails ie: the method is not mocked.
Does Thread somehow create its own copy of the #crawl object escaping the mock?
#crawl.should_receive(:crawl).with(an_instance_of(String)).twice.and_return(nil)
threads = #crawl.create_threads
thread creation code:
def crawl(uri)
dosomecrawling
end
def create_threads
(1..5).each do
Thread.new do
crawl(someurifeedingmethod)
end
end
end

It does not appear from the code posted that you are joining the threads. If so, there is a race condition: Sometimes the test will execute with some or all of the threads not having done their job; The fix is along these lines:
!/usr/bin/ruby1.9
class Crawler
def crawl(uri)
dosomecrawling
end
def create_threads
#threads = (1..5).collect do
Thread.new do
crawl(someurifeedingmethod)
end
end
end
def join
#threads.each do |thread|
thread.join
end
end
end
describe "the above code" do
it "should crawl five times" do
crawler = Crawler.new
uri = "uri"
crawler.should_receive(:someurifeedingmethod).with(no_args).exactly(5).times.and_return(uri)
crawler.should_receive(:crawl).with(uri).exactly(5).times
crawler.create_threads
crawler.join
end
end

This code works perfectly.
You can add 5 times the expects.
class Hello
def crawl(uri)
puts uri
end
def create_threads
(1..5).each do
Thread.new do
crawl('http://hello')
end
end
end
end
describe 'somting' do
it 'should mock' do
crawl = Hello.new
5.times do
crawl.should_receive(:crawl).with(an_instance_of(String)).and_return(nil)
end
threads = crawl.create_threads
end
end

Related

How to "magically" add code to all public class methods in ruby?

I would like to be able to insert some code at the beginning and at the end of methods in my class. I would like to avoid repetition as well.
I found this answer helpful, however it doesn't help with the repetition.
class MyClass
def initialize
[:a, :b].each{ |method| add_code(method) }
end
def a
sleep 1
"returning from a"
end
def b
sleep 1
"returning from b"
end
private
def elapsed
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
block_value = yield
finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
puts "elapsed: #{finish - start} seconds, block_value: #{block_value}."
block_value
end
def add_code(meth)
meth = meth.to_sym
self.singleton_class.send(:alias_method, "old_#{meth}".to_sym, meth)
self.singleton_class.send(:define_method, meth) do
elapsed do
send("old_#{meth}".to_sym)
end
end
end
end
The above does work, but what would be a more elegant solution? I would love to be able to, for example, put attr_add_code at the beginning of the class definition and list the methods I want the code added to, or perhaps even specify that I want it added to all public methods.
Note: The self.singleton_class is just a workaround since I am adding code during the initialisation.
If by repetition you mean the listing of methods you want to instrument, then you can do something like:
module Measure
def self.prepended(base)
method_names = base.instance_methods(false)
base.instance_eval do
method_names.each do |method_name|
alias_method "__#{method_name}_without_timing", method_name
define_method(method_name) do
t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
public_send("__#{method_name}_without_timing")
t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
puts "Method #{method_name} took #{t2 - t1}"
end
end
end
end
end
class Foo
def a
puts "a"
sleep(1)
end
def b
puts "b"
sleep(2)
end
end
Foo.prepend(Measure)
foo = Foo.new
foo.a
foo.b
# => a
# => Method a took 1.0052679998334497
# => b
# => Method b took 2.0026899999938905
Main change is that i use prepend and inside the prepended callback you can find the list of methods defined on the class with instance_methods(false), the falseparameter indicating that ancestors should not be considered.
Instead of using method aliasing, which in my opinion is something of the past since the introduction of Module#prepend, we can prepend an anonymous module that has a method for each instance method of the class to be measured. This will cause calling MyClass#a to invoke the method in this anonymous module, which measures the time and simply resorts to super to invoke the actual MyClass#a implementation.
def measure(klass)
mod = Module.new do
klass.instance_methods(false).each do |method|
define_method(method) do |*args, &blk|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
value = super(*args, &blk)
finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
puts "elapsed: #{finish - start} seconds, value: #{value}."
value
end
end
end
klass.prepend(mod)
end
Alternatively, you can use class_eval, which is also faster and allows you to just call super without specifying any arguments to forward all arguments from the method call, which isn't possible with define_method.
def measure(klass)
mod = Module.new do
klass.instance_methods(false).each do |method|
class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{method}(*)
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
value = super
finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
puts "elapsed: \#{finish - start} seconds, value: \#{value}."
value
end
CODE
end
end
klass.prepend(mod)
end
To use this, simply do:
measure(MyClass)
It looks like you're trying to do some benchmarking. Have you checked out the benchmark library? It's in the standard library.
require 'benchmark'
puts Benchmark.measure { MyClass.new.a }
puts Benchmark.measure { MyClass.new.b }
Another possibility would be to create a wrapper class like so:
class Measure < BasicObject
def initialize(target)
#target = target
end
def method_missing(name, *args)
t1 = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
target.public_send(name, *args)
t2 = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
::Kernel.puts "Method #{name} took #{t2 - t1}"
end
def respond_to_missing?(*args)
target.respond_to?(*args)
end
private
attr_reader :target
end
foo = Measure.new(Foo.new)
foo.a
foo.b

ruby local thread variable access from other methods

class Tour
def destinations
threads = []
[:new_york, :london, :syndey].each { |city|
#threads << Thread.new {
where = city
goto(where)
}
}
threads.each(&:join)
end
def where=(location)
Thread.current[:city] = location
end
def where
Thread.current[:city]
end
def goto(city)
puts "I am going to visit #{city}."
end
end
Tour.new.destinations
In order to access thread local variable in method goto(), the thread local variable has to be passed to it like goto(where), if there are many other similar methods need to do things based upon current thread local variable :city, then it has to be passed to other methods too.
I guess there is an elegant/ruby way to avoid passing thread local variable as an option, what does that look like?
This seems like you'll trip yourself up a lot. It might be better to initialize a new object for each thread.
class Tour
def self.destinations
threads = []
[:new_york, :london, :sydney].each do |city|
threads << Thread.new { Destination.new(city).go }
end
threads.each(&:join)
end
end
class Destination
attr_reader :location
def initialize(location)
#location = location
end
def go
puts "I am going to visit #{location}."
end
end
# Tour.destinations
Suggested reading: https://blog.engineyard.com/2011/a-modern-guide-to-threads

Testing infinite loop with MiniTest and using mocking

I have a section in my code which polls a queue for a message and then acts on it depending on the message type:
#queue = Foo::Queue.new
loop do
#queue.poll do |message|
if message[:task] == TAKEACTION
result = takeaction(message)
#queue.send_result(result, message)
end
#queue.pong(message) if message[:task] == PING
end
end
How do I set up a test to supply a single message and verify that the #queue acts on it as I expect?
I have seen very little about testing blocks in minitest, and haven't found anything in ruby regarding breaking out of infinite loops, though I found one idea in python where you set up the second run to throw an exception.
Can any ruby / minitest gurus help?
For minitest using a stub will work. The example below is self contained and can run on its own. You can send an exception as a lambda with a stub to break the infinite loop and continue testing.
# class receiving the messages from class being tested
class Obj
def method_if_true
# do some stuff
return 'anything that is true'
end
def method_if_false
# do some stuff
false
end
end
# class to be tested
class TestingLoop
def initialize(args)
#obj = args.fetch(:object, Obj.new)
#bool = args[:bool]
end
def looping
loop do
if #bool
#obj.method_if_true
# #bool is true
elsif !#bool
#obj.method_if_false
# #bool is false
end
end
end
end
require 'minitest/autorun'
# class that tests
class TestTestingLoop < MiniTest::Test
def setup
#obj = Obj.new
#raises_exception = lambda { raise RuntimeError.new }
# could use the '->' syntax instead of the word lambda
end
def test_sends_correct_method_when_true
#obj.stub :method_if_true, #raises_exception do
testing_loop = TestingLoop.new({object: #obj, bool: true})
assert_raises(RuntimeError) { testing_loop.looping }
end
end
def test_sends_correct_method_when_false
#obj.stub :method_if_false, #raises_exception do
testing_loop = TestingLoop.new({object: #obj, bool: false})
assert_raises(RuntimeError) { testing_loop.looping }
end
end
end

ruby Thread#allocate TypeError

I was looking in detail at the Thread class. Basically, I was looking for an elegant mechanism to allow thread-local variables to be inherited as threads are created. For example the functionality I am looking to create would ensure that
Thread.new do
self[:foo]="bar"
t1=Thread.new { puts self[:foo] }
end
=> "bar"
i.e. a Thread would inherit it's calling thread's thread-local variables
So I hit upon the idea of redefining Thread.new, so that I could add an extra step to copy the thread-local variables into the new thread from the current thread. Something like this:
class Thread
def self.another_new(*args)
o=allocate
o.send(:initialize, *args)
Thread.current.keys.each{ |k| o[k]=Thread.current[k] }
o
end
end
But when I try this I get the following error:
:in `allocate': allocator undefined for Thread (TypeError)
I thought that as Thread is a subclass of Object, it should have a working #allocate method. Is this not the case?
Does anyone have any deep insight on this, and on how to achieve the functionality I am looking for.
Thanks in advance
Steve
Thread.new do
Thread.current[:foo]="bar"
t1=Thread.new(Thread.current) do |parent|
puts parent[:foo] ? parent[:foo] : 'nothing'
end.join
end.join
#=> bar
UPDATED:
Try this in irb:
thread_ext.rb
class Thread
def self.another_new(*args)
parent = Thread.current
a = Thread.new(parent) do |parent|
parent.keys.each{ |k| Thread.current[k] = parent[k] }
yield
end
a
end
end
use_case.rb
A = Thread.new do
Thread.current[:local_a]="A"
B1 =Thread.another_new do
C1 = Thread.another_new{p Thread.current[:local_a] }.join
end
B2 =Thread.another_new do
C2 = Thread.another_new{p Thread.current[:local_a] }.join
end
[B1, B2].each{|b| b.join }
end.join
output
"A"
"A"
Here is a revised answer based on #CodeGroover's suggestion, with a simple unit test harness
ext/thread.rb
class Thread
def self.inherit(*args, &block)
parent = Thread.current
t = Thread.new(parent, *args) do |parent|
parent.keys.each{ |k| Thread.current[k] = parent[k] }
yield *args
end
t
end
end
test/thread.rb
require 'test/unit'
require 'ext/thread'
class ThreadTest < Test::Unit::TestCase
def test_inherit
Thread.current[:foo]=1
m=Mutex.new
#check basic inheritence
t1= Thread.inherit do
assert_equal(1, Thread.current[:foo])
end
#check inheritence with parameters - in this case a mutex
t2= Thread.inherit(m) do |m|
assert_not_nil(m)
m.synchronize{ Thread.current[:bar]=2 }
assert_equal(1, Thread.current[:foo])
assert_equal(2, Thread.current[:bar])
sleep 0.1
end
#ensure t2 runs its mutexs-synchronized block first
sleep 0.05
#check that the inheritence works downwards only - not back up in reverse
m.synchronize do
assert_nil(Thread.current[:bar])
end
[t1,t2].each{|x| x.join }
end
end
I was looking for the same thing recently and was able to come up with the following answer. Note I am aware the following is a hack and not recommended, but for the sake of answering the specific question on how you could alter the Thread.new functionality, I have done as following:
class Thread
class << self
alias :original_new :new
def new(*args, **options, &block)
original_thread = Thread.current
instance = original_new(*args, **options, &block)
original_thread.keys.each do |key|
instance[key] = original_thread[key]
end
instance
end
end
end

Ruby, MongoDB: How to share a Cursor between threads?

The following does not work. The call to resources.next_document within the thread returns nil. The same call without threading works as expected.
Any MongoDB experts out there? :P
resources = db[Resource::COLLECTION].find
number_of_threads.times do
threads << Thread.new do
while resource = resources.next_document
puts 'one more doc'
end
end
end
This is the solution I ended up using:
Feedback welcome
pool = DocumentPool.new(db)
5.times do
Thread.new do
while doc = pool.next_document
#something cool
end
end
end
class DocumentPool
COLLECTION = 'some_collection'
def initialize(db)
#db = db
#first_doc = cursor.next_document
end
def collection
#db[COLLECTION]
end
def cursor
#cursor ||= collection.find
end
def shift
doc = nil
if #first_doc
doc = #first_doc
#first_doc = nil
else
doc = cursor.next_document
end
doc
end
def count
collection.count
end
end
Although the driver itself is threadsafe, individuals cursor aren't, so you can't reliably process the data in the way you're describing.
One possibility would be to have a single thread that iterates over the documents, handing them off to any number of worker threads for the actual processing.

Resources