rumbster 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +515 -0
 - data/README +56 -0
 - data/Rakefile +12 -0
 - data/lib/message_observers.rb +40 -0
 - data/lib/rumbster.rb +24 -0
 - data/lib/smtp_protocol.rb +42 -0
 - data/lib/smtp_states.rb +159 -0
 - data/test/message_observers_test.rb +102 -0
 - data/test/rumbster_test.rb +69 -0
 - data/test/smtp_protocol_test.rb +64 -0
 - data/test/smtp_states_test.rb +217 -0
 - data/vendor/tmail.rb +4 -0
 - data/vendor/tmail/.cvsignore +3 -0
 - data/vendor/tmail/Makefile +19 -0
 - data/vendor/tmail/address.rb +222 -0
 - data/vendor/tmail/base64.rb +52 -0
 - data/vendor/tmail/compat.rb +39 -0
 - data/vendor/tmail/config.rb +50 -0
 - data/vendor/tmail/encode.rb +447 -0
 - data/vendor/tmail/header.rb +895 -0
 - data/vendor/tmail/info.rb +14 -0
 - data/vendor/tmail/loader.rb +1 -0
 - data/vendor/tmail/mail.rb +869 -0
 - data/vendor/tmail/mailbox.rb +386 -0
 - data/vendor/tmail/mbox.rb +1 -0
 - data/vendor/tmail/net.rb +260 -0
 - data/vendor/tmail/obsolete.rb +122 -0
 - data/vendor/tmail/parser.rb +1475 -0
 - data/vendor/tmail/parser.y +372 -0
 - data/vendor/tmail/port.rb +356 -0
 - data/vendor/tmail/scanner.rb +22 -0
 - data/vendor/tmail/scanner_r.rb +243 -0
 - data/vendor/tmail/stringio.rb +256 -0
 - data/vendor/tmail/textutils.rb +197 -0
 - data/vendor/tmail/tmail.rb +1 -0
 - data/vendor/tmail/utils.rb +23 -0
 - metadata +88 -0
 
    
        data/README
    ADDED
    
    | 
         @@ -0,0 +1,56 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Rumbster README
         
     | 
| 
      
 2 
     | 
    
         
            +
            ===============
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
              Rumbster is a fake smtp server for email testing in Ruby.
         
     | 
| 
      
 5 
     | 
    
         
            +
              Rumbster was developed to as a way to acceptance test email
         
     | 
| 
      
 6 
     | 
    
         
            +
              sending applications.
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            Requirements
         
     | 
| 
      
 9 
     | 
    
         
            +
            ------------
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
               * Ruby 1.8.2 or later (may work with earlier versions)
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            License
         
     | 
| 
      
 14 
     | 
    
         
            +
            -------
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              GNU LGPL, Lesser General Public License version 2.1
         
     | 
| 
      
 17 
     | 
    
         
            +
              For details of LGPL, see file "COPYING".
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            Example Usage
         
     | 
| 
      
 20 
     | 
    
         
            +
            -------------
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            A good source for usage information is the unit tests in the 
         
     | 
| 
      
 23 
     | 
    
         
            +
            test directory.   Below is an example of the usage.
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            class TestEmails < Test::Unit::TestCase
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 28 
     | 
    
         
            +
                @rumbster = Rumbster.new(port)
         
     | 
| 
      
 29 
     | 
    
         
            +
                @message_observer = MailMessageObserver.new
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                @rumbster.add_observer @message_observer
         
     | 
| 
      
 32 
     | 
    
         
            +
                @rumbster.add_observer FileMessageObserver.new('some/directory')
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                @rumbster.start
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              def teardown
         
     | 
| 
      
 38 
     | 
    
         
            +
                @rumbster.stop
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              def test_email_is_sent
         
     | 
| 
      
 42 
     | 
    
         
            +
                send_email
         
     | 
| 
      
 43 
     | 
    
         
            +
                assert_equal 1, @message_observer.messages.size
         
     | 
| 
      
 44 
     | 
    
         
            +
                assert_equal 'junk@junk.com', @message_observer.messages.first.to
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
            end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            Bug Report
         
     | 
