rpush 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.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +99 -0
  3. data/LICENSE +7 -0
  4. data/README.md +189 -0
  5. data/bin/rpush +36 -0
  6. data/config/database.yml +44 -0
  7. data/lib/generators/rpush_generator.rb +44 -0
  8. data/lib/generators/templates/add_adm.rb +23 -0
  9. data/lib/generators/templates/add_alert_is_json_to_rapns_notifications.rb +9 -0
  10. data/lib/generators/templates/add_app_to_rapns.rb +11 -0
  11. data/lib/generators/templates/add_fail_after_to_rpush_notifications.rb +9 -0
  12. data/lib/generators/templates/add_gcm.rb +102 -0
  13. data/lib/generators/templates/add_rpush.rb +349 -0
  14. data/lib/generators/templates/add_wpns.rb +16 -0
  15. data/lib/generators/templates/create_rapns_apps.rb +16 -0
  16. data/lib/generators/templates/create_rapns_feedback.rb +18 -0
  17. data/lib/generators/templates/create_rapns_notifications.rb +29 -0
  18. data/lib/generators/templates/rename_rapns_to_rpush.rb +63 -0
  19. data/lib/generators/templates/rpush.rb +104 -0
  20. data/lib/rpush.rb +62 -0
  21. data/lib/rpush/TODO +3 -0
  22. data/lib/rpush/adm/app.rb +15 -0
  23. data/lib/rpush/adm/data_validator.rb +11 -0
  24. data/lib/rpush/adm/notification.rb +29 -0
  25. data/lib/rpush/apns/app.rb +29 -0
  26. data/lib/rpush/apns/binary_notification_validator.rb +12 -0
  27. data/lib/rpush/apns/device_token_format_validator.rb +12 -0
  28. data/lib/rpush/apns/feedback.rb +16 -0
  29. data/lib/rpush/apns/notification.rb +84 -0
  30. data/lib/rpush/apns_feedback.rb +13 -0
  31. data/lib/rpush/app.rb +18 -0
  32. data/lib/rpush/configuration.rb +75 -0
  33. data/lib/rpush/daemon.rb +140 -0
  34. data/lib/rpush/daemon/adm.rb +9 -0
  35. data/lib/rpush/daemon/adm/delivery.rb +222 -0
  36. data/lib/rpush/daemon/apns.rb +16 -0
  37. data/lib/rpush/daemon/apns/certificate_expired_error.rb +20 -0
  38. data/lib/rpush/daemon/apns/delivery.rb +64 -0
  39. data/lib/rpush/daemon/apns/disconnection_error.rb +20 -0
  40. data/lib/rpush/daemon/apns/feedback_receiver.rb +79 -0
  41. data/lib/rpush/daemon/app_runner.rb +187 -0
  42. data/lib/rpush/daemon/batch.rb +115 -0
  43. data/lib/rpush/daemon/constants.rb +59 -0
  44. data/lib/rpush/daemon/delivery.rb +28 -0
  45. data/lib/rpush/daemon/delivery_error.rb +19 -0
  46. data/lib/rpush/daemon/dispatcher/http.rb +21 -0
  47. data/lib/rpush/daemon/dispatcher/tcp.rb +30 -0
  48. data/lib/rpush/daemon/dispatcher_loop.rb +54 -0
  49. data/lib/rpush/daemon/dispatcher_loop_collection.rb +33 -0
  50. data/lib/rpush/daemon/feeder.rb +68 -0
  51. data/lib/rpush/daemon/gcm.rb +9 -0
  52. data/lib/rpush/daemon/gcm/delivery.rb +222 -0
  53. data/lib/rpush/daemon/interruptible_sleep.rb +61 -0
  54. data/lib/rpush/daemon/loggable.rb +31 -0
  55. data/lib/rpush/daemon/reflectable.rb +13 -0
  56. data/lib/rpush/daemon/retry_header_parser.rb +23 -0
  57. data/lib/rpush/daemon/retryable_error.rb +20 -0
  58. data/lib/rpush/daemon/service_config_methods.rb +33 -0
  59. data/lib/rpush/daemon/store/active_record.rb +154 -0
  60. data/lib/rpush/daemon/store/active_record/reconnectable.rb +68 -0
  61. data/lib/rpush/daemon/tcp_connection.rb +143 -0
  62. data/lib/rpush/daemon/too_many_requests_error.rb +20 -0
  63. data/lib/rpush/daemon/wpns.rb +9 -0
  64. data/lib/rpush/daemon/wpns/delivery.rb +132 -0
  65. data/lib/rpush/deprecatable.rb +23 -0
  66. data/lib/rpush/deprecation.rb +23 -0
  67. data/lib/rpush/embed.rb +28 -0
  68. data/lib/rpush/gcm/app.rb +11 -0
  69. data/lib/rpush/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +11 -0
  70. data/lib/rpush/gcm/notification.rb +30 -0
  71. data/lib/rpush/logger.rb +63 -0
  72. data/lib/rpush/multi_json_helper.rb +16 -0
  73. data/lib/rpush/notification.rb +69 -0
  74. data/lib/rpush/notifier.rb +52 -0
  75. data/lib/rpush/payload_data_size_validator.rb +10 -0
  76. data/lib/rpush/push.rb +16 -0
  77. data/lib/rpush/railtie.rb +11 -0
  78. data/lib/rpush/reflection.rb +58 -0
  79. data/lib/rpush/registration_ids_count_validator.rb +10 -0
  80. data/lib/rpush/version.rb +3 -0
  81. data/lib/rpush/wpns/app.rb +9 -0
  82. data/lib/rpush/wpns/notification.rb +26 -0
  83. data/lib/tasks/cane.rake +18 -0
  84. data/lib/tasks/rpush.rake +16 -0
  85. data/lib/tasks/test.rake +38 -0
  86. data/spec/functional/adm_spec.rb +43 -0
  87. data/spec/functional/apns_spec.rb +58 -0
  88. data/spec/functional/embed_spec.rb +49 -0
  89. data/spec/functional/gcm_spec.rb +42 -0
  90. data/spec/functional/wpns_spec.rb +41 -0
  91. data/spec/support/cert_with_password.pem +90 -0
  92. data/spec/support/cert_without_password.pem +59 -0
  93. data/spec/support/install.sh +32 -0
  94. data/spec/support/simplecov_helper.rb +20 -0
  95. data/spec/support/simplecov_quality_formatter.rb +8 -0
  96. data/spec/tmp/.gitkeep +0 -0
  97. data/spec/unit/adm/app_spec.rb +58 -0
  98. data/spec/unit/adm/notification_spec.rb +45 -0
  99. data/spec/unit/apns/app_spec.rb +29 -0
  100. data/spec/unit/apns/feedback_spec.rb +9 -0
  101. data/spec/unit/apns/notification_spec.rb +208 -0
  102. data/spec/unit/apns_feedback_spec.rb +21 -0
  103. data/spec/unit/app_spec.rb +30 -0
  104. data/spec/unit/configuration_spec.rb +45 -0
  105. data/spec/unit/daemon/adm/delivery_spec.rb +243 -0
  106. data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +11 -0
  107. data/spec/unit/daemon/apns/delivery_spec.rb +101 -0
  108. data/spec/unit/daemon/apns/disconnection_error_spec.rb +18 -0
  109. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +117 -0
  110. data/spec/unit/daemon/app_runner_spec.rb +292 -0
  111. data/spec/unit/daemon/batch_spec.rb +232 -0
  112. data/spec/unit/daemon/delivery_error_spec.rb +13 -0
  113. data/spec/unit/daemon/delivery_spec.rb +38 -0
  114. data/spec/unit/daemon/dispatcher/http_spec.rb +33 -0
  115. data/spec/unit/daemon/dispatcher/tcp_spec.rb +38 -0
  116. data/spec/unit/daemon/dispatcher_loop_collection_spec.rb +37 -0
  117. data/spec/unit/daemon/dispatcher_loop_spec.rb +71 -0
  118. data/spec/unit/daemon/feeder_spec.rb +98 -0
  119. data/spec/unit/daemon/gcm/delivery_spec.rb +310 -0
  120. data/spec/unit/daemon/interruptible_sleep_spec.rb +68 -0
  121. data/spec/unit/daemon/reflectable_spec.rb +27 -0
  122. data/spec/unit/daemon/retryable_error_spec.rb +14 -0
  123. data/spec/unit/daemon/service_config_methods_spec.rb +33 -0
  124. data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +114 -0
  125. data/spec/unit/daemon/store/active_record_spec.rb +357 -0
  126. data/spec/unit/daemon/tcp_connection_spec.rb +287 -0
  127. data/spec/unit/daemon/too_many_requests_error_spec.rb +14 -0
  128. data/spec/unit/daemon/wpns/delivery_spec.rb +159 -0
  129. data/spec/unit/daemon_spec.rb +159 -0
  130. data/spec/unit/deprecatable_spec.rb +32 -0
  131. data/spec/unit/deprecation_spec.rb +15 -0
  132. data/spec/unit/embed_spec.rb +50 -0
  133. data/spec/unit/gcm/app_spec.rb +4 -0
  134. data/spec/unit/gcm/notification_spec.rb +36 -0
  135. data/spec/unit/logger_spec.rb +127 -0
  136. data/spec/unit/notification_shared.rb +105 -0
  137. data/spec/unit/notification_spec.rb +15 -0
  138. data/spec/unit/notifier_spec.rb +49 -0
  139. data/spec/unit/push_spec.rb +43 -0
  140. data/spec/unit/reflection_spec.rb +30 -0
  141. data/spec/unit/rpush_spec.rb +9 -0
  142. data/spec/unit/wpns/app_spec.rb +4 -0
  143. data/spec/unit/wpns/notification_spec.rb +30 -0
  144. data/spec/unit_spec_helper.rb +101 -0
  145. metadata +276 -0
