rapns_rails_2 3.4.3

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 (113) hide show
  1. checksums.yaml +15 -0
  2. data/CHANGELOG.md +83 -0
  3. data/LICENSE +7 -0
  4. data/README.md +168 -0
  5. data/bin/rapns +37 -0
  6. data/config/database.yml +44 -0
  7. data/lib/generators/rapns_generator.rb +25 -0
  8. data/lib/generators/templates/add_alert_is_json_to_rapns_notifications.rb +9 -0
  9. data/lib/generators/templates/add_app_to_rapns.rb +11 -0
  10. data/lib/generators/templates/add_gcm.rb +95 -0
  11. data/lib/generators/templates/create_rapns_apps.rb +16 -0
  12. data/lib/generators/templates/create_rapns_feedback.rb +15 -0
  13. data/lib/generators/templates/create_rapns_notifications.rb +26 -0
  14. data/lib/generators/templates/rapns.rb +87 -0
  15. data/lib/rapns/TODO +3 -0
  16. data/lib/rapns/apns/app.rb +25 -0
  17. data/lib/rapns/apns/binary_notification_validator.rb +12 -0
  18. data/lib/rapns/apns/device_token_format_validator.rb +12 -0
  19. data/lib/rapns/apns/feedback.rb +16 -0
  20. data/lib/rapns/apns/notification.rb +91 -0
  21. data/lib/rapns/apns_feedback.rb +13 -0
  22. data/lib/rapns/app.rb +16 -0
  23. data/lib/rapns/configuration.rb +89 -0
  24. data/lib/rapns/daemon/apns/app_runner.rb +26 -0
  25. data/lib/rapns/daemon/apns/certificate_expired_error.rb +20 -0
  26. data/lib/rapns/daemon/apns/connection.rb +142 -0
  27. data/lib/rapns/daemon/apns/delivery.rb +64 -0
  28. data/lib/rapns/daemon/apns/delivery_handler.rb +35 -0
  29. data/lib/rapns/daemon/apns/disconnection_error.rb +20 -0
  30. data/lib/rapns/daemon/apns/feedback_receiver.rb +89 -0
  31. data/lib/rapns/daemon/app_runner.rb +179 -0
  32. data/lib/rapns/daemon/batch.rb +112 -0
  33. data/lib/rapns/daemon/delivery.rb +23 -0
  34. data/lib/rapns/daemon/delivery_error.rb +19 -0
  35. data/lib/rapns/daemon/delivery_handler.rb +52 -0
  36. data/lib/rapns/daemon/delivery_handler_collection.rb +33 -0
  37. data/lib/rapns/daemon/feeder.rb +65 -0
  38. data/lib/rapns/daemon/gcm/app_runner.rb +13 -0
  39. data/lib/rapns/daemon/gcm/delivery.rb +228 -0
  40. data/lib/rapns/daemon/gcm/delivery_handler.rb +20 -0
  41. data/lib/rapns/daemon/interruptible_sleep.rb +65 -0
  42. data/lib/rapns/daemon/reflectable.rb +13 -0
  43. data/lib/rapns/daemon/store/active_record/reconnectable.rb +66 -0
  44. data/lib/rapns/daemon/store/active_record.rb +128 -0
  45. data/lib/rapns/daemon.rb +129 -0
  46. data/lib/rapns/deprecatable.rb +23 -0
  47. data/lib/rapns/deprecation.rb +23 -0
  48. data/lib/rapns/embed.rb +28 -0
  49. data/lib/rapns/gcm/app.rb +7 -0
  50. data/lib/rapns/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +11 -0
  51. data/lib/rapns/gcm/notification.rb +37 -0
  52. data/lib/rapns/gcm/payload_data_size_validator.rb +13 -0
  53. data/lib/rapns/gcm/registration_ids_count_validator.rb +13 -0
  54. data/lib/rapns/logger.rb +76 -0
  55. data/lib/rapns/multi_json_helper.rb +16 -0
  56. data/lib/rapns/notification.rb +62 -0
  57. data/lib/rapns/notifier.rb +35 -0
  58. data/lib/rapns/push.rb +17 -0
  59. data/lib/rapns/rails-2-compatibility.rb +34 -0
  60. data/lib/rapns/reflection.rb +44 -0
  61. data/lib/rapns/upgraded.rb +31 -0
  62. data/lib/rapns/version.rb +3 -0
  63. data/lib/rapns_rails_2.rb +67 -0
  64. data/lib/tasks/cane.rake +18 -0
  65. data/lib/tasks/test.rake +38 -0
  66. data/spec/support/cert_with_password.pem +90 -0
  67. data/spec/support/cert_without_password.pem +59 -0
  68. data/spec/support/simplecov_helper.rb +13 -0
  69. data/spec/support/simplecov_quality_formatter.rb +8 -0
  70. data/spec/tmp/.gitkeep +0 -0
  71. data/spec/unit/apns/app_spec.rb +29 -0
  72. data/spec/unit/apns/feedback_spec.rb +9 -0
  73. data/spec/unit/apns/notification_spec.rb +215 -0
  74. data/spec/unit/apns_feedback_spec.rb +21 -0
  75. data/spec/unit/app_spec.rb +16 -0
  76. data/spec/unit/configuration_spec.rb +55 -0
  77. data/spec/unit/daemon/apns/app_runner_spec.rb +45 -0
  78. data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +11 -0
  79. data/spec/unit/daemon/apns/connection_spec.rb +287 -0
  80. data/spec/unit/daemon/apns/delivery_handler_spec.rb +59 -0
  81. data/spec/unit/daemon/apns/delivery_spec.rb +101 -0
  82. data/spec/unit/daemon/apns/disconnection_error_spec.rb +18 -0
  83. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +134 -0
  84. data/spec/unit/daemon/app_runner_shared.rb +83 -0
  85. data/spec/unit/daemon/app_runner_spec.rb +170 -0
  86. data/spec/unit/daemon/batch_spec.rb +219 -0
  87. data/spec/unit/daemon/delivery_error_spec.rb +13 -0
  88. data/spec/unit/daemon/delivery_handler_collection_spec.rb +37 -0
  89. data/spec/unit/daemon/delivery_handler_shared.rb +45 -0
  90. data/spec/unit/daemon/feeder_spec.rb +81 -0
  91. data/spec/unit/daemon/gcm/app_runner_spec.rb +19 -0
  92. data/spec/unit/daemon/gcm/delivery_handler_spec.rb +44 -0
  93. data/spec/unit/daemon/gcm/delivery_spec.rb +289 -0
  94. data/spec/unit/daemon/interruptible_sleep_spec.rb +68 -0
  95. data/spec/unit/daemon/reflectable_spec.rb +27 -0
  96. data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +114 -0
  97. data/spec/unit/daemon/store/active_record_spec.rb +281 -0
  98. data/spec/unit/daemon_spec.rb +157 -0
  99. data/spec/unit/deprecatable_spec.rb +32 -0
  100. data/spec/unit/deprecation_spec.rb +15 -0
  101. data/spec/unit/embed_spec.rb +50 -0
  102. data/spec/unit/gcm/app_spec.rb +4 -0
  103. data/spec/unit/gcm/notification_spec.rb +52 -0
  104. data/spec/unit/logger_spec.rb +180 -0
  105. data/spec/unit/notification_shared.rb +45 -0
  106. data/spec/unit/notification_spec.rb +4 -0
  107. data/spec/unit/notifier_spec.rb +32 -0
  108. data/spec/unit/push_spec.rb +44 -0
  109. data/spec/unit/rapns_spec.rb +9 -0
  110. data/spec/unit/reflection_spec.rb +30 -0
  111. data/spec/unit/upgraded_spec.rb +40 -0
  112. data/spec/unit_spec_helper.rb +137 -0
  113. metadata +232 -0
