rapns_rails_2 3.4.3

Sign up to get free protection for your applications and to get access to all the features.
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