rpush 2.2.0-java → 2.3.0-java
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.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +10 -0
 - data/README.md +17 -9
 - data/lib/generators/rpush_migration_generator.rb +1 -1
 - data/lib/rpush.rb +4 -1
 - data/lib/rpush/apns_feedback.rb +1 -1
 - data/lib/rpush/cli.rb +24 -21
 - data/lib/rpush/client/active_model/apns/app.rb +1 -1
 - data/lib/rpush/client/active_model/apns/notification.rb +2 -2
 - data/lib/rpush/client/active_model/wpns/notification.rb +7 -1
 - data/lib/rpush/configuration.rb +32 -22
 - data/lib/rpush/daemon.rb +18 -9
 - data/lib/rpush/daemon/adm/delivery.rb +4 -1
 - data/lib/rpush/daemon/apns/delivery.rb +3 -0
 - data/lib/rpush/daemon/apns/feedback_receiver.rb +6 -2
 - data/lib/rpush/daemon/app_runner.rb +11 -16
 - data/lib/rpush/daemon/batch.rb +9 -0
 - data/lib/rpush/daemon/delivery.rb +10 -2
 - data/lib/rpush/daemon/delivery_error.rb +3 -3
 - data/lib/rpush/daemon/dispatcher/apns_tcp.rb +11 -11
 - data/lib/rpush/daemon/dispatcher/tcp.rb +2 -10
 - data/lib/rpush/daemon/gcm/delivery.rb +13 -7
 - data/lib/rpush/daemon/signal_handler.rb +5 -3
 - data/lib/rpush/daemon/store/active_record.rb +14 -0
 - data/lib/rpush/daemon/store/interface.rb +2 -1
 - data/lib/rpush/daemon/store/redis.rb +3 -0
 - data/lib/rpush/daemon/tcp_connection.rb +47 -17
 - data/lib/rpush/daemon/wpns/delivery.rb +19 -10
 - data/lib/rpush/logger.rb +30 -12
 - data/lib/rpush/plugin.rb +44 -0
 - data/lib/rpush/push.rb +1 -1
 - data/lib/rpush/reflectable.rb +13 -0
 - data/lib/rpush/{reflection.rb → reflection_collection.rb} +1 -9
 - data/lib/rpush/reflection_public_methods.rb +9 -0
 - data/lib/rpush/version.rb +1 -1
 - data/lib/tasks/test.rake +6 -4
 - data/spec/functional/adm_spec.rb +12 -0
 - data/spec/functional/apns_spec.rb +61 -42
 - data/spec/functional/gcm_spec.rb +9 -0
 - data/spec/functional/retry_spec.rb +1 -1
 - data/spec/functional/wpns_spec.rb +44 -11
 - data/spec/spec_helper.rb +2 -0
 - data/spec/unit/apns_feedback_spec.rb +2 -2
 - data/spec/unit/client/active_record/apns/app_spec.rb +2 -2
 - data/spec/unit/client/active_record/apns/notification_spec.rb +1 -2
 - data/spec/unit/client/active_record/wpns/notification_spec.rb +9 -3
 - data/spec/unit/configuration_spec.rb +1 -0
 - data/spec/unit/daemon/adm/delivery_spec.rb +0 -1
 - data/spec/unit/daemon/apns/feedback_receiver_spec.rb +0 -1
 - data/spec/unit/daemon/app_runner_spec.rb +14 -9
 - data/spec/unit/daemon/delivery_spec.rb +0 -1
 - data/spec/unit/daemon/dispatcher/tcp_spec.rb +0 -7
 - data/spec/unit/daemon/gcm/delivery_spec.rb +1 -1
 - data/spec/unit/daemon/signal_handler_spec.rb +5 -1
 - data/spec/unit/daemon/store/active_record_spec.rb +1 -1
 - data/spec/unit/daemon/tcp_connection_spec.rb +18 -18
 - data/spec/unit/daemon/wpns/delivery_spec.rb +1 -1
 - data/spec/unit/daemon_spec.rb +10 -2
 - data/spec/unit/logger_spec.rb +0 -1
 - data/spec/unit/plugin_spec.rb +36 -0
 - data/spec/unit/push_spec.rb +2 -2
 - data/spec/unit/{daemon/reflectable_spec.rb → reflectable_spec.rb} +6 -6
 - data/spec/unit/{reflection_spec.rb → reflection_collection_spec.rb} +4 -8
 - metadata +34 -36
 - data/lib/rpush/daemon/reflectable.rb +0 -11
 - data/spec/integration/rpush_spec.rb +0 -13
 - data/spec/integration/support/gcm_success_response.json +0 -1
 - data/spec/support/install.sh +0 -68
 
| 
         @@ -17,6 +17,9 @@ module Rpush 
     | 