@@ -0,0 +1,59 @@
1
+ Bag Attributes
2
+ friendlyName: test certificate
3
+ localKeyID: 00 93 8F E4 A3 C3 75 64 3D 7E EA 14 0B 0A EA DD 15 85 8A D5
4
+ subject=/CN=test certificate/O=Example/OU=Example/ST=QLD/C=AU/L=Example/emailAddress=user@example.com
5
+ issuer=/CN=test certificate/O=Example/OU=Example/ST=QLD/C=AU/L=Example/emailAddress=user@example.com
6
+ -----BEGIN CERTIFICATE-----
7
+ MIID5jCCAs6gAwIBAgIBATALBgkqhkiG9w0BAQswgY0xGTAXBgNVBAMMEHRlc3Qg
8
+ Y2VydGlmaWNhdGUxEDAOBgNVBAoMB0V4YW1wbGUxEDAOBgNVBAsMB0V4YW1wbGUx
9
+ DDAKBgNVBAgMA1FMRDELMAkGA1UEBhMCQVUxEDAOBgNVBAcMB0V4YW1wbGUxHzAd
10
+ BgkqhkiG9w0BCQEWEHVzZXJAZXhhbXBsZS5jb20wHhcNMTIwOTA5MDMxODMyWhcN
11
+ MjIwOTA3MDMxODMyWjCBjTEZMBcGA1UEAwwQdGVzdCBjZXJ0aWZpY2F0ZTEQMA4G
12
+ A1UECgwHRXhhbXBsZTEQMA4GA1UECwwHRXhhbXBsZTEMMAoGA1UECAwDUUxEMQsw
13
+ CQYDVQQGEwJBVTEQMA4GA1UEBwwHRXhhbXBsZTEfMB0GCSqGSIb3DQEJARYQdXNl
14
+ ckBleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKF+
15
+ UDsN1sLen8g+97PNTiWju9+wkSv+H5rQlvb6YFLPx11YvqpK8ms6kFU1OmWeLfmh
16
+ cpsT+bZtKupC7aGPoSG3RXzzf/YUMgs/ZSXA0idZHA6tkReAEzIX6jL5otfPWbaP
17
+ luCTUoVMeP4u9ywk628zlqh9IQHC1Agl0R1xGCpULDk8kn1gPyEisl38wI5aDbzy
18
+ 6lYQGNUKOqt1xfVjtIFe/jyY/v0sxFjIJlRLcAFBuJx4sRV+PwRBkusOQtYwcwpI
19
+ loMxJj+GQe66ueATW81aC4iOU66DAFFEuGzwIwm3bOilimGGQbGb92F339RfmSOo
20
+ TPAvVhsakI3mzESb4lkCAwEAAaNRME8wDgYDVR0PAQH/BAQDAgeAMCAGA1UdJQEB
21
+ /wQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAbBgNVHREEFDASgRB1c2VyQGV4YW1w
22
+ bGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQA5UbNR+83ZdI2DiaB4dRmy0V5RDAqJ
23
+ k9+QskcTV4gBTjsOBS46Dw1tI6iTrfTyjYJdnyH0Y2Y2YVWBnvtON41UCZak+4ed
24
+ /IqyzU0dtfZ+frWa0RY4reyl80TwqnzyJfni0nDo4zGGvz70cxyaz2u1BWqwLjqb
25
+ dh8Dxvt+aHW2MQi0iGKh/HNbgwVanR4+ubNwziK9sR1Rnq9MkHWtwBw16SXQG6ao
26
+ SZKASWNaH8VL08Zz0E98cwd137UJkPsldCwJ8kHR5OzkcjPdXvnGD3d64yy2TC1Z
27
+ Gy1Aazt98wPcTYBytlhK8Rvzg9OoY9QmsdpmWxz1ZCXECJNqCa3IKsqO
28
+ -----END CERTIFICATE-----
29
+ Bag Attributes
30
+ friendlyName: test certificate
31
+ localKeyID: 00 93 8F E4 A3 C3 75 64 3D 7E EA 14 0B 0A EA DD 15 85 8A D5
32
+ Key Attributes: <No Attributes>
33
+ -----BEGIN RSA PRIVATE KEY-----
34
+ MIIEpQIBAAKCAQEAoX5QOw3Wwt6fyD73s81OJaO737CRK/4fmtCW9vpgUs/HXVi+
35
+ qkryazqQVTU6ZZ4t+aFymxP5tm0q6kLtoY+hIbdFfPN/9hQyCz9lJcDSJ1kcDq2R
36
+ F4ATMhfqMvmi189Zto+W4JNShUx4/i73LCTrbzOWqH0hAcLUCCXRHXEYKlQsOTyS
37
+ fWA/ISKyXfzAjloNvPLqVhAY1Qo6q3XF9WO0gV7+PJj+/SzEWMgmVEtwAUG4nHix
38
+ FX4/BEGS6w5C1jBzCkiWgzEmP4ZB7rq54BNbzVoLiI5TroMAUUS4bPAjCbds6KWK
39
+ YYZBsZv3YXff1F+ZI6hM8C9WGxqQjebMRJviWQIDAQABAoIBAQCTiLIDQUFSBdAz
40
+ QFNLD+S0vkCEuunlJuP4q1c/ir006l1YChsluBJ/o6D4NwiCjV+zDquEwVsALftm
41
+ yH4PewfZpXT2Ef508T5GyEO/mchj6iSXxDkpHvhqay6qIyWBwwxSnBtaTzy0Soi+
42
+ rmlhCtmLXbXld2sQEM1kJChGnWtWPtvSyrn+mapNPZviGRtgRNK+YsrAti1nUext
43
+ 2syO5mTdHf1D8GR7I98OaX6odREuSocEV9PzfapWZx2GK5tvRiS1skiug5ciieTd
44
+ Am5/C+bb31h4drFslihLb5BRGO5SFQJvMJL2Sx1f19BCC4XikS01P4/zZbxQNq79
45
+ kxEQuDGBAoGBANP4pIYZ5xshCkx7cTYqmxzWLClGKE2S7Oa8N89mtOwfmqT9AFun
46
+ t9Us9Ukbi8BaKlKhGpQ1HlLf/KVcpyW0x2qLou6AyIWYH+/5VaR3graNgUnzpK9f
47
+ 1F5HoaNHbhlAoebqhzhASFlJI2aqUdQjdOv73z+s9szJU4gpILNwGDFnAoGBAMMJ
48
+ j+vIxtG9J2jldyoXzpg5mbMXSj9u/wFLBVdjXWyOoiqVMMBto53RnoqAom7Ifr9D
49
+ 49LxRAT1Q3l4vs/YnM3ziMsIg2vQK1EbrLsY9OnD/kvPaLXOlNIOdfLM8UeVWZMc
50
+ I4LPbbZrhv/7CC8RjbRhMoWWdGYPvxmvD6V4ZDY/AoGBALoI6OxA45Htx4okdNHj
51
+ RstiNNPsnQaoQn6nBhxiubraafEPkzbd1fukP4pwQJELEUX/2sHkdL6rkqLW1GPF
52
+ a5dZAiBsqpCFWNJWdBGqSfBJ9QSgbxLz+gDcwUH6OOi0zuNJRm/aCyVBiW5bYQHc
53
+ NIvAPMk31ksZDtTbs7WIVdNVAoGBALZ1+KWNxKqs+fSBT5UahpUUtfy8miJz9a7A
54
+ /3M8q0cGvSF3Rw+OwpW/aEGMi+l2OlU27ykFuyukRAac9m296RwnbF79TO2M5ylO
55
+ 6a5zb5ROXlWP6RbE96b4DlIidssQJqegmHwlEC+rsrVBpOtb0aThlYEyOxzMOGyP
56
+ wOR9l8rDAoGADZ4TUHFM6VrvPlUZBkGbqiyXH9IM/y9JWk+22JQCEGnM6RFZemSs
57
+ jxWqQiPAdJtb3xKryJSCMtFPH9azedoCrSgaMflJ1QgoXgpiKZyoEXWraVUggh/0
58
+ CEavgZcTZ6SvMuayqJdGGB+zb1V8XwXMtCjApR/kTm47DjxO4DmpOPs=
59
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,13 @@
1
+ require 'simplecov'
2
+ require './spec/support/simplecov_quality_formatter'
3
+
4
+ module SimpleCovHelper
5
+ def start_simple_cov(name)
6
+ SimpleCov.start do
7
+ add_filter '/spec/'
8
+ add_filter '/lib/generators'
9
+ command_name name
10
+ formatter SimpleCov::Formatter::QualityFormatter
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ class SimpleCov::Formatter::QualityFormatter
2
+ def format(result)
3
+ SimpleCov::Formatter::HTMLFormatter.new.format(result)
4
+ File.open("coverage/covered_percent", "w") do |f|
5
+ f.puts result.source_files.covered_percent.to_f
6
+ end
7
+ end
8
+ end
data/spec/tmp/.gitkeep ADDED
File without changes
@@ -0,0 +1,29 @@
1
+ require File.expand_path("spec/unit_spec_helper")
2
+
3
+ describe Rapns::App do
4
+ it 'does not validate an app with an invalid certificate' do
5
+ app = Rapns::Apns::App.new(:name => 'test', :environment => 'development', :certificate => 'foo')
6
+ app.valid?
7
+ app.errors[:certificate].should == 'Certificate value must contain a certificate and a private key.'
8
+ end
9
+
10
+ it 'validates a certificate without a password' do
11
+ app = Rapns::Apns::App.new :name => 'test', :environment => 'development', :certificate => TEST_CERT
12
+ app.valid?
13
+ app.errors[:certificate].should be_nil
14
+ end
15
+
16
+ it 'validates a certificate with a password' do
17
+ app = Rapns::Apns::App.new :name => 'test', :environment => 'development',
18
+ :certificate => TEST_CERT_WITH_PASSWORD, :password => 'fubar'
19
+ app.valid?
20
+ app.errors[:certificate].should be_nil
21
+ end
22
+
23
+ it 'validates a certificate with an incorrect password' do
24
+ app = Rapns::Apns::App.new :name => 'test', :environment => 'development',
25
+ :certificate => TEST_CERT_WITH_PASSWORD, :password => 'incorrect'
26
+ app.valid?
27
+ app.errors[:certificate].should == "Certificate value must contain a certificate and a private key."
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ require File.expand_path("spec/unit_spec_helper")
2
+
3
+ describe Rapns::Apns::Feedback do
4
+ it "should validate the format of the device_token" do
5
+ notification = Rapns::Apns::Feedback.new(:device_token => "{$%^&*()}")
6
+ notification.valid?.should be_false
7
+ notification.errors[:device_token].include?("is invalid").should be_true
8
+ end
9
+ end
@@ -0,0 +1,215 @@
1
+ # encoding: US-ASCII
2
+
3
+ require File.expand_path("spec/unit_spec_helper")
4
+ require 'spec/unit/notification_shared.rb'
5
+
6
+ describe Rapns::Apns::Notification do
7
+ it_should_behave_like 'an Notification subclass'
8
+
9
+ let(:notification_class) { Rapns::Apns::Notification }
10
+ let(:notification) { notification_class.new }
11
+ let(:data_setter) { 'attributes_for_device=' }
12
+ let(:data_getter) { 'attributes_for_device' }
13
+
14
+ it "should validate the format of the device_token" do
15
+ notification = Rapns::Apns::Notification.new(:device_token => "{$%^&*()}")
16
+ notification.valid?.should be_false
17
+ notification.errors[:device_token].include?("is invalid").should be_true
18
+ end
19
+
20
+ it "should validate the length of the binary conversion of the notification" do
21
+ notification.device_token = "a" * 64
22
+ notification.alert = "way too long!" * 100
23
+ notification.valid?.should be_false
24
+ notification.errors[:base].include?("APN notification cannot be larger than 256 bytes. Try condensing your alert and device attributes.").should be_true
25
+ end
26
+
27
+ it "should default the sound to 'default'" do
28
+ notification.sound.should == 'default'
29
+ end
30
+
31
+ it "should default the expiry to 1 day" do
32
+ notification.expiry.should == 1.day.to_i
33
+ end
34
+ end
35
+
36
+ describe Rapns::Apns::Notification, "when assigning the device token" do
37
+ it "should strip spaces from the given string" do
38
+ notification = Rapns::Apns::Notification.new(:device_token => "o m g")
39
+ notification.device_token.should == "omg"
40
+ end
41
+
42
+ it "should strip chevrons from the given string" do
43
+ notification = Rapns::Apns::Notification.new(:device_token => "<omg>")
44
+ notification.device_token.should == "omg"
45
+ end
46
+ end
47
+
48
+ describe Rapns::Apns::Notification, "as_json" do
49
+ it "should include the alert if present" do
50
+ notification = Rapns::Apns::Notification.new(:alert => "hi mom")
51
+ notification.as_json["aps"]["alert"].should == "hi mom"
52
+ end
53
+
54
+ it "should not include the alert key if the alert is not present" do
55
+ notification = Rapns::Apns::Notification.new(:alert => nil)
56
+ notification.as_json["aps"].key?("alert").should be_false
57
+ end
58
+
59
+ it "should encode the alert as JSON if it is a Hash" do
60
+ notification = Rapns::Apns::Notification.new(:alert => { 'body' => "hi mom", 'alert-loc-key' => "View" })
61
+ notification.as_json["aps"]["alert"].should == { 'body' => "hi mom", 'alert-loc-key' => "View" }
62
+ end
63
+
64
+ it "should include the badge if present" do
65
+ notification = Rapns::Apns::Notification.new(:badge => 6)
66
+ notification.as_json["aps"]["badge"].should == 6
67
+ end
68
+
69
+ it "should not include the badge key if the badge is not present" do
70
+ notification = Rapns::Apns::Notification.new(:badge => nil)
71
+ notification.as_json["aps"].key?("badge").should be_false
72
+ end
73
+
74
+ it "should include the sound if present" do
75
+ notification = Rapns::Apns::Notification.new(:alert => "my_sound.aiff")
76
+ notification.as_json["aps"]["alert"].should == "my_sound.aiff"
77
+ end
78
+
79
+ it "should not include the sound key if the sound is not present" do
80
+ notification = Rapns::Apns::Notification.new(:sound => false)
81
+ notification.as_json["aps"].key?("sound").should be_false
82
+ end
83
+
84
+ it "should include attributes for the device" do
85
+ notification = Rapns::Apns::Notification.new
86
+ notification.attributes_for_device = {:omg => :lol, :wtf => :dunno}
87
+ notification.as_json["omg"].should == "lol"
88
+ notification.as_json["wtf"].should == "dunno"
89
+ end
90
+
91
+ it "should allow attributes to include a hash" do
92
+ notification = Rapns::Apns::Notification.new
93
+ notification.attributes_for_device = {:omg => {:ilike => :hashes}}
94
+ notification.as_json["omg"]["ilike"].should == "hashes"
95
+ end
96
+
97
+ end
98
+
99
+ describe Rapns::Apns::Notification, 'MDM' do
100
+ let(:magic) { 'abc123' }
101
+ let(:notification) { Rapns::Apns::Notification.new }
102
+
103
+ it 'includes the mdm magic in the payload' do
104
+ notification.mdm = magic
105
+ notification.as_json.should == {'mdm' => magic}
106
+ end
107
+
108
+ it 'does not include aps attribute' do
109
+ notification.alert = "i'm doomed"
110
+ notification.mdm = magic
111
+ notification.as_json.key?('aps').should be_false
112
+ end
113
+ end
114
+
115
+ describe Rapns::Apns::Notification, 'content-available' do
116
+ let(:notification) { Rapns::Apns::Notification.new }
117
+
118
+ it 'includes content-available in the payload' do
119
+ notification.content_available = true
120
+ notification.as_json['aps']['content-available'].should == 1
121
+ end
122
+
123
+ it 'does not include content-available in the payload if not set' do
124
+ notification.as_json['aps'].key?('content-available').should be_false
125
+ end
126
+
127
+ it 'does not include content-available as a non-aps attribute' do
128
+ notification.content_available = true
129
+ notification.as_json.key?('content-available').should be_false
130
+ end
131
+
132
+ it 'does not overwrite existing attributes for the device' do
133
+ notification.data = {:hi => :mom}
134
+ notification.content_available = true
135
+ notification.as_json['aps']['content-available'].should == 1
136
+ notification.as_json['hi'].should == 'mom'
137
+ end
138
+
139
+ it 'does not overwrite the content-available flag when setting attributes for the device' do
140
+ notification.content_available = true
141
+ notification.data = {:hi => :mom}
142
+ notification.as_json['aps']['content-available'].should == 1
143
+ notification.as_json['hi'].should == 'mom'
144
+ end
145
+
146
+ end
147
+
148
+ describe Rapns::Apns::Notification, "to_binary" do
149
+ it "should correctly convert the notification to binary" do
150
+ notification = Rapns::Apns::Notification.new
151
+ notification.device_token = "a" * 64
152
+ notification.sound = "1.aiff"
153
+ notification.badge = 3
154
+ notification.alert = "Don't panic Mr Mainwaring, don't panic!"
155
+ notification.attributes_for_device = {:hi => :mom}
156
+ notification.expiry = 86400 # 1 day, \x00\x01Q\x80
157
+ notification.app = Rapns::Apns::App.create!(:name => 'my_app', :environment => 'development', :certificate => TEST_CERT)
158
+ notification.save!
159
+ notification.stub(:id).and_return(1234)
160
+ notification.to_binary.should == "\x01\x00\x00\x04\xD2\x00\x01Q\x80\x00 \xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\x00a{\"aps\":{\"alert\":\"Don't panic Mr Mainwaring, don't panic!\",\"badge\":3,\"sound\":\"1.aiff\"},\"hi\":\"mom\"}"
161
+ end
162
+ end
163
+
164
+ describe Rapns::Apns::Notification, "bug #31" do
165
+ it 'does not confuse a JSON looking string as JSON' do
166
+ notification = Rapns::Apns::Notification.new
167
+ notification.alert = "{\"one\":2}"
168
+ notification.alert.should == "{\"one\":2}"
169
+ end
170
+
171
+ it 'does confuse a JSON looking string as JSON if the alert_is_json attribute is not present' do
172
+ notification = Rapns::Apns::Notification.new
173
+ notification.stub(:has_attribute? => false)
174
+ notification.alert = "{\"one\":2}"
175
+ notification.alert.should == {"one" => 2}
176
+ end
177
+ end
178
+
179
+ describe Rapns::Apns::Notification, "bug #35" do
180
+ it "should limit payload size to 256 bytes but not the entire packet" do
181
+ notification = Rapns::Apns::Notification.new do |n|
182
+ n.device_token = "a" * 64
183
+ n.alert = "a" * 210
184
+ n.app = Rapns::Apns::App.create!(:name => 'my_app', :environment => 'development', :certificate => TEST_CERT)
185
+ end
186
+
187
+ notification.to_binary(:for_validation => true).bytesize.should > 256
188
+ notification.payload_size.should < 256
189
+ notification.should be_valid
190
+ end
191
+ end
192
+
193
+ describe Rapns::Apns::Notification, "multi_json usage" do
194
+ describe Rapns::Apns::Notification, "alert" do
195
+ it "should call MultiJson.load when multi_json version is 1.3.0" do
196
+ Object.stub_constants(:MultiJson => mock) do
197
+ MultiJson.should_receive(:encode).with(any_args())
198
+ MultiJson.should_receive(:load).with(any_args())
199
+ notification = Rapns::Apns::Notification.new(:alert => { :a => 1 }, :alert_is_json => true)
200
+ Gem.stub(:loaded_specs).and_return( { 'multi_json' => Gem::Specification.new('multi_json', '1.3.0') } )
201
+ notification.alert
202
+ end
203
+ end
204
+
205
+ it "should call MultiJson.decode when multi_json version is 1.2.9" do
206
+ Object.stub_constants(:MultiJson => mock) do
207
+ MultiJson.should_receive(:encode).with(any_args())
208
+ MultiJson.should_receive(:decode).with(any_args())
209
+ notification = Rapns::Apns::Notification.new(:alert => { :a => 1 }, :alert_is_json => true)
210
+ Gem.stub(:loaded_specs).and_return( { 'multi_json' => Gem::Specification.new('multi_json', '1.2.9') } )
211
+ notification.alert
212
+ end
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,21 @@
1
+ require File.expand_path("spec/unit_spec_helper")
2
+
3
+ describe Rapns, 'apns_feedback' do
4
+ let!(:app) { Rapns::Apns::App.create!(:name => 'test', :environment => 'production', :certificate => TEST_CERT) }
5
+ let(:receiver) { double(:check_for_feedback => nil) }
6
+
7
+ before do
8
+ Rapns::Daemon::Apns::FeedbackReceiver.stub(:new => receiver)
9
+ end
10
+
11
+ it 'initializes the store' do
12
+ Rapns::Daemon.should_receive(:initialize_store)
13
+ Rapns.apns_feedback
14
+ end
15
+
16
+ it 'checks feedback for each app' do
17
+ Rapns::Daemon::Apns::FeedbackReceiver.should_receive(:new).with(app, 0).and_return(receiver)
18
+ receiver.should_receive(:check_for_feedback)
19
+ Rapns.apns_feedback
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ require File.expand_path("spec/unit_spec_helper")
2
+
3
+ describe Rapns::App do
4
+ it 'validates the uniqueness of name within type and environment' do
5
+ Rapns::Apns::App.create!(:name => 'test', :environment => 'production', :certificate => TEST_CERT)
6
+ app = Rapns::Apns::App.new(:name => 'test', :environment => 'production', :certificate => TEST_CERT)
7
+ app.valid?.should be_false
8
+ app.errors[:name].should == 'has already been taken'
9
+
10
+ app = Rapns::Apns::App.new(:name => 'test', :environment => 'development', :certificate => TEST_CERT)
11
+ app.valid?.should be_true
12
+
13
+ app = Rapns::Gcm::App.new(:name => 'test', :environment => 'production', :auth_key => TEST_CERT)
14
+ app.valid?.should be_true
15
+ end
16
+ end
@@ -0,0 +1,55 @@
1
+ require File.expand_path("spec/unit_spec_helper")
2
+
3
+ describe Rapns do
4
+ let(:config) { double }
5
+
6
+ before { Rapns.stub(:config => config) }
7
+
8
+ it 'can yields a config block' do
9
+ yielded_args = nil
10
+ Rapns.configure do |*a| yielded_args = a end
11
+ yielded_args.should == [config]
12
+ end
13
+ end
14
+
15
+ describe Rapns::Configuration do
16
+ let(:config) do
17
+ Rapns::Deprecation.muted do
18
+ Rapns::Configuration.new
19
+ end
20
+ end
21
+
22
+ it 'configures a feedback callback' do
23
+ b = Proc.new {}
24
+ Rapns::Deprecation.muted do
25
+ config.on_apns_feedback(&b)
26
+ end
27
+ config.apns_feedback_callback.should == b
28
+ end
29
+
30
+ it 'can be updated' do
31
+ Rapns::Deprecation.muted do
32
+ new_config = Rapns::Configuration.new
33
+ new_config.batch_size = 100
34
+ expect { config.update(new_config) }.to change(config, :batch_size).to(100)
35
+ end
36
+ end
37
+
38
+ it 'sets the pid_file relative if not absolute' do
39
+ Rails.stub(:root => '/rails')
40
+ config.pid_file = 'tmp/rapns.pid'
41
+ config.pid_file.should == '/rails/tmp/rapns.pid'
42
+ end
43
+
44
+ it 'does not alter an absolute pid_file path' do
45
+ config.pid_file = '/tmp/rapns.pid'
46
+ config.pid_file.should == '/tmp/rapns.pid'
47
+ end
48
+
49
+ it 'does not allow foreground to be set to false if the platform is JRuby' do
50
+ config.foreground = true
51
+ Rapns.stub(:jruby? => true)
52
+ config.foreground = false
53
+ config.foreground.should be_true
54
+ end
55
+ end
@@ -0,0 +1,45 @@
1
+ require File.expand_path("spec/unit_spec_helper")
2
+ require File.dirname(__FILE__) + '/../app_runner_shared.rb'
3
+
4
+ describe Rapns::Daemon::Apns::AppRunner do
5
+ it_should_behave_like 'an AppRunner subclass'
6
+
7
+ let(:app_class) { Rapns::Apns::App }
8
+ let(:app) { app_class.create!(:name => 'my_app', :environment => 'development',
9
+ :certificate => TEST_CERT, :password => 'pass') }
10
+ let(:runner) { Rapns::Daemon::Apns::AppRunner.new(app) }
11
+ let(:handler) { double(:start => nil, :queue= => nil, :wakeup => nil, :wait => nil, :stop => nil) }
12
+ let(:handler_collection) { double(:handler_collection, :push => nil, :size => 1, :stop => nil) }
13
+ let(:receiver) { double(:start => nil, :stop => nil) }
14
+ let(:config) { double(:feedback_poll => 60, :push => false) }
15
+ let(:logger) { double(:info => nil, :warn => nil, :error => nil) }
16
+
17
+ before do
18
+ Rapns.stub(:logger => logger, :config => config)
19
+ Rapns::Daemon::Apns::DeliveryHandler.stub(:new => handler)
20
+ Rapns::Daemon::DeliveryHandlerCollection.stub(:new => handler_collection)
21
+ Rapns::Daemon::Apns::FeedbackReceiver.stub(:new => receiver)
22
+ end
23
+
24
+ it 'instantiates a new feedback receiver when started' do
25
+ Rapns::Daemon::Apns::FeedbackReceiver.should_receive(:new).with(app, 60)
26
+ runner.start
27
+ end
28
+
29
+ it 'starts the feedback receiver' do
30
+ receiver.should_receive(:start)
31
+ runner.start
32
+ end
33
+
34
+ it 'stops the feedback receiver' do
35
+ runner.start
36
+ receiver.should_receive(:stop)
37
+ runner.stop
38
+ end
39
+
40
+ it 'does not check for feedback when in push mode' do
41
+ config.stub(:push => true)
42
+ Rapns::Daemon::Apns::FeedbackReceiver.should_not_receive(:new)
43
+ runner.start
44
+ end
45
+ end
@@ -0,0 +1,11 @@
1
+ require File.expand_path("spec/unit_spec_helper")
2
+
3
+ describe Rapns::Apns::CertificateExpiredError do
4
+ let(:app) { double(:name => 'test') }
5
+ let(:error) { Rapns::Apns::CertificateExpiredError.new(app, Time.now) }
6
+
7
+ it 'returns a message' do
8
+ error.message
9
+ error.to_s
10
+ end
11
+ end