| 
      
 49 
     | 
    
         
            +
            ----------
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              Any bug reports are welcome.
         
     | 
| 
      
 52 
     | 
    
         
            +
              If you encounter a bug, please email me.
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
              Adam Esterline
         
     | 
| 
      
 55 
     | 
    
         
            +
              adam@esterlines.com
         
     | 
| 
      
 56 
     | 
    
         
            +
              http://adamesterline.com
         
     | 
    
        data/Rakefile
    ADDED
    
    
| 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            $:.unshift(File.join(File.dirname(__FILE__), '..', 'vendor'))
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'fileutils'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'tmail'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            class FileMessageObserver
         
     | 
| 
      
 7 
     | 
    
         
            +
              include FileUtils
         
     | 
| 
      
 8 
     | 
    
         
            +
              
         
     | 
| 
      
 9 
     | 
    
         
            +
              def initialize(message_directory, system_time = SystemTime.new)
         
     | 
| 
      
 10 
     | 
    
         
            +
                @message_directory = message_directory
         
     | 
| 
      
 11 
     | 
    
         
            +
                @system_time = system_time
         
     | 
| 
      
 12 
     | 
    
         
            +
                mkdir_p(message_directory)
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              def update(message_string)
         
     | 
| 
      
 16 
     | 
    
         
            +
                mail = TMail::Mail.parse(message_string)
         
     | 
| 
      
 17 
     | 
    
         
            +
                
         
     | 
| 
      
 18 
     | 
    
         
            +
                file_name = File.join(@message_directory, "#{@system_time.current_time_in_seconds}_#{mail.to}.txt")    
         
     | 
| 
      
 19 
     | 
    
         
            +
                File.open(file_name, 'w') {|file| file << message_string }
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            class MailMessageObserver
         
     | 
| 
      
 24 
     | 
    
         
            +
              attr_reader :messages
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              def initialize
         
     | 
| 
      
 27 
     | 
    
         
            +
                @messages = []
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
              
         
     | 
| 
      
 30 
     | 
    
         
            +
              def update(message_string)
         
     | 
| 
      
 31 
     | 
    
         
            +
                @messages << TMail::Mail.parse(message_string)
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
              
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            class SystemTime
         
     | 
| 
      
 37 
     | 
    
         
            +
              def current_time_in_seconds
         
     | 
| 
      
 38 
     | 
    
         
            +
                Time.now.to_i
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/rumbster.rb
    ADDED
    
    | 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'gserver'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'smtp_protocol'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            class Rumbster < GServer
         
     | 
| 
      
 5 
     | 
    
         
            +
              
         
     | 
| 
      
 6 
     | 
    
         
            +
              def initialize(port=25, *args)
         
     | 
| 
      
 7 
     | 
    
         
            +
                super(port, *args)
         
     | 
| 
      
 8 
     | 
    
         
            +
                
         
     | 
| 
      
 9 
     | 
    
         
            +
                @observers = []
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
              
         
     | 
| 
      
 12 
     | 
    
         
            +
              def serve(io)
         
     | 
| 
      
 13 
     | 
    
         
            +
                protocol = SmtpProtocol.create
         
     | 
| 
      
 14 
     | 
    
         
            +
                @observers.each do |observer|
         
     | 
| 
      
 15 
     | 
    
         
            +
                  protocol.add_observer(observer)
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
                protocol.serve(io)
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
              
         
     | 
| 
      
 20 
     | 
    
         
            +
              def add_observer(observer)
         
     | 
| 
      
 21 
     | 
    
         
            +
                @observers.push(observer)
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
              
         
     | 
| 
      
 24 
     | 
    
         
            +
             end
         
     | 
| 
         @@ -0,0 +1,42 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'observer'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'smtp_states'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            class SmtpProtocol
         
     | 
| 
      
 5 
     | 
    
         
            +
              include Observable
         
     | 
| 
      
 6 
     | 
    
         
            +
              
         
     | 
| 
      
 7 
     | 
    
         
            +
              def SmtpProtocol.create
         
     | 
| 
      
 8 
     | 
    
         
            +
                initial_state = :init
         
     | 
