Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fix race conditions feeding events to all listeners

  • Loading branch information...
commit 4f0bf50643fa35bc47acd72fe022c956f5f70333 1 parent cb53676
@ConradIrwin ConradIrwin authored
Showing with 33 additions and 2 deletions.
  1. +7 −2 lib/em-imap/connection.rb
  2. +26 −0 spec/client_spec.rb
View
9 lib/em-imap/connection.rb
@@ -103,7 +103,10 @@ def unbind
end
def fail_all(error, closed=false)
- @listeners.each{ |listener| listener.fail error }
+ # NOTE: Take a shallow clone of the listeners here so that we get guaranteed
+ # behaviour. We want to fail any listeners that may be added by the errbacks
+ # of other listeners.
+ @listeners.clone.each{ |listener| listener.fail error } while @listeners.size > 0
close_connection unless closed
end
@@ -115,7 +118,9 @@ def add_to_listener_pool(listener)
# EM::IMAP::ResponseParser. Each response is a Net::IMAP response
# object. (FIXME)
def receive_response(response)
- @listeners.each{ |listener| listener.receive_event response }
+ # NOTE: Take a shallow clone of the listeners so that if receiving an
+ # event causes a new listener to be added, it won't receive this response!
+ @listeners.clone.each{ |listener| listener.receive_event response }
end
# Await the response that marks the completion of this command,
View
26 spec/client_spec.rb
@@ -157,5 +157,31 @@
a.should == true
b.should == true
end
+
+ it "should fail any commands inserted by errbacks of commands on catastrophic failure" do
+ a = false
+ @client.create("Encyclop\xc3\xa6dia").errback do |e|
+ @client.logout.errback do
+ a = true
+ end
+ end
+ @connection.fail_all EOFError.new("Testing error")
+ a.should == true
+ end
+
+ it "should not pass response objects to listeners added in callbacks" do
+ rs = []
+ @connection.should_receive(:send_data).with("RUBY0001 SELECT \"[Google Mail]/All Mail\"\r\n")
+ @client.select("[Google Mail]/All Mail").callback do |response|
+ @connection.should_receive(:send_data).with("RUBY0002 IDLE\r\n")
+ @client.idle do |r|
+ rs << r
+ end
+ end
+ @connection.receive_data "RUBY0001 OK [READ-WRITE] [Google Mail]/All Mail selected. (Success)\r\n"
+ rs.length.should == 0
+ @connection.receive_data "+ idling\r\n"
+ rs.length.should == 1
+ end
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.