@@ -0,0 +1,159 @@
1
+ require 'unit_spec_helper'
2
+ require 'rpush/daemon/store/active_record'
3
+
4
+ describe Rpush::Daemon, "when starting" do
5
+ module Rails; end
6
+
7
+ let(:certificate) { double }
8
+ let(:password) { double }
9
+ let(:config) { double(:pid_file => nil, :foreground => true,
10
+ :embedded => false, :push => false, :store => :active_record,
11
+ :logger => nil) }
12
+ let(:logger) { double(:logger, :info => nil, :error => nil, :warn => nil) }
13
+
14
+ before do
15
+ Rpush.stub(:config => config, :logger => logger)
16
+ Rpush::Daemon::Feeder.stub(:start)
17
+ Rpush::Daemon::AppRunner.stub(:sync => nil, :stop => nil)
18
+ Rpush::Daemon.stub(:daemonize => nil, :exit => nil, :puts => nil)
19
+ File.stub(:open)
20
+ Rails.stub(:root).and_return("/rails_root")
21
+ end
22
+
23
+ unless Rpush.jruby?
24
+ it "forks into a daemon if the foreground option is false" do
25
+ config.stub(:foreground => false)
26
+ Rpush::Daemon.initialize_store
27
+ Rpush::Daemon.store.stub(:after_daemonize => nil)
28
+ Rpush::Daemon.should_receive(:daemonize)
29
+ Rpush::Daemon.start
30
+ end
31
+
32
+ it 'notifies the store after forking' do
33
+ config.stub(:foreground => false)
34
+ Rpush::Daemon.initialize_store
35
+ Rpush::Daemon.store.should_receive(:after_daemonize)
36
+ Rpush::Daemon.start
37
+ end
38
+
39
+ it "does not fork into a daemon if the foreground option is true" do
40
+ config.stub(:foreground => true)
41
+ Rpush::Daemon.should_not_receive(:daemonize)
42
+ Rpush::Daemon.start
43
+ end
44
+
45
+ it "does not fork into a daemon if the push option is true" do
46
+ config.stub(:push => true)
47
+ Rpush::Daemon.should_not_receive(:daemonize)
48
+ Rpush::Daemon.start
49
+ end
50
+
51
+ it "does not fork into a daemon if the embedded option is true" do
52
+ config.stub(:embedded => true)
53
+ Rpush::Daemon.should_not_receive(:daemonize)
54
+ Rpush::Daemon.start
55
+ end
56
+ end
57
+
58
+ it 'sets up setup signal traps' do
59
+ Rpush::Daemon.should_receive(:setup_signal_traps)
60
+ Rpush::Daemon.start
61
+ end
62
+
63
+ it 'does not setup signal traps when embedded' do
64
+ config.stub(:embedded => true)
65
+ Rpush::Daemon.should_not_receive(:setup_signal_traps)
66
+ Rpush::Daemon.start
67
+ end
68
+
69
+ it 'instantiates the store' do
70
+ config.stub(:store => :active_record)
71
+ Rpush::Daemon.start
72
+ Rpush::Daemon.store.should be_kind_of(Rpush::Daemon::Store::ActiveRecord)
73
+ end
74
+
75
+ it 'logs an error if the store cannot be loaded' do
76
+ config.stub(:store => :foo_bar)
77
+ Rpush.logger.should_receive(:error).with(kind_of(LoadError))
78
+ Rpush::Daemon.start
79
+ end
80
+
81
+ it "writes the process ID to the PID file" do
82
+ Rpush::Daemon.should_receive(:write_pid_file)
83
+ Rpush::Daemon.start
84
+ end
85
+
86
+ it "logs an error if the PID file could not be written" do
87
+ config.stub(:pid_file => '/rails_root/rpush.pid')
88
+ File.stub(:open).and_raise(Errno::ENOENT)
89
+ logger.should_receive(:error).with("Failed to write PID to '/rails_root/rpush.pid': #<Errno::ENOENT: No such file or directory>")
90
+ Rpush::Daemon.start
91
+ end
92
+
93
+ it "starts the feeder" do
94
+ Rpush::Daemon::Feeder.should_receive(:start)
95
+ Rpush::Daemon.start
96
+ end
97
+
98
+ it "syncs apps" do
99
+ Rpush::Daemon::AppRunner.should_receive(:sync)
100
+ Rpush::Daemon.start
101
+ end
102
+ end
103
+
104
+ describe Rpush::Daemon, "when being shutdown" do
105
+ let(:config) { double(:pid_file => '/rails_root/rpush.pid') }
106
+ let(:logger) { double(:info => nil, :error => nil, :warn => nil) }
107
+
108
+ before do
109
+ Rpush.stub(:config => config)
110
+ Rpush::Daemon.stub(:puts => nil)
111
+ Rpush::Daemon::Feeder.stub(:stop)
112
+ Rpush::Daemon::AppRunner.stub(:stop)
113
+ end
114
+
115
+ # These tests do not work on JRuby.
116
+ unless Rpush.jruby?
117
+ it "shuts down when signaled signaled SIGINT" do
118
+ Rpush::Daemon.setup_signal_traps
119
+ Rpush::Daemon.should_receive(:shutdown)
120
+ Process.kill("SIGINT", Process.pid)
121
+ sleep 0.01
122
+ end
123
+
124
+ it "shuts down when signaled signaled SIGTERM" do
125
+ Rpush::Daemon.setup_signal_traps
126
+ Rpush::Daemon.should_receive(:shutdown)
127
+ Process.kill("SIGTERM", Process.pid)
128
+ sleep 0.01
129
+ end
130
+ end
131
+
132
+ it "stops the feeder" do
133
+ Rpush::Daemon::Feeder.should_receive(:stop)
134
+ Rpush::Daemon.shutdown
135
+ end
136
+
137
+ it "stops the app runners" do
138
+ Rpush::Daemon::AppRunner.should_receive(:stop)
139
+ Rpush::Daemon.shutdown
140
+ end
141
+
142
+ it "removes the PID file if one was written" do
143
+ File.stub(:exists?).and_return(true)
144
+ File.should_receive(:delete).with("/rails_root/rpush.pid")
145
+ Rpush::Daemon.shutdown
146
+ end
147
+
148
+ it "does not attempt to remove the PID file if it does not exist" do
149
+ File.stub(:exists?).and_return(false)
150
+ File.should_not_receive(:delete)
151
+ Rpush::Daemon.shutdown
152
+ end
153
+
154
+ it "does not attempt to remove the PID file if one was not written" do
155
+ config.stub(:pid_file).and_return(nil)
156
+ File.should_not_receive(:delete)
157
+ Rpush::Daemon.shutdown
158
+ end
159
+ end
@@ -0,0 +1,32 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Rpush::Deprecatable do
4
+ class HasDeprecatedMethod
5
+ include Rpush::Deprecatable
6
+
7
+ def original_called?
8
+ @called == true
9
+ end
10
+
11
+ def deprecated_method
12
+ @called = true
13
+ end
14
+ deprecated(:deprecated_method, '4.0')
15
+ end
16
+
17
+ let(:klass) { HasDeprecatedMethod.new }
18
+
19
+ before do
20
+ Rpush::Deprecation.stub(:warn)
21
+ end
22
+
23
+ it 'warns the method is deprecated when called' do
24
+ Rpush::Deprecation.should_receive(:warn).with("deprecated_method is deprecated and will be removed from Rpush 4.0.")
25
+ klass.deprecated_method
26
+ end
27
+
28
+ it 'calls the original method' do
29
+ klass.deprecated_method
30
+ klass.original_called?.should be_true
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Rpush::Deprecation do
4
+ it 'prints a warning' do
5
+ STDERR.should_receive(:puts).with("DEPRECATION WARNING: msg")
6
+ Rpush::Deprecation.warn("msg")
7
+ end
8
+
9
+ it 'does not print a warning when muted' do
10
+ STDERR.should_not_receive(:puts)
11
+ Rpush::Deprecation.muted do
12
+ Rpush::Deprecation.warn("msg")
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,50 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Rpush, 'embed' do
4
+ before do
5
+ Rpush::Daemon.stub(:start)
6
+ Kernel.stub(:at_exit)
7
+ end
8
+
9
+ it 'sets the embedded config option to true' do
10
+ Rpush.embed
11
+ Rpush.config.embedded.should be_true
12
+ end
13
+
14
+ it 'starts the daemon' do
15
+ Rpush::Daemon.should_receive(:start)
16
+ Rpush.embed
17
+ end
18
+
19
+ it 'overrides the default config options with those given as a hash' do
20
+ Rpush.config.push_poll = 4
21
+ expect { Rpush.embed(:push_poll => 2) }.to change(Rpush.config, :push_poll).to(2)
22
+ end
23
+ end
24
+
25
+ describe Rpush, 'shutdown' do
26
+ before { Rpush.config.embedded = true }
27
+
28
+ it 'shuts down the daemon' do
29
+ Rpush::Daemon.should_receive(:shutdown)
30
+ Rpush.shutdown
31
+ end
32
+ end
33
+
34
+ describe Rpush, 'sync' do
35
+ before { Rpush.config.embedded = true }
36
+
37
+ it 'syncs the AppRunner' do
38
+ Rpush::Daemon::AppRunner.should_receive(:sync)
39
+ Rpush.sync
40
+ end
41
+ end
42
+
43
+ describe Rpush, 'debug' do
44
+ before { Rpush.config.embedded = true }
45
+
46
+ it 'debugs the AppRunner' do
47
+ Rpush::Daemon::AppRunner.should_receive(:debug)
48
+ Rpush.debug
49
+ end
50
+ end
@@ -0,0 +1,4 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Rpush::Gcm::App do
4
+ end
@@ -0,0 +1,36 @@
1
+ require 'unit_spec_helper'
2
+ require 'unit/notification_shared.rb'
3
+
4
+ describe Rpush::Gcm::Notification do
5
+ it_should_behave_like 'an Notification subclass'
6
+
7
+ let(:app) { Rpush::Gcm::App.create!(:name => 'test', :auth_key => 'abc') }
8
+ let(:notification_class) { Rpush::Gcm::Notification }
9
+ let(:notification) { notification_class.new }
10
+ let(:data_setter) { 'data=' }
11
+ let(:data_getter) { 'data' }
12
+
13
+ it "has a 'data' payload limit of 4096 bytes" do
14
+ notification.data = { :key => "a" * 4096 }
15
+ notification.valid?.should be_false
16
+ notification.errors[:base].should eq ["Notification payload data cannot be larger than 4096 bytes."]
17
+ end
18
+
19
+ it 'limits the number of registration ids to 1000' do
20
+ notification.registration_ids = ['a']*(1000+1)
21
+ notification.valid?.should be_false
22
+ notification.errors[:base].should eq ["Number of registration_ids cannot be larger than 1000."]
23
+ end
24
+
25
+ it 'validates expiry is present if collapse_key is set' do
26
+ notification.collapse_key = 'test'
27
+ notification.expiry = nil
28
+ notification.valid?.should be_false
29
+ notification.errors[:expiry].should eq ['must be set when using a collapse_key']
30
+ end
31
+
32
+ it 'includes time_to_live in the payload' do
33
+ notification.expiry = 100
34
+ notification.as_json['time_to_live'].should eq 100
35
+ end
36
+ end
@@ -0,0 +1,127 @@
1
+ require "unit_spec_helper"
2
+
3
+ module Rails
4
+ def self.logger
5
+ @logger
6
+ end
7
+
8
+ def self.logger=(logger)
9
+ @logger = logger
10
+ end
11
+ end
12
+
13
+ module HoptoadNotifier
14
+ def self.notify(e)
15
+ end
16
+ end
17
+
18
+ describe Rpush::Logger do
19
+ let(:log) { double(:sync= => true) }
20
+
21
+ before do
22
+ Rails.stub(:root).and_return("/rails_root")
23
+
24
+ @logger_class = if defined?(ActiveSupport::BufferedLogger)
25
+ ActiveSupport::BufferedLogger
26
+ else
27
+ ActiveSupport::Logger
28
+ end
29
+
30
+ @logger = double(@logger_class.name, :info => nil, :error => nil, :level => 0, :auto_flushing => 1, :auto_flushing= => nil)
31
+ @logger_class.stub(:new).and_return(@logger)
32
+ Rails.logger = @logger
33
+ File.stub(:open => log)
34
+ FileUtils.stub(:mkdir_p => nil)
35
+ STDERR.stub(:puts)
36
+ end
37
+
38
+ it "disables logging if the log file cannot be opened" do
39
+ File.stub(:open).and_raise(Errno::ENOENT)
40
+ STDERR.should_receive(:puts).with(/No such file or directory/)
41
+ STDERR.should_receive(:puts).with(/Logging disabled/)
42
+ Rpush::Logger.new(:foreground => true)
43
+ end
44
+
45
+ it 'creates the log directory' do
46
+ FileUtils.should_receive(:mkdir_p).with('/rails_root/log')
47
+ Rpush::Logger.new(:foreground => true)
48
+ end
49
+
50
+ it "should open the a log file in the Rails log directory" do
51
+ File.should_receive(:open).with('/rails_root/log/rpush.log', 'a')
52
+ Rpush::Logger.new(:foreground => true)
53
+ end
54
+
55
+ it 'sets sync mode on the log descriptor' do
56
+ log.should_receive(:sync=).with(true)
57
+ Rpush::Logger.new(:foreground => true)
58
+ end
59
+
60
+ it 'uses the user-defined logger' do
61
+ my_logger = double
62
+ Rpush.config.logger = my_logger
63
+ logger = Rpush::Logger.new({})
64
+ my_logger.should_receive(:info)
65
+ logger.info('test')
66
+ end
67
+
68
+ it 'uses ActiveSupport::BufferedLogger if a user-defined logger is not set' do
69
+ if ActiveSupport.const_defined?('BufferedLogger')
70
+ ActiveSupport::BufferedLogger.should_receive(:new).with(log, Rails.logger.level)
71
+ Rpush::Logger.new(:foreground => true)
72
+ end
73
+ end
74
+
75
+ it 'uses ActiveSupport::Logger if BufferedLogger does not exist' do
76
+ stub_const('ActiveSupport::Logger', double)
77
+ ActiveSupport.stub(:const_defined? => false)
78
+ ActiveSupport::Logger.should_receive(:new).with(log, Rails.logger.level)
79
+ Rpush::Logger.new(:foreground => true)
80
+ end
81
+
82
+ it "should print out the msg if running in the foreground" do
83
+ logger = Rpush::Logger.new(:foreground => true)
84
+ STDOUT.should_receive(:puts).with(/hi mom/)
85
+ logger.info("hi mom")
86
+ end
87
+
88
+ it "should not print out the msg if not running in the foreground" do
89
+ logger = Rpush::Logger.new(:foreground => false)
90
+ STDOUT.should_not_receive(:puts).with(/hi mom/)
91
+ logger.info("hi mom")
92
+ end
93
+
94
+ it "should prefix log lines with the current time" do
95
+ now = Time.now
96
+ Time.stub(:now).and_return(now)
97
+ logger = Rpush::Logger.new(:foreground => false)
98
+ @logger.should_receive(:info).with(/#{Regexp.escape("[#{now.to_s(:db)}]")}/)
99
+ logger.info("blah")
100
+ end
101
+
102
+ it "should prefix error logs with the ERROR label" do
103
+ logger = Rpush::Logger.new(:foreground => false)
104
+ @logger.should_receive(:error).with(/#{Regexp.escape("[ERROR]")}/)
105
+ logger.error("eeek")
106
+ end
107
+
108
+ it "should prefix warn logs with the WARNING label" do
109
+ logger = Rpush::Logger.new(:foreground => false)
110
+ @logger.should_receive(:warn).with(/#{Regexp.escape("[WARNING]")}/)
111
+ logger.warn("eeek")
112
+ end
113
+
114
+ it "should handle an Exception instance" do
115
+ e = RuntimeError.new("hi mom")
116
+ e.stub(:backtrace => [])
117
+ logger = Rpush::Logger.new(:foreground => false)
118
+ @logger.should_receive(:error).with(/RuntimeError, hi mom/)
119
+ logger.error(e)
120
+ end
121
+
122
+ it 'defaults auto_flushing to true if the Rails logger does not respond to auto_flushing' do
123
+ rails_logger = double(:info => nil, :error => nil, :level => 0)
124
+ Rails.logger = rails_logger
125
+ @logger.auto_flushing.should be_true
126
+ end
127
+ end
@@ -0,0 +1,105 @@
1
+ shared_examples_for "an Notification subclass" do
2
+ describe "when assigning data for the device" do
3
+ before { Rpush::Deprecation.stub(:warn) }
4
+
5
+ it "calls MultiJson.dump when multi_json responds to :dump" do
6
+ notification = notification_class.new
7
+ MultiJson.stub(:respond_to?).with(:dump).and_return(true)
8
+ MultiJson.should_receive(:dump).with(any_args())
9
+ notification.send(data_setter, { :pirates => 1 })
10
+ end
11
+
12
+ it "calls MultiJson.encode when multi_json does not respond to :dump" do
13
+ notification = notification_class.new
14
+ MultiJson.stub(:respond_to?).with(:dump).and_return(false)
15
+ MultiJson.should_receive(:encode).with(any_args())
16
+ notification.send(data_setter, { :ninjas => 1 })
17
+ end
18
+
19
+ it "raises an ArgumentError if something other than a Hash is assigned" do
20
+ expect do
21
+ notification.send(data_setter, Array.new)
22
+ end.to raise_error(ArgumentError, "must be a Hash")
23
+ end
24
+
25
+ it "encodes the given Hash as JSON" do
26
+ notification.send(data_setter, { :hi => "mom" })
27
+ notification.read_attribute(:data).should eq "{\"hi\":\"mom\"}"
28
+ end
29
+
30
+ it "decodes the JSON when using the reader method" do
31
+ notification.send(data_setter, { :hi => "mom" })
32
+ notification.send(data_getter).should eq ({"hi" => "mom"})
33
+ end
34
+
35
+ describe 'scopes' do
36
+ before do
37
+ Timecop.freeze(Time.now)
38
+
39
+ (@delivered_notification = notification_class.new(:app => app, :delivered => true, :failed => false)).save!(:validate => false)
40
+ (@failed_notification = notification_class.new(:app => app, :delivered => false, :failed => true)).save!(:validate => false)
41
+ (@new_notification = notification_class.new(:app => app, :delivered => false, :failed => false)).save!(:validate => false)
42
+ end
43
+
44
+ after do
45
+ Timecop.return
46
+ end
47
+
48
+ describe '.completed' do
49
+ it 'should return notifications that have been delivered or failed' do
50
+ completed_notification_ids = Rpush::Notification.completed.map(&:id)
51
+
52
+ completed_notification_ids.size.should eq 2
53
+ completed_notification_ids.should include(@delivered_notification.id, @failed_notification.id)
54
+ completed_notification_ids.should_not include(@new_notification.id)
55
+ end
56
+ end
57
+
58
+ describe '.created_before' do
59
+ it 'should return notifications that were created before the specified date' do
60
+ @delivered_notification.created_at = Time.now - 30.days - 1.second
61
+ @delivered_notification.save!(:validate => false)
62
+
63
+ notification_ids = Rpush::Notification.created_before(Time.now - 30.days).map(&:id)
64
+
65
+ notification_ids.size.should eq 1
66
+ notification_ids.should include(@delivered_notification.id)
67
+ end
68
+ end
69
+
70
+ describe '.completed_and_older_than' do
71
+ before do
72
+ @delivered_notification.created_at = Time.now - 30.days - 1.second
73
+ @delivered_notification.save!(:validate => false)
74
+
75
+ @failed_notification.created_at = Time.now - 20.days - 1.second
76
+ @failed_notification.save!(:validate => false)
77
+
78
+ @new_notification.created_at = Time.now - 30.days - 1.second
79
+ @new_notification.save!(:validate => false)
80
+ end
81
+
82
+ it 'should only include completed notifications' do
83
+ notification_ids = Rpush::Notification.completed_and_older_than(Time.now - 30.days).map(&:id)
84
+
85
+ notification_ids.size.should eq 1
86
+ notification_ids.should include(@delivered_notification.id)
87
+ end
88
+
89
+ it 'should not include completed notifications if not older than specified date' do
90
+ notification_ids = Rpush::Notification.completed_and_older_than(Time.now - 30.days).map(&:id)
91
+
92
+ notification_ids.size.should eq 1
93
+ notification_ids.should_not include(@failed_notification.id)
94
+ end
95
+
96
+ it 'should return notifications that are completed and created before the specified date' do
97
+ notification_ids = Rpush::Notification.completed_and_older_than(Time.now - 20.days).map(&:id)
98
+
99
+ notification_ids.size.should eq 2
100
+ notification_ids.should include(@delivered_notification.id, @failed_notification.id)
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end