| 
      
 9 
     | 
    
         
            +
                
         
     | 
| 
      
 10 
     | 
    
         
            +
                states = {
         
     | 
| 
      
 11 
     | 
    
         
            +
                  :init => InitState.new, 
         
     | 
| 
      
 12 
     | 
    
         
            +
                  :connect => ConnectState.new, 
         
     | 
| 
      
 13 
     | 
    
         
            +
                  :connected => ConnectedState.new, 
         
     | 
| 
      
 14 
     | 
    
         
            +
                  :read_mail => ReadMailState.new, 
         
     | 
| 
      
 15 
     | 
    
         
            +
                  :quit => QuitState.new 
         
     | 
| 
      
 16 
     | 
    
         
            +
                }
         
     | 
| 
      
 17 
     | 
    
         
            +
                
         
     | 
| 
      
 18 
     | 
    
         
            +
                SmtpProtocol.new(initial_state, states)
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              def initialize(initial_state, states)
         
     | 
| 
      
 22 
     | 
    
         
            +
                states.each_value { |state| state.protocol = self }
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                @states = states
         
     | 
| 
      
 25 
     | 
    
         
            +
                @state = @states[initial_state]
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
              
         
     | 
| 
      
 28 
     | 
    
         
            +
              def state=(new_state)
         
     | 
| 
      
 29 
     | 
    
         
            +
                @state = @states[new_state]
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
              
         
     | 
| 
      
 32 
     | 
    
         
            +
              def serve(io)
         
     | 
| 
      
 33 
     | 
    
         
            +
                @state.serve(io)
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
              
         
     | 
| 
      
 36 
     | 
    
         
            +
              def new_message_received(message)
         
     | 
| 
      
 37 
     | 
    
         
            +
                changed
         
     | 
| 
      
 38 
     | 
    
         
            +
                notify_observers(message)
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
              
         
     | 
| 
      
 41 
     | 
    
         
            +
            end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
    
        data/lib/smtp_states.rb
    ADDED
    
    | 
         @@ -0,0 +1,159 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class NotInitializedError < RuntimeError; end
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module State
         
     | 
| 
      
 4 
     | 
    
         
            +
              attr_accessor :protocol
         
     | 
| 
      
 5 
     | 
    
         
            +
              
         
     | 
| 
      
 6 
     | 
    
         
            +
              def serve(io)
         
     | 
| 
      
 7 
     | 
    
         
            +
                raise NotInitializedError.new if @protocol.nil?
         
     | 
| 
      
 8 
     | 
    
         
            +
                
         
     | 
| 
      
 9 
     | 
    
         
            +
                service_request(io)
         
     | 
| 
      
 10 
     | 
    
         
            +
                @protocol.state = @next_state
         
     | 
| 
      
 11 
     | 
    
         
            +
                @protocol.serve(io)
         
     | 
| 
      
 12 
     | 
    
         
            +
              end  
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            module Messages
         
     | 
| 
      
 16 
     | 
    
         
            +
              
         
     | 
| 
      
 17 
     | 
    
         
            +
              def greeting(io)
         
     | 
| 
      
 18 
     | 
    
         
            +
                io.puts '220 ruby ESMTP'
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
              
         
     | 
| 
      
 21 
     | 
    
         
            +
              def helo_response(io)
         
     | 
| 
      
 22 
     | 
    
         
            +
                io.puts '250 ruby'
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
              
         
     | 
| 
      
 25 
     | 
    
         
            +
              def ok(io)
         
     | 
| 
      
 26 
     | 
    
         
            +
                io.puts '250 ok'
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
              
         
     | 
| 
      
 29 
     | 
    
         
            +
              def go_ahead(io)
         
     | 
| 
      
 30 
     | 
    
         
            +
                io.puts '354 go ahead'
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
              
         
     | 
| 
      
 33 
     | 
    
         
            +
              def goodbye(io)
         
     | 
| 
      
 34 
     | 
    
         
            +
                io.puts '221 ruby goodbye'
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
              
         
     | 
| 
      
 37 
     | 
    
         
            +
            end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            class InitState
         
     | 
