From a50d3e2e139ece7aada4b885e8ae575630c318b3 Mon Sep 17 00:00:00 2001 From: Mark Bates Date: Thu, 23 Jul 2009 16:59:08 -0400 Subject: [PATCH] Added APN::Notification.send_notifications method and tests for it. --- lib/apn_on_rails/apn_on_rails.rb | 20 +++++++++ .../app/models/apn/notification.rb | 27 +++++++++++- ...20090723132059_create_apn_notifications.rb | 1 - spec/active_record/setup_ar.rb | 3 +- .../app/models/apn/notification_spec.rb | 41 +++++++++++++++++++ spec/factories/notification_factory.rb | 12 +----- .../apple_push_notification_development.pem | 19 +++++++++ spec/spec_helper.rb | 6 +++ 8 files changed, 115 insertions(+), 14 deletions(-) create mode 100644 spec/rails_root/config/apple_push_notification_development.pem diff --git a/lib/apn_on_rails/apn_on_rails.rb b/lib/apn_on_rails/apn_on_rails.rb index 03e955d1..b33b4669 100644 --- a/lib/apn_on_rails/apn_on_rails.rb +++ b/lib/apn_on_rails/apn_on_rails.rb @@ -2,6 +2,26 @@ require 'openssl' require 'configatron' +rails_root = File.join(FileUtils.pwd, 'rails_root') +if defined?(RAILS_ROOT) + rails_root = RAILS_ROOT +end + +rails_env = 'development' +if defined?(RAILS_ENV) + rails_env = RAILS_ENV +end + +configatron.apn.set_default(:passphrase, '') +configatron.apn.set_default(:port, 2195) +configatron.apn.set_default(:host, 'gateway.sandbox.push.apple.com') +configatron.apn.set_default(:cert, File.join(rails_root, 'config', 'apple_push_notification_development.pem')) + +if rails_env == 'production' + configatron.apn.set_default(:host, 'gateway.push.apple.com') + configatron.apn.set_default(:cert, File.join(rails_root, 'config', 'apple_push_notification_production.pem')) +end + module APN module Errors diff --git a/lib/apn_on_rails/app/models/apn/notification.rb b/lib/apn_on_rails/app/models/apn/notification.rb index daf05760..b017aa06 100644 --- a/lib/apn_on_rails/app/models/apn/notification.rb +++ b/lib/apn_on_rails/app/models/apn/notification.rb @@ -51,4 +51,29 @@ def message_for_sending message end -end \ No newline at end of file + class << self + + def send_notifications(notifications) + cert = File.read(configatron.apn.cert) + ctx = OpenSSL::SSL::SSLContext.new + ctx.key = OpenSSL::PKey::RSA.new(cert, configatron.apn.passphrase) + ctx.cert = OpenSSL::X509::Certificate.new(cert) + + s = TCPSocket.new(configatron.apn.host, configatron.apn.port) + ssl = OpenSSL::SSL::SSLSocket.new(s, ctx) + ssl.sync = true + ssl.connect + + notifications.each do |noty| + ssl.write(noty.message_for_sending) + noty.sent_at = Time.now + noty.save + end + + ssl.close + s.close + end + + end # class << self + +end # APN::Notification \ No newline at end of file diff --git a/lib/apn_on_rails/db/migrate/20090723132059_create_apn_notifications.rb b/lib/apn_on_rails/db/migrate/20090723132059_create_apn_notifications.rb index 02a0b744..6bc1863c 100644 --- a/lib/apn_on_rails/db/migrate/20090723132059_create_apn_notifications.rb +++ b/lib/apn_on_rails/db/migrate/20090723132059_create_apn_notifications.rb @@ -6,7 +6,6 @@ def self.up t.integer :device_id, :null => false t.integer :errors_nb, :default => 0 # used for storing errors from apple feedbacks t.string :device_language, :size => 5 # if you don't want to send localized strings - t.text :payload t.string :sound t.string :alert, :size => 150 t.integer :badge diff --git a/spec/active_record/setup_ar.rb b/spec/active_record/setup_ar.rb index fc911103..6c090277 100644 --- a/spec/active_record/setup_ar.rb +++ b/spec/active_record/setup_ar.rb @@ -6,7 +6,8 @@ ActiveRecord::Base.logger = logger db_file = File.join(File.dirname(__FILE__), 'test.db') -FileUtils.rm(db_file) if File.exists?(db_file) +# FileUtils.rm(db_file) if File.exists?(db_file) +File.open(db_file, 'w') ActiveRecord::Base.establish_connection({ :adapter => 'sqlite3', diff --git a/spec/apn_on_rails/app/models/apn/notification_spec.rb b/spec/apn_on_rails/app/models/apn/notification_spec.rb index acd66069..fa7b977f 100644 --- a/spec/apn_on_rails/app/models/apn/notification_spec.rb +++ b/spec/apn_on_rails/app/models/apn/notification_spec.rb @@ -56,4 +56,45 @@ end + describe 'send_notifications' do + + it 'should send the notifications in an Array' do + + notifications = [NotificationFactory.create, NotificationFactory.create] + notifications.each_with_index do |notify, i| + notify.stub(:message_for_sending).and_return("message-#{i}") + notify.should_receive(:sent_at=).with(instance_of(Time)) + notify.should_receive(:save) + end + + rsa_mock = mock('rsa_mock') + OpenSSL::PKey::RSA.should_receive(:new).with(apn_cert, '').and_return(rsa_mock) + + cert_mock = mock('cert_mock') + OpenSSL::X509::Certificate.should_receive(:new).and_return(cert_mock) + + ctx_mock = mock('ctx_mock') + ctx_mock.should_receive(:key=).with(rsa_mock) + ctx_mock.should_receive(:cert=).with(cert_mock) + OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ctx_mock) + + # TCPSocket.new(configatron.apn.host, configatron.apn.port) + tcp_mock = mock('tcp_mock') + tcp_mock.should_receive(:close) + TCPSocket.should_receive(:new).with('gateway.sandbox.push.apple.com', 2195).and_return(tcp_mock) + + ssl_mock = mock('ssl_mock') + ssl_mock.should_receive(:sync=).with(true) + ssl_mock.should_receive(:connect) + ssl_mock.should_receive(:write).with('message-0') + ssl_mock.should_receive(:write).with('message-1') + ssl_mock.should_receive(:close) + OpenSSL::SSL::SSLSocket.should_receive(:new).with(tcp_mock, ctx_mock).and_return(ssl_mock) + + APN::Notification.send_notifications(notifications) + + end + + end + end \ No newline at end of file diff --git a/spec/factories/notification_factory.rb b/spec/factories/notification_factory.rb index 560e61e8..4c1cf74c 100644 --- a/spec/factories/notification_factory.rb +++ b/spec/factories/notification_factory.rb @@ -19,14 +19,4 @@ def create(options = {}) end -NotificationFactory.create - -# t.integer :device_id, :null => false -# t.integer :errors_nb, :default => 0 # used for storing errors from apple feedbacks -# t.string :device_language, :size => 5 # if you don't want to send localized strings -# t.text :payload -# t.string :sound -# t.integer :badge -# t.text :app_data -# t.datetime :sent_at -# t.timestamps \ No newline at end of file +NotificationFactory.create \ No newline at end of file diff --git a/spec/rails_root/config/apple_push_notification_development.pem b/spec/rails_root/config/apple_push_notification_development.pem new file mode 100644 index 00000000..c7fb513a --- /dev/null +++ b/spec/rails_root/config/apple_push_notification_development.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIBATANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGEwJVUzEN +MAsGA1UECgwEaG9tZTERMA8GA1UECwwIbWFjYmF0ZXMxCzAJBgNVBAMMAkNBMB4X +DTA5MDIyMjE5MDUyOVoXDTEwMDIyMjE5MDUyOVowUzELMAkGA1UEBhMCVVMxDTAL +BgNVBAoMBGhvbWUxETAPBgNVBAsMCG1hY2JhdGVzMQswCQYDVQQLDAJDQTEVMBMG +A1UEAwwMaGVsbG8tc2VydmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCr +LhTbcQc6hpYVeB8O94JzWnS41wZTaHReYe2mAxkIH9gF11Gm/Tejdfy7TboVsVtD +FZ+vrVYPFnnVZG2UNDUkfBvkbCBrFQ8glnAHGRYtDxdFjrLDxm0BOfC58wEtV2cM +hZhiLqjHFuSjHuAlAUshfCfWmKbEeDVtFSDxUMa6iQIDAQABo4GFMIGCMAwGA1Ud +EwEB/wQCMAAwMQYJYIZIAYb4QgENBCQWIlJ1YnkvT3BlblNTTCBHZW5lcmF0ZWQg +Q2VydGlmaWNhdGUwHQYDVR0OBBYEFEIBIEcdhFKPB+QILbsupdz3uD6YMAsGA1Ud +DwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUFAAOCAQEA +dOKP/y/hsdnn2cbYpu2I6r8Lzql52XKa+jOaOT0TyPhmUAz0bFUgA53a202MDhbS +KDVhIkC88KTjyyRwVNnwsrS5JD/IOXIJw/vy9VX14aCymPkup0TQR6ZIicKrjcMS +yhmU5I0+fmsUN4PnayOuT/tJ0giy/x+1L/pgMicS47TvyNLB0vl34FplgmH6zlXv +nS/5phroEJm71DPyDNNzoohZo54YHpGmvEDqjLc6DB+Ihu6/sghmd5dlSPNqsubO +sBQeOyNuscbXo6MXI8uDYrZ/PqAtdzPXBjB7LXvVs69YT4KT7BaO3rqobgfJ0kNU +e7roqj04VUJGmU47qrMLBg== +-----END CERTIFICATE----- diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 137cfd5a..626b7608 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -14,6 +14,8 @@ require f end +configatron.apn.cert = File.expand_path(File.join(File.dirname(__FILE__), 'rails_root', 'config', 'apple_push_notification_development.pem')) + Spec::Runner.configure do |config| config.before(:all) do @@ -44,4 +46,8 @@ def fixture_value(*name) def write_fixture(name, value) File.open(fixture_path(*name), 'w') {|f| f.write(value)} +end + +def apn_cert + File.read(File.join(File.dirname(__FILE__), 'rails_root', 'config', 'apple_push_notification_development.pem')) end \ No newline at end of file