|
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
                    def perform
         
     | 
| 
       19 
19 
     | 
    
         
             
                      handle_response(do_post)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    rescue SocketError => error
         
     | 
| 
      
 21 
     | 
    
         
            +
                      mark_retryable(@notification, Time.now + 10.seconds, error)
         
     | 
| 
      
 22 
     | 
    
         
            +
                      raise
         
     | 
| 
       20 
23 
     | 
    
         
             
                    rescue StandardError => error
         
     | 
| 
       21 
24 
     | 
    
         
             
                      mark_failed(error)
         
     | 
| 
       22 
25 
     | 
    
         
             
                      raise
         
     | 
| 
         @@ -77,7 +80,7 @@ module Rpush 
     | 
|
| 
       77 
80 
     | 
    
         
             
                    end
         
     | 
| 
       78 
81 
     | 
    
         | 
| 
       79 
82 
     | 
    
         
             
                    def retry_message
         
     | 
| 
       80 
     | 
    
         
            -
                      "Notification #{@notification.id} will be retried after #{@notification.deliver_after.strftime( 
     | 
| 
      
 83 
     | 
    
         
            +
                      "Notification #{@notification.id} will be retried after #{@notification.deliver_after.strftime('%Y-%m-%d %H:%M:%S')} (retry #{@notification.retries})."
         
     | 
| 
       81 
84 
     | 
    
         
             
                    end
         
     | 
| 
       82 
85 
     | 
    
         | 
| 
       83 
86 
     | 
    
         
             
                    def retry_notification(reason)
         
     | 
| 
         @@ -106,16 +109,22 @@ module Rpush 
     | 
|
| 
       106 
109 
     | 
    
         
             
                    end
         
     | 
| 
       107 
110 
     | 
    
         | 
| 
       108 
111 
     | 
    
         
             
                    def notification_to_xml
         
     | 
| 
       109 
     | 
    
         
            -
                       
     | 
| 
      
 112 
     | 
    
         
            +
                      title = clean_param_string(@notification.data['title']) if @notification.data['title'].present?
         
     | 
| 
      
 113 
     | 
    
         
            +
                      body = clean_param_string(@notification.data['body']) if @notification.data['body'].present?
         
     | 
| 
      
 114 
     | 
    
         
            +
                      param = clean_param_string(@notification.data['param']) if @notification.data['param'].present?
         
     | 
| 
      
 115 
     | 
    
         
            +
                      "<?xml version=\"1.0\" encoding=\"utf-8\"?>
         
     | 
| 
      
 116 
     | 
    
         
            +
                       <wp:Notification xmlns:wp=\"WPNotification\">
         
     | 
| 
      
 117 
     | 
    
         
            +
                         <wp:Toast>
         
     | 
| 
      
 118 
     | 
    
         
            +
                           <wp:Text1>#{title}</wp:Text1>
         
     | 
| 
      
 119 
     | 
    
         
            +
                           <wp:Text2>#{body}</wp:Text2>
         
     | 
| 
      
 120 
     | 
    
         
            +
                           <wp:Param>#{param}</wp:Param>
         
     | 
| 
      
 121 
     | 
    
         
            +
                         </wp:Toast>
         
     | 
| 
      
 122 
     | 
    
         
            +
                       </wp:Notification>"
         
     | 
| 
      
 123 
     | 
    
         
            +
                    end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                    def clean_param_string(string)
         
     | 
| 
      
 126 
     | 
    
         
            +
                      string.gsub(/&/, "&").gsub(/</, "<") \
         
     | 
| 
       110 
