How to test em-mongo + Goliath? - ruby

This below app saves some data to the db and I want to test that it saves properly.
require 'goliath'
class App < Goliath::API
def response(env)
db = EM::Mongo::Connection.new('localhost').db('hello')
db.collection('coll').insert({'identifier => 1'})
[204, {}, {}]
end
end
require 'goliath/test_helper'
Goliath.env = :test
describe App do
include Goliath::TestHelper
it do
with_api(described_class) do
get_request do |req|
db = EM::Mongo::Connection.new('localhost').db('hello')
db.collection('coll').first.callback do |rec|
rec['identifier'].should == 100
end
end
end
end
end
The above spec passes since reactor ends before callback returns. I thought about manually starting a reactor like:
EM.run do
db = EM::Mongo::Connection.new('localhost').db('hello')
db.collection('coll').first.callback do |rec|
rec['identifier'].should == 100
EM.stop
end
end
Though I'm not sure if starting the reactor for every spec is good practice. Help please?

The problem is that when the get_request is setup we add a callback on the request that stops the event loop. So, as soon as your block finishes (which will be before the connection is even created), it will stop the reactor.
I'm not sure the best solution, but a crappy one would be to override:
def hookup_request_callbacks(req, errback, &blk)
req.callback &blk
req.callback { stop }
req.errback &errback if errback
req.errback { stop }
end
in your test class after you include Goliath::TestHelper. Then, I think, you should be able to write your own that just has something like:
def hookup_request_callbacks(req, errback, &blk)
req.callback &blk
req.errback &errback if errback
req.errback { stop }
end
You'll just have to make sure you call stop in your callback from Mongo.
I haven't actually tested this, so let me know if something doesn't work and I can dig in further.

#dj2's solution works great, but I decided instead of use mongo gem in specs, instead of em-mongo. Since mongo blocks, I don't have to worry about Goliath stopping the reactor before database returns results.

Related

How to make sure each Minitest unit test is fast enough?

I have a large amount of Minitest unit tests (methods), over 300. They all take some time, from a few milliseconds to a few seconds. Some of them hang up, sporadically. I can't understand which one and when.
I want to apply Timeout to each of them, to make sure anyone fails if it takes longer than, say, 5 seconds. Is it achievable?
For example:
class FooTest < Minitest::Test
def test_calculates_something
# Something potentially too slow
end
end
You can use the Minitest PLugin loader to load a plugin. This is, by far, the cleanest solution. The plugin system is not very well documented, though.
Luckily, Adam Sanderson wrote an article on the plugin system.
The best news is that this article explains the plugin system by writing a sample plugin that reports slow tests. Try out minitest-snail, it is probably almost what you want.
With a little modification we can use the Reporter to mark a test as failed if it is too slow, like so (untested):
File minitest/snail_reporter.rb:
module Minitest
class SnailReporter < Reporter
attr_reader :max_duration
def self.options
#default_options ||= {
:max_duration => 2
}
end
def self.enable!(options = {})
#enabled = true
self.options.merge!(options)
end
def self.enabled?
#enabled ||= false
end
def initialize(io = STDOUT, options = self.class.options)
super
#max_duration = options.fetch(:max_duration)
end
def record result
#passed = result.time < max_duration
slow_tests << result if !#passed
end
def passed?
#passed
end
def report
return if slow_tests.empty?
slow_tests.sort_by!{|r| -r.time}
io.puts
io.puts "#{slow_tests.length} slow tests."
slow_tests.each_with_index do |result, i|
io.puts "%3d) %s: %.2f s" % [i+1, result.location, result.time]
end
end
end
end
File minitest/snail_plugin.rb:
require_relative './snail_reporter'
module Minitest
def self.plugin_snail_options(opts, options)
opts.on "--max-duration TIME", "Report tests that take longer than TIME seconds." do |max_duration|
SnailReporter.enable! :max_duration => max_duration.to_f
end
end
def self.plugin_snail_init(options)
if SnailReporter.enabled?
io = options[:io]
Minitest.reporter.reporters << SnailReporter.new(io)
end
end
end

How can I make sure threads inside my class end after each rspec test?