| 
      
 40 
     | 
    
         
            +
              
         
     | 
| 
      
 41 
     | 
    
         
            +
              include State, Messages
         
     | 
| 
      
 42 
     | 
    
         
            +
              
         
     | 
| 
      
 43 
     | 
    
         
            +
              def initialize(protocol = nil, next_state = :connect)
         
     | 
| 
      
 44 
     | 
    
         
            +
                @protocol = protocol
         
     | 
| 
      
 45 
     | 
    
         
            +
                @next_state = next_state
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
              
         
     | 
| 
      
 48 
     | 
    
         
            +
              private
         
     | 
| 
      
 49 
     | 
    
         
            +
                
         
     | 
| 
      
 50 
     | 
    
         
            +
              def service_request(io)
         
     | 
| 
      
 51 
     | 
    
         
            +
                greeting(io)
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
              
         
     | 
| 
      
 54 
     | 
    
         
            +
            end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            class ConnectState
         
     | 
| 
      
 57 
     | 
    
         
            +
              
         
     | 
| 
      
 58 
     | 
    
         
            +
              include State, Messages
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
              def initialize(protocol = nil, next_state = :connected)
         
     | 
| 
      
 61 
     | 
    
         
            +
                @protocol = protocol
         
     | 
| 
      
 62 
     | 
    
         
            +
                @next_state = next_state
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
                
         
     | 
| 
      
 65 
     | 
    
         
            +
              private
         
     | 
| 
      
 66 
     | 
    
         
            +
              
         
     | 
| 
      
 67 
     | 
    
         
            +
              def service_request(io)
         
     | 
| 
      
 68 
     | 
    
         
            +
                read_client_helo(io)
         
     | 
| 
      
 69 
     | 
    
         
            +
                helo_response(io)
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
              
         
     | 
| 
      
 72 
     | 
    
         
            +
              def read_client_helo(io)
         
     | 
| 
      
 73 
     | 
    
         
            +
                io.readline
         
     | 
| 
      
 74 
     | 
    
         
            +
              end
         
     | 
| 
      
 75 
     | 
    
         
            +
              
         
     | 
| 
      
 76 
     | 
    
         
            +
            end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
            class ConnectedState
         
     | 
| 
      
 79 
     | 
    
         
            +
              
         
     | 
| 
      
 80 
     | 
    
         
            +
              include State, Messages
         
     | 
| 
      
 81 
     | 
    
         
            +
              
         
     | 
| 
      
 82 
     | 
    
         
            +
              def initialize(protocol = nil)
         
     | 
| 
      
 83 
     | 
    
         
            +
                @protocol = protocol
         
     | 
| 
      
 84 
     | 
    
         
            +
                @next_state = :connected
         
     | 
| 
      
 85 
     | 
    
         
            +
              end
         
     | 
| 
      
 86 
     | 
    
         
            +
              
         
     | 
| 
      
 87 
     | 
    
         
            +
              private
         
     | 
| 
      
 88 
     | 
    
         
            +
              
         
     | 
| 
      
 89 
     | 
    
         
            +
              def service_request(io)
         
     | 
| 
      
 90 
     | 
    
         
            +
                request = io.readline
         
     | 
| 
      
 91 
     | 
    
         
            +
                
         
     | 
| 
      
 92 
     | 
    
         
            +
                if request.strip.eql? "DATA"
         
     | 
| 
      
 93 
     | 
    
         
            +
                  @next_state = :read_mail
         
     | 
| 
      
 94 
     | 
    
         
            +
                  go_ahead(io)
         
     | 
| 
      
 95 
     | 
    
         
            +
                else
         
     | 
| 
      
 96 
     | 
    
         
            +
                  ok(io)
         
     | 
| 
      
 97 
     | 
    
         
            +
                end
         
     | 
| 
      
 98 
     | 
    
         
            +
              end
         
     | 
| 
      
 99 
     | 
    
         
            +
              
         
     | 
| 
      
 100 
     | 
    
         
            +
            end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
            class ReadMailState
         
     | 
| 
      
 103 
     | 
    
         
            +
              
         
     | 
| 
      
 104 
     | 
    
         
            +
              include State, Messages
         
     | 