127 
     | 
    
         
             
                        .gsub(/>/, ">").gsub(/'/, "'").gsub(/"/, """)
         
     | 
| 
       111 
     | 
    
         
            -
                      <<-EOF
         
     | 
| 
       112 
     | 
    
         
            -
            <?xml version="1.0" encoding="utf-8"?>
         
     | 
| 
       113 
     | 
    
         
            -
            <wp:Notification xmlns:wp="WPNotification">
         
     | 
| 
       114 
     | 
    
         
            -
              <wp:Toast>
         
     | 
| 
       115 
     | 
    
         
            -
                <wp:Text1>#{msg}</wp:Text1>
         
     | 
| 
       116 
     | 
    
         
            -
              </wp:Toast>
         
     | 
| 
       117 
     | 
    
         
            -
            </wp:Notification>
         
     | 
| 
       118 
     | 
    
         
            -
                      EOF
         
     | 
| 
       119 
128 
     | 
    
         
             
                    end
         
     | 
| 
       120 
129 
     | 
    
         
             
                  end
         
     | 
| 
       121 
130 
     | 
    
         
             
                end
         
     | 
    
        data/lib/rpush/logger.rb
    CHANGED
    
    | 
         @@ -1,12 +1,15 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Rpush
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Logger
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_reader :internal_logger
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
       3 
5 
     | 
    
         
             
                def initialize
         
     | 
| 
       4 
     | 
    
         
            -
                   
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
                   
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
      
 6 
     | 
    
         
            +
                  if Rpush.config.logger
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @internal_logger = Rpush.config.logger
         
     | 
| 
      
 8 
     | 
    
         
            +
                  else
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @internal_logger = setup_logger(open_logfile)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
       8 
11 
     | 
    
         
             
                rescue Errno::ENOENT, Errno::EPERM => e
         
     | 
| 
       9 
     | 
    
         
            -
                  @ 
     | 
| 
      
 12 
     | 
    
         
            +
                  @internal_logger = nil
         
     | 
| 
       10 
13 
     | 
    
         
             
                  error(e)
         
     | 
| 
       11 
14 
     | 
    
         
             
                  error('Logging disabled.')
         
     | 
| 
       12 
15 
     | 
    
         
             
                end
         
     | 
| 
         @@ -23,16 +26,31 @@ module Rpush 
     | 
|
| 
       23 
26 
     | 
    
         
             
                  log(:warn, msg, inline, 'WARNING', STDERR)
         
     | 
| 
       24 
27 
     | 
    
         
             
                end
         
     | 
| 
       25 
28 
     | 
    
         | 
| 
      
 29 
     | 
    
         
            +
                def reopen
         
     | 
| 
      
 30 
     | 
    
         
            +
                  if Rpush.config.logger
         
     | 
| 
      
 31 
     | 
    
         
            +
                    Rpush.config.logger.reopen if Rpush.config.logger.respond_to?(:reopen)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  else
         
     | 
| 
      
 33 
     | 
    
         
            +
                    @internal_logger.close
         
     | 
| 
      
 34 
     | 
    
         
            +
                    @internal_logger = setup_logger(open_logfile)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
       26 
38 
     | 
    
         
             
                private
         
     | 
| 
       27 
39 
     | 
    
         | 
| 
      
 40 
     | 
    
         
            +
                def open_logfile
         
     | 
| 
      
 41 
     | 
    
         
            +
                  FileUtils.mkdir_p(File.dirname(Rpush.config.log_file))
         
     | 
| 
      
 42 
     | 
    
         
            +
                  log = File.open(Rpush.config.log_file, 'a')
         
     | 
| 
      
 43 
     | 
    
         
            +
                  log.sync = true
         
     | 
| 
      
 44 
     | 
    
         
            +
                  log
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
       28 
47 
     | 
    
         
             
                def setup_logger(log)
         
     | 
| 
       29 
     | 
    
         
            -
                  if  
     | 
| 
       30 
     | 
    
         
            -
                     
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                     
     | 
| 
       33 
     | 
    
         
            -
                    @logger.auto_flushing = auto_flushing
         
     | 
| 
      
 48 
     | 
    
         
            +
                  if ActiveSupport.const_defined?('BufferedLogger')
         
     | 
| 
      
 49 
     | 
    
         
            +
                    logger = ActiveSupport::BufferedLogger.new(log, Rpush.config.log_level)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    logger.auto_flushing = auto_flushing
         
     | 
| 
      
 51 
     | 
    
         
            +
                    logger
         
     | 
| 
       34 
52 
     | 
    
         
             
                  else
         
     | 
| 
       35 
     | 
    
         
            -
                     
     | 
| 
      
 53 
     | 
    
         
            +
                    ActiveSupport::Logger.new(log, Rpush.config.log_level)
         
     | 
| 
       36 
54 
     | 
    
         
             
                  end
         
     | 
| 
       37 
55 
     | 
    
         
             
                end
         
     | 
| 
       38 
56 
     | 
    
         | 
| 
         @@ -55,7 +73,7 @@ module Rpush 
     | 
|
| 
       55 
73 
     | 
    
         
             
                  formatted_msg << msg
         
     | 
| 
       56 
74 
     | 
    
         | 
| 
       57 
75 
     | 
    
         
             
                  log_foreground(io, formatted_msg, inline)
         
     | 
| 
       58 
     | 
    
         
            -
                  @ 
     | 
| 
      
 76 
     | 
    
         
            +
                  @internal_logger.send(where, formatted_msg) if @internal_logger
         
     | 
| 
       59 
77 
     | 
    
         
             
                end
         
     | 
| 
       60 
78 
     | 
    
         | 
| 
       61 
79 
     | 
    
         
             
                def log_foreground(io, formatted_msg, inline)
         
     | 
    
        data/lib/rpush/plugin.rb
    ADDED
    
    | 
         @@ -0,0 +1,44 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Rpush
         
     | 
| 
      
 2 
     | 
    
         
            +
              def self.plugin(name)
         
     | 
| 
      
 3 
     | 
    
         
            +
                plugins[name] ||= Rpush::Plugin.new(name)
         
     | 
| 
      
 4 
     | 
    
         
            +
                plugins[name]
         
     | 
| 
      
 5 
     | 
    
         
            +
              end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              def self.plugins
         
     | 
| 
      
 8 
     | 
    
         
            +
                @plugins ||= {}
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              class Plugin
         
     | 
| 
      
 12 
     | 
    
         
            +
                attr_reader :name, :config, :init_block
         
     | 
| 
      
 13 
     | 
    
         
            +
                attr_accessor :url, :description
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def initialize(name)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @name = name
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @url = nil
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @description = nil
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @config = OpenStruct.new
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @reflection_collection = Rpush::ReflectionCollection.new
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @init_block = -> {}
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                def reflect
         
     | 
| 
      
 25 
     | 
    
         
            +
                  yield(@reflection_collection)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  return if Rpush.reflection_stack.include?(@reflection_collection)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  Rpush.reflection_stack << @reflection_collection
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def configure
         
     | 
| 
      
 31 
     | 
    
         
            +
                  yield(@config)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  Rpush.config.plugin.send("#{@name}=", @config)
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def init(&block) # rubocop:disable Style/TrivialAccessors
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @init_block = block
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                def unload
         
     | 
| 
      
 40 
     | 
    
         
            +
                  Rpush.reflection_stack.delete(@reflection_collection)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  Rpush.config.plugin.send("#{name}=", nil)
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/rpush/push.rb
    CHANGED
    
    
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Rpush
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Reflectable
         
     | 
| 
      
 3 
     | 
    
         
            +
                def reflect(name, *args)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  Rpush.reflection_stack.each do |reflection_collection|
         
     | 
| 
      
 5 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 6 
     | 
    
         
            +
                      reflection_collection.__dispatch(name, *args)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    rescue StandardError => e
         
     | 
| 
      
 8 
     | 
    
         
            +
                      Rpush.logger.error(e)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    end
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,13 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Rpush
         
     | 
| 
       2 
     | 
    
         
            -
               
     | 
| 
       3 
     | 
    
         
            -
                yield reflections if block_given?
         
     | 
| 
       4 
     | 
    
         
            -
              end
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
              def self.reflections
         
     | 
| 
       7 
     | 
    
         
            -
                @reflections ||= Reflections.new
         
     | 
| 
       8 
     | 
    
         
            -
              end
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
              class Reflections
         
     | 
| 
      
 2 
     | 
    
         
            +
              class ReflectionCollection
         
     | 
| 
       11 
3 
     | 
    
         
             
                class NoSuchReflectionError < StandardError; end
         
     | 
| 
       12 
4 
     | 
    
         | 
| 
       13 
5 
     | 
    
         
             
                REFLECTIONS = [
         
     | 
    
        data/lib/rpush/version.rb
    CHANGED
    
    
    
        data/lib/tasks/test.rake
    CHANGED
    
    | 
         @@ -7,6 +7,7 @@ def cmd(str, clean_env = true) 
     | 
|
| 
       7 
7 
     | 
    
         
             
              retval
         
     | 
| 
       8 
8 
     | 
    
         
             
            end
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
      
 10 
     | 
    
         
            +
            desc 'Build Rails app bundled with Rpush'
         
     | 
| 
       10 
11 
     | 
    
         
             
            task :build_rails do
         
     | 
| 
       11 
12 
     | 
    
         
             
              rpush_root = Dir.pwd
         
     | 
| 
       12 
13 
     | 
    
         
             
              path = '/tmp/rpush/rails_test'
         
     | 
| 
         @@ -27,10 +28,10 @@ task :build_rails do 
     | 
|
| 
       27 
28 
     | 
    
         
             
                File.open('config/database.yml', 'w') do |fd|
         
     | 
| 
       28 
29 
     | 
    
         
             
                  fd.write(<<-YML)
         
     | 
| 
       29 
30 
     | 
    
         
             
            development:
         
     | 
| 
       30 
     | 
    
         
            -
            adapter: postgresql
         
     | 
| 
       31 
     | 
    
         
            -
            database: rpush_rails_test
         
     | 
| 
       32 
     | 
    
         
            -
            pool: 5
         
     | 
| 
       33 
     | 
    
         
            -
            timeout: 5000
         
     | 
| 
      
 31 
     | 
    
         
            +
              adapter: postgresql
         
     | 
| 
      
 32 
     | 
    
         
            +
              database: rpush_rails_test
         
     | 
| 
      
 33 
     | 
    
         
            +
              pool: 5
         
     | 
| 
      
 34 
     | 
    
         
            +
              timeout: 5000
         
     | 
| 
       34 
35 
     | 
    
         
             
                  YML
         
     | 
| 
       35 
36 
     | 
    
         
             
                end
         
     | 
| 
       36 
37 
     | 
    
         
             
              ensure
         
     | 
| 
         @@ -40,6 +41,7 @@ timeout: 5000 
     | 
|
| 
       40 
41 
     | 
    
         
             
              puts "Built into #{path}"
         
     | 
| 
       41 
42 
     | 
    
         
             
            end
         
     | 
| 
       42 
43 
     | 
    
         | 
| 
      
 44 
     | 
    
         
            +
            desc 'Build blank app bundled with Rpush'
         
     | 
| 
       43 
45 
     | 
    
         
             
            task :build_standalone do
         
     | 
| 
       44 
46 
     | 
    
         
             
              rpush_root = Dir.pwd
         
     | 
| 
       45 
47 
     | 
    
         
             
              path = '/tmp/rpush/standalone_test'
         
     | 
    
        data/spec/functional/adm_spec.rb
    CHANGED
    
    | 
         @@ -5,6 +5,9 @@ describe 'ADM' do 
     | 
|
| 
       5 
5 
     | 
    
         
             
              let(:notification) { Rpush::Adm::Notification.new }
         
     | 
| 
       6 
6 
     | 
    
         
             
              let(:response) { double(Net::HTTPResponse, code: 200) }
         
     | 
| 
       7 
7 
     | 
    
         
             
              let(:http) { double(Net::HTTP::Persistent, request: response, shutdown: nil) }
         
     | 
| 
      
 8 
     | 
    
         
            +
              let(:delivered_ids) { [] }
         
     | 
| 
      
 9 
     | 
    
         
            +
              let(:failed_ids) { [] }
         
     | 
| 
      
 10 
     | 
    
         
            +
              let(:retry_ids) { [] }
         
     | 
| 
       8 
11 
     | 
    
         | 
| 
       9 
12 
     | 
    
         
             
              before do
         
     | 
| 
       10 
13 
     | 
    
         
             
                app.name = 'test'
         
     | 
| 
         @@ -37,4 +40,13 @@ describe 'ADM' do 
     | 
|
| 
       37 
40 
     | 
    
         
             
                  notification.reload
         
     | 
| 
       38 
41 
     | 
    
         
             
                end.to_not change(notification, :delivered).to(true)
         
     | 
| 
       39 
42 
     | 
    
         
             
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
              it 'retries notification that fail due to a SocketError' do
         
     | 
| 
      
 45 
     | 
    
         
            +
                expect(http).to receive(:request).and_raise(SocketError.new)
         
     | 
| 
      
 46 
     | 
    
         
            +
                expect(notification.deliver_after).to be_nil
         
     | 
| 
      
 47 
     | 
    
         
            +
                expect do
         
     | 
| 
      
 48 
     | 
    
         
            +
                  Rpush.push
         
     | 
| 
      
 49 
     | 
    
         
            +
                  notification.reload
         
     | 
| 
      
 50 
     | 
    
         
            +
                end.to change(notification, :deliver_after).to(kind_of(Time))
         
     | 
| 
      
 51 
     | 
    
         
            +
              end
         
     | 
| 
       40 
52 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,14 +1,16 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'functional_spec_helper'
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            describe 'APNs' do
         
     | 
| 
       4 
     | 
    
         
            -
              let(:timeout) { 10 }
         
     | 
| 
       5 
4 
     | 
    
         
             
              let(:app) { create_app }
         
     | 
| 
       6 
     | 
    
         
            -
              let!(:notification) { create_notification }
         
     | 
| 
       7 
5 
     | 
    
         
             
              let(:tcp_socket) { double(TCPSocket, setsockopt: nil, close: nil) }
         
     | 
| 
       8 
6 
     | 
    
         
             
              let(:ssl_socket) { double(OpenSSL::SSL::SSLSocket, :sync= => nil, connect: nil, write: nil, flush: nil, read: nil, close: nil) }
         
     | 
| 
       9 
7 
     | 
    
         
             
              let(:io_double) { double(select: nil) }
         
     | 
| 
      
 8 
     | 
    
         
            +
              let(:delivered_ids) { [] }
         
     | 
| 
      
 9 
     | 
    
         
            +
              let(:failed_ids) { [] }
         
     | 
| 
      
 10 
     | 
    
         
            +
              let(:retry_ids) { [] }
         
     | 
| 
       10 
11 
     | 
    
         | 
| 
       11 
12 
     | 
    
         
             
              before do
         
     | 
| 
      
 13 
     | 
    
         
            +
                Rpush.config.push_poll = 0.5
         
     | 
| 
       12 
14 
     | 
    
         
             
                stub_tcp_connection
         
     | 
| 
       13 
15 
     | 
    
         
             
              end
         
     | 
| 
       14 
16 
     | 
    
         | 
| 
         @@ -36,31 +38,20 @@ describe 'APNs' do 
     | 
|
| 
       36 
38 
     | 
    
         
             
                stub_const('Rpush::Daemon::TcpConnection::IO', io_double)
         
     | 
| 
       37 
39 
     | 
    
         
             
              end
         
     | 
| 
       38 
40 
     | 
    
         | 
| 
      
 41 
     | 
    
         
            +
              def wait
         
     | 
| 
      
 42 
     | 
    
         
            +
                sleep 0.1
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
       39 
45 
     | 
    
         
             
              def wait_for_notification_to_deliver(notification)
         
     | 
| 
       40 
     | 
    
         
            -
                 
     | 
| 
       41 
     | 
    
         
            -
                  until notification.delivered
         
     | 
| 
       42 
     | 
    
         
            -
                    sleep 0.1
         
     | 
| 
       43 
     | 
    
         
            -
                    notification.reload
         
     | 
| 
       44 
     | 
    
         
            -
                  end
         
     | 
| 
       45 
     | 
    
         
            -
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
                timeout { wait until delivered_ids.include?(notification.id) }
         
     | 
| 
       46 
47 
     | 
    
         
             
              end
         
     | 
| 
       47 
48 
     | 
    
         | 
| 
       48 
49 
     | 
    
         
             
              def wait_for_notification_to_fail(notification)
         
     | 
| 
       49 
     | 
    
         
            -
                 
     | 
| 
       50 
     | 
    
         
            -
                  while notification.delivered
         
     | 
| 
       51 
     | 
    
         
            -
                    sleep 0.1
         
     | 
| 
       52 
     | 
    
         
            -
                    notification.reload
         
     | 
| 
       53 
     | 
    
         
            -
                  end
         
     | 
| 
       54 
     | 
    
         
            -
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
                timeout { wait until failed_ids.include?(notification.id) }
         
     | 
| 
       55 
51 
     | 
    
         
             
              end
         
     | 
| 
       56 
52 
     | 
    
         | 
| 
       57 
53 
     | 
    
         
             
              def wait_for_notification_to_retry(notification)
         
     | 
| 
       58 
     | 
    
         
            -
                 
     | 
| 
       59 
     | 
    
         
            -
                  until !notification.delivered && !notification.failed && !notification.deliver_after.nil?
         
     | 
| 
       60 
     | 
    
         
            -
                    sleep 0.1
         
     | 
| 
       61 
     | 
    
         
            -
                    notification.reload
         
     | 
| 
       62 
     | 
    
         
            -
                  end
         
     | 
| 
       63 
     | 
    
         
            -
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
                timeout { wait until retry_ids.include?(notification.id) }
         
     | 
| 
       64 
55 
     | 
    
         
             
              end
         
     | 
| 
       65 
56 
     | 
    
         | 
| 
       66 
57 
     | 
    
         
             
              def fail_notification(notification)
         
     | 
| 
         @@ -79,7 +70,12 @@ describe 'APNs' do 
     | 
|
| 
       79 
70 
     | 
    
         
             
                end
         
     | 
| 
       80 
71 
     | 
    
         
             
              end
         
     | 
| 
       81 
72 
     | 
    
         | 
| 
      
 73 
     | 
    
         
            +
              def timeout(&blk)
         
     | 
| 
      
 74 
     | 
    
         
            +
                Timeout.timeout(10, &blk)
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
       82 
77 
     | 
    
         
             
              it 'delivers a notification successfully' do
         
     | 
| 
      
 78 
     | 
    
         
            +
                notification = create_notification
         
     | 
| 
       83 
79 
     | 
    
         
             
                expect do
         
     | 
| 
       84 
80 
     | 
    
         
             
                  Rpush.push
         
     | 
| 
       85 
81 
     | 
    
         
             
                  notification.reload
         
     | 
| 
         @@ -87,6 +83,7 @@ describe 'APNs' do 
     | 
|
| 
       87 
83 
     | 
    
         
             
              end
         
     | 
| 
       88 
84 
     | 
    
         | 
| 
       89 
85 
     | 
    
         
             
              it 'receives feedback' do
         
     | 
| 
      
 86 
     | 
    
         
            +
                app
         
     | 
| 
       90 
87 
     | 
    
         
             
                tuple = "N\xE3\x84\r\x00 \x83OxfU\xEB\x9F\x84aJ\x05\xAD}\x00\xAF1\xE5\xCF\xE9:\xC3\xEA\a\x8F\x1D\xA4M*N\xB0\xCE\x17"
         
     | 
| 
       91 
88 
     | 
    
         
             
                allow(ssl_socket).to receive(:read).and_return(tuple, nil)
         
     | 
| 
       92 
89 
     | 
    
         
             
                Rpush.apns_feedback
         
     | 
| 
         @@ -97,21 +94,57 @@ describe 'APNs' do 
     | 
|
| 
       97 
94 
     | 
    
         
             
              end
         
     | 
| 
       98 
95 
     | 
    
         | 
| 
       99 
96 
     | 
    
         
             
              describe 'delivery failures' do
         
     | 
| 
       100 
     | 
    
         
            -
                before  
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
      
 97 
     | 
    
         
            +
                before do
         
     | 
| 
      
 98 
     | 
    
         
            +
                  Rpush.reflect do |on|
         
     | 
| 
      
 99 
     | 
    
         
            +
                    on.notification_delivered do |n|
         
     | 
| 
      
 100 
     | 
    
         
            +
                      delivered_ids << n.id
         
     | 
| 
      
 101 
     | 
    
         
            +
                    end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                    on.notification_id_failed do |_, n_id|
         
     | 
| 
      
 104 
     | 
    
         
            +
                      failed_ids << n_id
         
     | 
| 
      
 105 
     | 
    
         
            +
                    end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                    on.notification_id_will_retry do |_, n_id|
         
     | 
| 
      
 108 
     | 
    
         
            +
                      retry_ids << n_id
         
     | 
| 
      
 109 
     | 
    
         
            +
                    end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                    on.notification_will_retry do |n|
         
     | 
| 
      
 112 
     | 
    
         
            +
                      retry_ids << n.id
         
     | 
| 
      
 113 
     | 
    
         
            +
                    end
         
     | 
| 
      
 114 
     | 
    
         
            +
                  end
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                  Rpush.embed
         
     | 
| 
      
 117 
     | 
    
         
            +
                end
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                after do
         
     | 
| 
      
 120 
     | 
    
         
            +
                  Rpush.reflection_stack.clear
         
     | 
| 
      
 121 
     | 
    
         
            +
                  Rpush.reflection_stack.push(Rpush::ReflectionCollection.new)
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                  timeout { Rpush.shutdown }
         
     | 
| 
      
 124 
     | 
    
         
            +
                end
         
     | 
| 
       102 
125 
     | 
    
         | 
| 
       103 
126 
     | 
    
         
             
                it 'fails to deliver a notification' do
         
     | 
| 
      
 127 
     | 
    
         
            +
                  notification = create_notification
         
     | 
| 
       104 
128 
     | 
    
         
             
                  wait_for_notification_to_deliver(notification)
         
     | 
| 
       105 
129 
     | 
    
         
             
                  fail_notification(notification)
         
     | 
| 
       106 
130 
     | 
    
         
             
                  wait_for_notification_to_fail(notification)
         
     | 
| 
       107 
131 
     | 
    
         
             
                end
         
     | 
| 
       108 
132 
     | 
    
         | 
| 
      
 133 
     | 
    
         
            +
                describe 'with a failed connection' do
         
     | 
| 
      
 134 
     | 
    
         
            +
                  it 'retries all notifications' do
         
     | 
| 
      
 135 
     | 
    
         
            +
                    Rpush::Daemon::TcpConnection.any_instance.stub(sleep: nil)
         
     | 
| 
      
 136 
     | 
    
         
            +
                    expect(ssl_socket).to receive(:write).at_least(1).times.and_raise(Errno::EPIPE)
         
     | 
| 
      
 137 
     | 
    
         
            +
                    notifications = 2.times.map { create_notification }
         
     | 
| 
      
 138 
     | 
    
         
            +
                    notifications.each { |n| wait_for_notification_to_retry(n) }
         
     | 
| 
      
 139 
     | 
    
         
            +
                  end
         
     | 
| 
      
 140 
     | 
    
         
            +
                end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
       109 
142 
     | 
    
         
             
                describe 'with multiple notifications' do
         
     | 
| 
       110 
143 
     | 
    
         
             
                  let(:notification1) { create_notification }
         
     | 
| 
       111 
144 
     | 
    
         
             
                  let(:notification2) { create_notification }
         
     | 
| 
       112 
145 
     | 
    
         
             
                  let(:notification3) { create_notification }
         
     | 
| 
       113 
146 
     | 
    
         
             
                  let(:notification4) { create_notification }
         
     | 
| 
       114 
     | 
    
         
            -
                  let 
     | 
| 
      
 147 
     | 
    
         
            +
                  let(:notifications) { [notification1, notification2, notification3, notification4] }
         
     | 
| 
       115 
148 
     | 
    
         | 
| 
       116 
149 
     | 
    
         
             
                  it 'marks the correct notification as failed' do
         
     | 
| 
       117 
150 
     | 
    
         
             
                    notifications.each { |n| wait_for_notification_to_deliver(n) }
         
     | 
| 
         @@ -124,29 +157,15 @@ describe 'APNs' do 
     | 
|
| 
       124 
157 
     | 
    
         
             
                    fail_notification(notification2)
         
     | 
| 
       125 
158 
     | 
    
         
             
                    wait_for_notification_to_fail(notification2)
         
     | 
| 
       126 
159 
     | 
    
         | 
| 
      
 160 
     | 
    
         
            +
                    expect(failed_ids).to_not include(notification1.id)
         
     | 
| 
       127 
161 
     | 
    
         
             
                    notification1.reload
         
     | 
| 
       128 
162 
     | 
    
         
             
                    notification1.delivered.should be_true
         
     | 
| 
       129 
163 
     | 
    
         
             
                  end
         
     | 
| 
       130 
164 
     | 
    
         | 
| 
       131 
     | 
    
         
            -
                   
     | 
| 
       132 
     | 
    
         
            -
             
     | 
| 
       133 
     | 
    
         
            -
             
     | 
| 
       134 
     | 
    
         
            -
             
     | 
| 
       135 
     | 
    
         
            -
                  #   notifications.each { |n| wait_for_notification_to_deliver(n) }
         
     | 
| 
       136 
     | 
    
         
            -
                  #   fail_notification(notification2)
         
     | 
| 
       137 
     | 
    
         
            -
                  #
         
     | 
| 
       138 
     | 
    
         
            -
                  #   [notification3, notification4].each do |n|
         
     | 
| 
       139 
     | 
    
         
            -
                  #     wait_for_notification_to_retry(n)
         
     | 
| 
       140 
     | 
    
         
            -
                  #   end
         
     | 
| 
       141 
     | 
    
         
            -
                  # end
         
     | 
| 
       142 
     | 
    
         
            -
             
     | 
| 
       143 
     | 
    
         
            -
                  describe 'without an error response' do
         
     | 
| 
       144 
     | 
    
         
            -
                    it 'marks all notifications as failed' do
         
     | 
| 
       145 
     | 
    
         
            -
                      notifications.each { |n| wait_for_notification_to_deliver(n) }
         
     | 
| 
       146 
     | 
    
         
            -
                      ssl_socket.stub(read: nil)
         
     | 
| 
       147 
     | 
    
         
            -
                      enable_io_select
         
     | 
| 
       148 
     | 
    
         
            -
                      notifications.each { |n| wait_for_notification_to_fail(n) }
         
     | 
| 
       149 
     | 
    
         
            -
                    end
         
     | 
| 
      
 165 
     | 
    
         
            +
                  it 'marks notifications following the failed one as retryable' do
         
     | 
| 
      
 166 
     | 
    
         
            +
                    notifications.each { |n| wait_for_notification_to_deliver(n) }
         
     | 
| 
      
 167 
     | 
    
         
            +
                    fail_notification(notification2)
         
     | 
| 
      
 168 
     | 
    
         
            +
                    [notification3, notification4].each { |n| wait_for_notification_to_retry(n) }
         
     | 
| 
       150 
169 
     | 
    
         
             
                  end
         
     | 
| 
       151 
170 
     | 
    
         
             
                end
         
     | 
| 
       152 
171 
     | 
    
         
             
              end
         
     | 
    
        data/spec/functional/gcm_spec.rb
    CHANGED
    
    | 
         @@ -36,4 +36,13 @@ describe 'GCM' do 
     | 
|
| 
       36 
36 
     | 
    
         
             
                  notification.reload
         
     | 
| 
       37 
37 
     | 
    
         
             
                end.to_not change(notification, :delivered).to(true)
         
     | 
| 
       38 
38 
     | 
    
         
             
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              it 'retries notification that fail due to a SocketError' do
         
     | 
| 
      
 41 
     | 
    
         
            +
                expect(http).to receive(:request).and_raise(SocketError.new)
         
     | 
| 
      
 42 
     | 
    
         
            +
                expect(notification.deliver_after).to be_nil
         
     | 
| 
      
 43 
     | 
    
         
            +
                expect do
         
     | 
| 
      
 44 
     | 
    
         
            +
                  Rpush.push
         
     | 
| 
      
 45 
     | 
    
         
            +
                  notification.reload
         
     | 
| 
      
 46 
     | 
    
         
            +
                end.to change(notification, :deliver_after).to(kind_of(Time))
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
       39 
48 
     | 
    
         
             
            end
         
     |