I have a jruby class which contains a heartbeat that does something every certain number of seconds: (simplified code below)
class Client
def initialise
#interval = 30
#heartbeat = Thread.new do
begin
loop do
puts "heartbeat"
sleep #interval
end
rescue Exception => e
Thread.main.raise e
end
end
end
end
And I have a range of rspec tests that instantiate this class.
At the end of each test, I would expect the object to be destroyed, but the threads seem to remain.
At the moment I've fixed this with:
client.rb:
def kill
#heartbeat.kill
end
rspec:
after(:all) do
client.kill
end
Which seems to do the job - but this doesn't feel like the best way to do it.
What is the best way to approach this?
Using version jruby-9.1.10.0 & rspec 3.7.0
Edit:
As per http://ruby-doc.org/core-2.4.0/Thread.html I would expect the thread to normally terminate when the main thread does
In my tests I instantiate the client with
describe Client do
context 'bla' do
let(:client) do
described_class.new
end
it 'blas' do
end
end
end
You should replace after(:all) with after(:each).
Should be the correct syntax for what you want to do because after(:all) evaluates after all test cases have been run.

Rspec let() cleanup

Is there a way to keep track of variables that are created when using let?
I have a series of tests, some of which use let(:server) { #blah blah }. Part of the blah is to wait for the server to start up so that it is in a decent state before it is used.
The issue comes when I'm done with that test. I want to kill the server using server.kill(). This would be almost perfect if I could say something to the effect of
after(:each) { server.kill }
But this would create the server and waste all the resources/time to create it when it is referenced, only to kill it immediately if the server hadn't been used in the preceding test. Is there a way to keep track of and only clean up the server if it has been used?
I've come across a similar problem. A simple way to solve this is to set a instance variable in the let method to track if the object was created:
describe MyTest do
before(:each) { #created_server = false }
let(:server) {
#created_server = true
Server.new
}
after(:each) { server.kill if #created_server }
end
What I would do is something like this:
describe MyTest do
let(:server) { Server.new }
context "without server" do
## dont kill the server in here.
end
context "with server" do
before do
server
end
after(:each) { server.kill }
it {}
it {}
end
end
This is definitely a hack:
describe "cleanup for let" do
let(:expensive_object) {
ExpensiveObject.new
}
after(:context) {
v = __memoized[:expensive_object]
v.close if v
}
end
I figured that rspec had to be storing these lazy values somewhere the instance could access them, and __memoized is that place.
With a helper, it becomes a bit tidier:
def cleanup(name, &block)
after(:context) do
v = __memoized[name]
instance_exec(v, &block) if v
end
end
describe "cleanup for let" do
let(:expensive_object) {
ExpensiveObject.new
}
cleanup(:expensive_object) { |v|
v.close
}
end
There's still room for improvement, though. I think I would rather not have to type the object's name twice, so something like this would be nicer:
describe "cleanup for let" do
let(:expensive_object) {
ExpensiveObject.new
}.cleanup { |v|
v.close
}
end
I'm not sure I can do that without hacking rspec to pieces, but maybe if rspec themselves saw the benefit of it, something could be done in core...
Edit: Changed to using instance_exec because rspec started whining if things were called from the wrong context, and changed cleanup to be after(:context), because apparently this is the level it's memoising at.
Just write a small decorator to handle both the explicit and implicit starting of the server and which allows you to determine if the server has been started.
Imagine this to be the real server that needs to be started:
class TheActualServer
def initialize
puts 'Server starting'
end
def operation1
1
end
def operation2
2
end
def kill
puts 'Server stopped'
end
end
The reusable decorator could look like this:
class ServiceWrapper < BasicObject
def initialize(&start_procedure)
#start_procedure = start_procedure
end
def started?
!!#instance
end
def instance
#instance ||= #start_procedure.call
end
alias start instance
private
def method_missing(method_name, *arguments)
instance.public_send(method_name, *arguments)
end
def respond_to?(method_name)
super || instance.respond_to?(method_name)
end
end
Now you can apply this in your specs like the following:
describe 'something' do
let(:server) do
ServiceWrapper.new { TheActualServer.new }
end
specify { expect(server.operation1).to eql 1 }
specify { expect(server.operation2).to eql 2 }
specify { expect(123).to be_a Numeric }
context 'when server is running' do
before(:each) { server.start }
specify { expect('abc').to be_a String }
specify { expect(/abc/).to be_a Regexp }
end
after(:each) { server.kill if server.started? }
end
When a method is called on the decorator, it will run it's own implementation if one exists. For example if #started? is called, it will answer whether the actual server has been started or not. If it doesn't have an own implementation of that method, it will delegate the method call to the server object returned by that. If it doesn't have a reference to an instance of the actual server at that point, it will run the provided start_procedure to get one and memoize that for future calls.
If you put all the posted code into a file called server_spec.rb you can then run it with:
rspec server_spec.rb
The output will be like this:
something
Server starting
Server stopped
should eql 1
Server starting
Server stopped
should eql 2
should be a kind of Numeric
when server is running
Server starting
Server stopped
should be a kind of String
Server starting
Server stopped
should be a kind of Regexp
Finished in 0.00165 seconds (files took 0.07534 seconds to load)
5 examples, 0 failures
Note that in the examples 1 and 2, methods on the server are called, and therefore you see the output of the server that is implicitly started by the decorator.
In example 3 there is no interaction with the server at all, therefore you don't see the server's output in the log.
Then again in examples 4 and 5, there is not direct interaction with the server object in the example code, but the server is explicitly started through a before block, which can also be seen in the output.

Ruby EventMachine testing

My first question concerning Ruby.
I'm trying to test EventMachine interaction inside the Reactor loop - I guess it could be classified as "functional" testing.
Say I have two classes - a server and a client. And I want to test both sides - I need to be sure about their interaction.
Server:
require 'singleton'
class EchoServer < EM::Connection
include EM::Protocols::LineProtocol
def post_init
puts "-- someone connected to the echo server!"
end
def receive_data data
send_data ">>>you sent: #{data}"
close_connection if data =~ /quit/i
end
def unbind
puts "-- someone disconnected from the echo server!"
end
end
Client:
class EchoClient < EM::Connection
include EM::Protocols::LineProtocol
def post_init
send_data "Hello"
end
def receive_data(data)
#message = data
p data
end
def unbind
puts "-- someone disconnected from the echo server!"
end
end
So, I've tried different approaches and came up with nothing.
The fundamental question is - could I somehow test my code with RSpec, using should_recive?
EventMachine parameter should be a class or a module, so I can't send instantiated/mocked code inside. Right?
Something like this?
describe 'simple rspec test' do
it 'should pass the test' do
EventMachine.run {
EventMachine::start_server "127.0.0.1", 8081, EchoServer
puts 'running echo server on 8081'
EchoServer.should_receive(:receive_data)
EventMachine.connect '127.0.0.1', 8081, EchoClient
EventMachine.add_timer 1 do
puts 'Second passed. Stop loop.'
EventMachine.stop_event_loop
end
}
end
end
And, if not, how would you do it with EM::SpecHelper? I have this code using it, and can't figure out what I'm doing wrong.
describe 'when server is run and client sends data' do
include EM::SpecHelper
default_timeout 2
def start_server
EM.start_server('0.0.0.0', 12345) { |ws|
yield ws if block_given?
}
end
def start_client
client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
yield client if block_given?
return client
end
describe "examples from the spec" do
it "should accept a single-frame text message" do
em {
start_server
start_client { |client|
client.onopen {
client.send_data("\x04\x05Hello")
}
}
}
end
end
end
Tried a lot of variations of these tests and I just can't figure it out. I'm sure I'm missing something here...
Thanks for your help.
The simplest solution that I can think of is to change this:
EchoServer.should_receive(:receive_data)
To this:
EchoServer.any_instance.should_receive(:receive_data)
Since EM is expecting a class to start a server, the above any_instance trick will expect any instance of that class to receive that method.
The EMSpecHelper example (while being official/standard) is quite convoluted, I'd rather stick with the first rspec and use any_instance, just for simplicity's sake.

How can I use EventMachine from within a Sinatra app?

I use an api, that is written on top of EM. This means that to make a call, I need to write something like the following:
EventMachine.run do
api.query do |result|
# Do stuff with result
end
EventMachine.stop
end
Works fine.
But now I want to use this same API within a Sinatra controller. I tried this:
get "/foo" do
output = ""
EventMachine.run do
api.query do |result|
output = "Result: #{result}"
end
EventMachine.stop
end
output
end
But this doesn't work. The run block is bypassed, so an empty response is returned and once stop is called, Sinatra shuts down.
Not sure if it's relevant, but my Sinatra app runs on Thin.
What am I doing wrong?
I've found a workaround by busy waiting until data becomes available. Possibly not the best solution, but it works at least:
helpers do
def wait_for(&block)
while (return_val = block.call).nil?
sleep(0.1)
end
return_val
end
end
get "/foo" do
output = nil
EventMachine.run do
api.query do |result|
output = "Result: #{result}"
end
end
wait_for { output }
end

Resources