| 
      
 105 
     | 
    
         
            +
              
         
     | 
| 
      
 106 
     | 
    
         
            +
              def initialize(protocol = nil)
         
     | 
| 
      
 107 
     | 
    
         
            +
                @protocol = protocol
         
     | 
| 
      
 108 
     | 
    
         
            +
                @next_state = :quit
         
     | 
| 
      
 109 
     | 
    
         
            +
              end
         
     | 
| 
      
 110 
     | 
    
         
            +
              
         
     | 
| 
      
 111 
     | 
    
         
            +
              private
         
     | 
| 
      
 112 
     | 
    
         
            +
              
         
     | 
| 
      
 113 
     | 
    
         
            +
              def service_request(io)
         
     | 
| 
      
 114 
     | 
    
         
            +
                message = read_message(io)
         
     | 
| 
      
 115 
     | 
    
         
            +
                @protocol.new_message_received(message)
         
     | 
| 
      
 116 
     | 
    
         
            +
                ok(io)
         
     | 
| 
      
 117 
     | 
    
         
            +
              end
         
     | 
| 
      
 118 
     | 
    
         
            +
              
         
     | 
| 
      
 119 
     | 
    
         
            +
              def not_end_of_message(line)
         
     | 
| 
      
 120 
     | 
    
         
            +
                not line.strip.eql?('.')
         
     | 
| 
      
 121 
     | 
    
         
            +
              end
         
     | 
| 
      
 122 
     | 
    
         
            +
              
         
     | 
| 
      
 123 
     | 
    
         
            +
              def read_message(io)
         
     | 
| 
      
 124 
     | 
    
         
            +
                message = ''
         
     | 
| 
      
 125 
     | 
    
         
            +
                
         
     | 
| 
      
 126 
     | 
    
         
            +
                line = io.readline
         
     | 
| 
      
 127 
     | 
    
         
            +
                while not_end_of_message(line)
         
     | 
| 
      
 128 
     | 
    
         
            +
                  message << line
         
     | 
| 
      
 129 
     | 
    
         
            +
                  line = io.readline
         
     | 
| 
      
 130 
     | 
    
         
            +
                end
         
     | 
| 
      
 131 
     | 
    
         
            +
                
         
     | 
| 
      
 132 
     | 
    
         
            +
                message
         
     | 
| 
      
 133 
     | 
    
         
            +
              end
         
     | 
| 
      
 134 
     | 
    
         
            +
              
         
     | 
| 
      
 135 
     | 
    
         
            +
            end
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
            class QuitState
         
     | 
| 
      
 138 
     | 
    
         
            +
              
         
     | 
| 
      
 139 
     | 
    
         
            +
              include Messages
         
     | 
| 
      
 140 
     | 
    
         
            +
              attr_accessor :protocol
         
     | 
| 
      
 141 
     | 
    
         
            +
              
         
     | 
| 
      
 142 
     | 
    
         
            +
              def initialize(protocol = nil)
         
     | 
| 
      
 143 
     | 
    
         
            +
                @protocol = protocol
         
     | 
| 
      
 144 
     | 
    
         
            +
              end
         
     | 
| 
      
 145 
     | 
    
         
            +
              
         
     | 
| 
      
 146 
     | 
    
         
            +
              def serve(io)
         
     | 
| 
      
 147 
     | 
    
         
            +
                raise NotInitializedError.new if @protocol.nil?
         
     | 
| 
      
 148 
     | 
    
         
            +
                
         
     | 
| 
      
 149 
     | 
    
         
            +
                read_quit(io)
         
     | 
| 
      
 150 
     | 
    
         
            +
                goodbye(io)
         
     | 
| 
      
 151 
     | 
    
         
            +
              end
         
     | 
| 
      
 152 
     | 
    
         
            +
              
         
     | 
| 
      
 153 
     | 
    
         
            +
              private
         
     | 
| 
      
 154 
     | 
    
         
            +
              
         
     | 
| 
      
 155 
     | 
    
         
            +
              def read_quit(io)
         
     | 
| 
      
 156 
     | 
    
         
            +
                io.readline    
         
     | 
