Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 987
pfh Avatar asked May 21 '13 14:05

pfh


People also ask

What is Ruby EventMachine?

EventMachine is a software system designed for writing highly scalable applications for Ruby. It provides event-driven I/O using the reactor pattern. EventMachine is the most popular library for concurrent computing in the Ruby programming language.

What is EventMachine gem?

EventMachine implements a fast, single-threaded engine for arbitrary network communications. It's extremely easy to use in Ruby. EventMachine wraps all interactions with IP sockets, allowing programs to concentrate on the implementation of network protocols. It can be used to create both network servers and clients.


1 Answers

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.

like image 78
Subhas Avatar answered Sep 24 '22 22:09

Subhas