| 
      
 157 
     | 
    
         
            +
              end
         
     | 
| 
      
 158 
     | 
    
         
            +
              
         
     | 
| 
      
 159 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,102 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'fileutils'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'message_observers'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            class MessageObserversTest < Test::Unit::TestCase
         
     | 
| 
      
 8 
     | 
    
         
            +
              
         
     | 
| 
      
 9 
     | 
    
         
            +
              include FileUtils
         
     | 
| 
      
 10 
     | 
    
         
            +
              
         
     | 
| 
      
 11 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 12 
     | 
    
         
            +
                @directory = File.join(File.dirname(__FILE__), '..', 'messages')
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
              
         
     | 
| 
      
 15 
     | 
    
         
            +
              def teardown
         
     | 
| 
      
 16 
     | 
    
         
            +
                rm_r(@directory) if File.exists?(@directory)
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
              
         
     | 
| 
      
 19 
     | 
    
         
            +
              def test_directory_is_created_when_directory_is_not_present
         
     | 
| 
      
 20 
     | 
    
         
            +
                file_observer = FileMessageObserver.new(@directory)
         
     | 
| 
      
 21 
     | 
    
         
            +
                
         
     | 
| 
      
 22 
     | 
    
         
            +
                assert File.exists?(@directory)
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
              
         
     | 
| 
      
 25 
     | 
    
         
            +
              def test_if_directory_is_already_present_observer_can_still_be_created
         
     | 
| 
      
 26 
     | 
    
         
            +
                mkdir_p(@directory)
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                assert File.exists?(@directory)
         
     | 
| 
      
 29 
     | 
    
         
            +
                assert_not_nil FileMessageObserver.new(@directory)
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
              
         
     | 
| 
      
 32 
     | 
    
         
            +
              def test_message_received_is_saved_to_message_directory
         
     | 
| 
      
 33 
     | 
    
         
            +
                file_observer = FileMessageObserver.new(@directory)
         
     | 
| 
      
 34 
     | 
    
         
            +
                file_observer.update "To: junk@junk.com\nFrom: junk2@junk2.com\nSubject: What's up\n\nHi"
         
     | 
| 
      
 35 
     | 
    
         
            +
                
         
     | 
| 
      
 36 
     | 
    
         
            +
                assert_one_new_file_added_to @directory
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
              
         
     | 
| 
      
 39 
     | 
    
         
            +
              def test_message_is_saved_in_a_file_named_time_stamp_underscore_to_dot_txt
         
     | 
| 
      
 40 
     | 
    
         
            +
                file_observer = FileMessageObserver.new(@directory, TestSystemTime.new(1))
         
     | 
| 
      
 41 
     | 
    
         
            +
                file_observer.update "To: junk@junk.com\nFrom: junk2@junk2.com\nSubject: What's up\n\nHi"
         
     | 
| 
      
 42 
     | 
    
         
            +
                
         
     | 
| 
      
 43 
     | 
    
         
            +
                expected_file_name = File.join(@directory, "1_junk@junk.com.txt")
         
     | 
| 
      
 44 
     | 
    
         
            +
                
         
     | 
| 
      
 45 
     | 
    
         
            +
                assert File.exists?(expected_file_name)
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
              
         
     | 
| 
      
 48 
     | 
    
         
            +
              def test_message_contents_are_saved_to_the_file
         
     | 
| 
      
 49 
     | 
    
         
            +
                message = "To: junk@junk.com\nFrom: junk2@junk2.com\nSubject: What's up\n\nHi"
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                file_observer = FileMessageObserver.new(@directory, TestSystemTime.new(1))
         
     | 
| 
      
 52 
     | 
    
         
            +
                file_observer.update message
         
     | 
| 
      
 53 
     | 
    
         
            +
                
         
     | 
| 
      
 54 
     | 
    
         
            +
                expected_file_name = File.join(@directory, "1_junk@junk.com.txt")
         
     | 
| 
      
 55 
     | 
    
         
            +
                
         
     | 
| 
      
 56 
     | 
    
         
            +
                assert_equal read_file_contents_into_a_string(expected_file_name), message
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
              
         
     | 
| 
      
 59 
     | 
    
         
            +
              def test_messages_are_saved_for_later_inspection
         
     | 
| 
      
 60 
     | 
    
         
            +
                message = "To: junk@junk.com\nFrom: junk2@junk2.com\nSubject: What's up\n\nHi"
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                mail_observer = MailMessageObserver.new
         
     | 
| 
      
 63 
     | 
    
         
            +
                mail_observer.update message
         
     | 
| 
      
 64 
     | 
    
         
            +
                mail_observer.update message
         
     | 
| 
      
 65 
     | 
    
         
            +
                
         
     | 
| 
      
 66 
     | 
    
         
            +
                assert_equal 2, mail_observer.messages.size
         
     | 
| 
      
 67 
     | 
    
         
            +
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
              
         
     | 
| 
      
 69 
     | 
    
         
            +
              def test_message_is_converted_to_tmail
         
     | 
| 
      
 70 
     | 
    
         
            +
                message = "To: junk@junk.com\nFrom: junk2@junk2.com\nSubject: What's up\n\nHi"
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                mail_observer = MailMessageObserver.new
         
     | 
| 
      
 73 
     | 
    
         
            +
                mail_observer.update message
         
     | 
| 
      
 74 
     | 
    
         
            +
                
         
     | 
| 
      
 75 
     | 
    
         
            +
                assert_equal 'What\'s up', mail_observer.messages.first.subject
         
     | 
| 
      
 76 
     | 
    
         
            +
              end
         
     | 
| 
      
 77 
     | 
    
         
            +
              
         
     | 
| 
      
 78 
     | 
    
         
            +
              private
         
     | 
| 
      
 79 
     | 
    
         
            +
              
         
     | 
| 
      
 80 
     | 
    
         
            +
              def read_file_contents_into_a_string(file_name)
         
     | 
| 
      
 81 
     | 
    
         
            +
                File.open(file_name) {|file| file.readlines.join }
         
     | 
| 
      
 82 
     | 
    
         
            +
              end
         
     | 
| 
      
 83 
     | 
    
         
            +
              
         
     | 
| 
      
 84 
     | 
    
         
            +
              
         
     | 
| 
      
 85 
     | 
    
         
            +
              def assert_one_new_file_added_to(directory)
         
     | 
| 
      
 86 
     | 
    
         
            +
                number_of_dot_and_dot_dot_entries_in_a_directory_when_it_is_first_created = 2
         
     | 
| 
      
 87 
     | 
    
         
            +
                number_of_entries_with_one_file = number_of_dot_and_dot_dot_entries_in_a_directory_when_it_is_first_created + 1
         
     | 
| 
      
 88 
     | 
    
         
            +
                
         
     | 
| 
      
 89 
     | 
    
         
            +
                assert_equal number_of_entries_with_one_file, Dir.entries(@directory).size
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
            end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
            class TestSystemTime
         
     | 
| 
      
 94 
     | 
    
         
            +
              def initialize(time)
         
     | 
| 
      
 95 
     | 
    
         
            +
                @time = time
         
     | 
| 
      
 96 
     | 
    
         
            +
              end
         
     | 
| 
      
 97 
     | 
    
         
            +
              
         
     | 
| 
      
 98 
     | 
    
         
            +
              def current_time_in_seconds
         
     | 
| 
      
 99 
     | 
    
         
            +
                @time
         
     | 
| 
      
 100 
     | 
    
         
            +
              end
         
     | 
| 
      
 101 
     | 
    
         
            +
              
         
     | 
| 
      
 102 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,69 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'rumbster'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'net/smtp'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'gserver'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            class RumbsterTest < Test::Unit::TestCase
         
     | 
| 
      
 10 
     | 
    
         
            +
              
         
     | 
| 
      
 11 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 12 
     | 
    
         
            +
                @observer = RumbsterObserver.new
         
     | 
| 
      
 13 
     | 
    
         
            +
                @server = Rumbster.new(10025)
         
     | 
| 
      
 14 
     | 
    
         
            +
                @server.add_observer(@observer)
         
     | 
| 
      
 15 
     | 
    
         
            +
                
         
     | 
| 
      
 16 
     | 
    
         
            +
                @server.start
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
              
         
     | 
| 
      
 19 
     | 
    
         
            +
              def teardown
         
     | 
| 
      
 20 
     | 
    
         
            +
                @server.stop
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
              
         
     | 
| 
      
 23 
     | 
    
         
            +
              def test_single_receiver_message_sent_by_client_is_received_by_listener
         
     | 
| 
      
 24 
     | 
    
         
            +
                message = "From: <junk@junkster.com>\r\nTo: junk@junk.com\r\nSubject: hi\r\n\r\nThis is a test\r\n"
         
     | 
| 
      
 25 
     | 
    
         
            +
                to = 'his_address@example.com'
         
     | 
| 
      
 26 
     | 
    
         
            +
                send_message to, message 
         
     | 
| 
      
 27 
     | 
    
         
            +
                    
         
     | 
| 
      
 28 
     | 
    
         
            +
                assert_equal message, @observer.message
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
              
         
     | 
| 
      
 31 
     | 
    
         
            +
              def test_multiple_receiver_message_sent_by_client_is_received_by_listener
         
     | 
| 
      
 32 
     | 
    
         
            +
                message = "From: <junk@junkster.com>\r\nTo: junk@junk.com\r\nSubject: hi\r\n\r\nThis is a test\r\n"
         
     | 
| 
      
 33 
     | 
    
         
            +
                to = ['his_address@example.com', 'her_address@example.com']
         
     | 
| 
      
 34 
     | 
    
         
            +
                send_message to, message 
         
     | 
| 
      
 35 
     | 
    
         
            +
                    
         
     | 
| 
      
 36 
     | 
    
         
            +
                assert_equal message, @observer.message
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              def test_multiple_receiver_messages_sent_by_client_are_received_by_listener
         
     | 
| 
      
 40 
     | 
    
         
            +
                message_1 = "From: <junk_1@junkster.com>\r\nTo: junk_1@junk.com\r\nSubject: hi\r\n\r\nThis is a test_1\r\n"
         
     | 
| 
      
 41 
     | 
    
         
            +
                to_1 = ['his_address_1@example.com', 'her_address_1@example.com']
         
     | 
| 
      
 42 
     | 
    
         
            +
                send_message to_1, message_1 
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                assert_equal message_1, @observer.message
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                message_2 = "From: <junk_2@junkster.com>\r\nTo: junk_2@junk.com\r\nSubject: hi\r\n\r\nThis is a test_2\r\n"
         
     | 
| 
      
 47 
     | 
    
         
            +
                to_2 = ['his_address_2@example.com', 'her_address_2@example.com']
         
     | 
| 
      
 48 
     | 
    
         
            +
                send_message to_2, message_2 
         
     | 
| 
      
 49 
     | 
    
         
            +
                    
         
     | 
| 
      
 50 
     | 
    
         
            +
                assert_equal message_2, @observer.message
         
     | 
| 
      
 51 
     | 
    
         
            +
              end
         
     | 
| 
      
 52 
     | 
    
         
            +
              
         
     | 
| 
      
 53 
     | 
    
         
            +
              private
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
              def send_message(to, message)
         
     | 
| 
      
 56 
     | 
    
         
            +
                Net::SMTP.start('localhost', 10025) do |smtp|
         
     | 
| 
      
 57 
     | 
    
         
            +
                  smtp.send_message message, 'your@mail.address', to
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
              end
         
     | 
| 
      
 60 
     | 
    
         
            +
              
         
     | 
| 
      
 61 
     | 
    
         
            +
            end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            class RumbsterObserver
         
     | 
| 
      
 64 
     | 
    
         
            +
              attr_accessor :message
         
     | 
| 
      
 65 
     | 
    
         
            +
              
         
     | 
| 
      
 66 
     | 
    
         
            +
              def update(message)
         
     | 
| 
      
 67 
     | 
    
         
            +
                @message = message
         
     | 
| 
      
 68 
     | 
    
         
            +
              end
         
     | 
| 
      
 69 
     | 
    
         
            +
            end
         
     |