diff options
author | 2010-08-05 11:42:19 +0800 | |
---|---|---|
committer | 2010-08-09 07:36:21 +0200 | |
commit | ebd7fc4f18f1e342d245271eeb2ab47045a733af (patch) | |
tree | aa0161fc8bebf5fe03bbd08cfd85c3f87e092972 | |
parent | Add project instruction to README and use markdown (diff) | |
download | council-webapp-ebd7fc4f18f1e342d245271eeb2ab47045a733af.tar.gz council-webapp-ebd7fc4f18f1e342d245271eeb2ab47045a733af.tar.bz2 council-webapp-ebd7fc4f18f1e342d245271eeb2ab47045a733af.zip |
Infrastructure for sending and testing email
Configured sendmail, added delayed_job and email_spec to send and test email
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | Rakefile | 6 | ||||
-rw-r--r-- | app/models/user_mailer.rb | 6 | ||||
-rw-r--r-- | config/config.yml.sample | 9 | ||||
-rw-r--r-- | config/environment.rb | 12 | ||||
-rw-r--r-- | config/environments/test.rb | 3 | ||||
-rw-r--r-- | config/initializers/load_config.rb | 1 | ||||
-rw-r--r-- | db/migrate/20100618142500_create_delayed_jobs.rb | 21 | ||||
-rw-r--r-- | features/step_definitions/email_steps.rb | 182 | ||||
-rw-r--r-- | features/support/env.rb | 1 | ||||
-rwxr-xr-x | script/delayed_job | 5 | ||||
-rw-r--r-- | spec/models/user_mailer_spec.rb | 14 | ||||
-rw-r--r-- | spec/spec_helper.rb | 1 |
14 files changed, 260 insertions, 4 deletions
@@ -12,3 +12,4 @@ db/*.sqlite3 nbproject *.swp db/schema.rb +config/config.yml @@ -30,6 +30,8 @@ before running any testing, please prepare the necessary config files: >cp config/database.yml.sample config/database.yml +>cp config/config.yml.sample config/config.yml + to run both cucumber and spec tests: @@ -12,3 +12,9 @@ require 'tasks/rails' require 'hobo/tasks/rails' task :default => [:spec, :cucumber] + +begin + require 'delayed/tasks' +rescue LoadError + STDERR.puts 'Run rake gems:install to install delayed_job' +end diff --git a/app/models/user_mailer.rb b/app/models/user_mailer.rb index f42ee62..2aa7481 100644 --- a/app/models/user_mailer.rb +++ b/app/models/user_mailer.rb @@ -1,12 +1,12 @@ class UserMailer < ActionMailer::Base def forgot_password(user, key) - host = Hobo::Controller.request_host - app_name = Hobo::Controller.app_name || host + host = configatron.host + app_name = configatron.app_name @subject = "#{app_name} -- forgotten password" @body = { :user => user, :key => key, :host => host, :app_name => app_name } @recipients = user.email_address - @from = "no-reply@#{host}" + @from = configatron.email.from @sent_on = Time.now @headers = {} end diff --git a/config/config.yml.sample b/config/config.yml.sample new file mode 100644 index 0000000..cde302c --- /dev/null +++ b/config/config.yml.sample @@ -0,0 +1,9 @@ +# Sample file for config.yml +# access using configatron.site_name + +app_name: Council Webapp +host: gentoo.org +email: + from: no-reply@gentoo.org + sendmail_location: /usr/sbin/sendmail + sendmail_arguments: -i -t diff --git a/config/environment.rb b/config/environment.rb index c900d29..0786679 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -8,6 +8,9 @@ require File.join(File.dirname(__FILE__), 'boot') Rails::Initializer.run do |config| config.gem 'hobo' + config.gem 'delayed_job' + # to easily fetch configs + config.gem 'configatron' # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers @@ -40,4 +43,11 @@ Rails::Initializer.run do |config| # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')] # config.i18n.default_locale = :de -end
\ No newline at end of file +end + +# email configuration +ActionMailer::Base.delivery_method = :sendmail +ActionMailer::Base.sendmail_settings = { + :location => configatron.email.sendmail_location, + :arguments => configatron.email.sendmail_arguments +} diff --git a/config/environments/test.rb b/config/environments/test.rb index 3cae1a7..1e722c7 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -26,3 +26,6 @@ config.action_mailer.delivery_method = :test # This is necessary if your schema can't be completely dumped by the schema dumper, # like if you have constraints or database-specific column types # config.active_record.schema_format = :sql +# +# require gems +config.gem 'email_spec', :lib => 'email_spec', :version => '<1.0.0' diff --git a/config/initializers/load_config.rb b/config/initializers/load_config.rb new file mode 100644 index 0000000..5f8a7bb --- /dev/null +++ b/config/initializers/load_config.rb @@ -0,0 +1 @@ +configatron.configure_from_yaml("config/config.yml") diff --git a/db/migrate/20100618142500_create_delayed_jobs.rb b/db/migrate/20100618142500_create_delayed_jobs.rb new file mode 100644 index 0000000..ac579df --- /dev/null +++ b/db/migrate/20100618142500_create_delayed_jobs.rb @@ -0,0 +1,21 @@ +class CreateDelayedJobs < ActiveRecord::Migration + def self.up + create_table :delayed_jobs, :force => true do |table| + table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue + table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually. + table.text :handler # YAML-encoded string of the object that will do work + table.text :last_error # reason for last failure (See Note below) + table.datetime :run_at # When to run. Could be Time.zone.now for immediately, or sometime in the future. + table.datetime :locked_at # Set when a client is working on this object + table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead) + table.string :locked_by # Who is working on this object (if locked) + table.timestamps + end + + add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority' + end + + def self.down + drop_table :delayed_jobs + end +end
\ No newline at end of file diff --git a/features/step_definitions/email_steps.rb b/features/step_definitions/email_steps.rb new file mode 100644 index 0000000..cacd1e3 --- /dev/null +++ b/features/step_definitions/email_steps.rb @@ -0,0 +1,182 @@ +# Commonly used email steps +# +# To add your own steps make a custom_email_steps.rb +# The provided methods are: +# +# last_email_address +# reset_mailer +# open_last_email +# visit_in_email +# unread_emails_for +# mailbox_for +# current_email +# open_email +# read_emails_for +# find_email +# +# General form for email scenarios are: +# - clear the email queue (done automatically by email_spec) +# - execute steps that sends an email +# - check the user received an/no/[0-9] emails +# - open the email +# - inspect the email contents +# - interact with the email (e.g. click links) +# +# The Cucumber steps below are setup in this order. + +module EmailHelpers + def current_email_address + # Replace with your a way to find your current email. e.g @current_user.email + # last_email_address will return the last email address used by email spec to find an email. + # Note that last_email_address will be reset after each Scenario. + last_email_address || "example@example.com" + end +end + +World(EmailHelpers) + +# +# Reset the e-mail queue within a scenario. +# This is done automatically before each scenario. +# + +Given /^(?:a clear email queue|no emails have been sent)$/ do + reset_mailer +end + +# +# Check how many emails have been sent/received +# + +Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails?$/ do |address, amount| + unread_emails_for(address).size.should == parse_email_count(amount) +end + +Then /^(?:I|they|"([^"]*?)") should have (an|no|\d+) emails?$/ do |address, amount| + mailbox_for(address).size.should == parse_email_count(amount) +end + +Then /^(?:I|they|"([^"]*?)") should receive (an|no|\d+) emails? with subject "([^"]*?)"$/ do |address, amount, subject| + unread_emails_for(address).select { |m| m.subject =~ Regexp.new(subject) }.size.should == parse_email_count(amount) +end + +Then /^(?:I|they|"([^"]*?)") should receive an email with the following body:$/ do |address, expected_body| + open_email(address, :with_text => expected_body) +end + +# +# Accessing emails +# + +# Opens the most recently received email +When /^(?:I|they|"([^"]*?)") opens? the email$/ do |address| + open_email(address) +end + +When /^(?:I|they|"([^"]*?)") opens? the email with subject "([^"]*?)"$/ do |address, subject| + open_email(address, :with_subject => subject) +end + +When /^(?:I|they|"([^"]*?)") opens? the email with text "([^"]*?)"$/ do |address, text| + open_email(address, :with_text => text) +end + +# +# Inspect the Email Contents +# + +Then /^(?:I|they) should see "([^"]*?)" in the email subject$/ do |text| + current_email.should have_subject(text) +end + +Then /^(?:I|they) should see \/([^"]*?)\/ in the email subject$/ do |text| + current_email.should have_subject(Regexp.new(text)) +end + +Then /^(?:I|they) should see "([^"]*?)" in the email body$/ do |text| + current_email.body.should include(text) +end + +Then /^(?:I|they) should see \/([^"]*?)\/ in the email body$/ do |text| + current_email.body.should =~ Regexp.new(text) +end + +Then /^(?:I|they) should see the email delivered from "([^"]*?)"$/ do |text| + current_email.should be_delivered_from(text) +end + +Then /^(?:I|they) should see "([^\"]*)" in the email "([^"]*?)" header$/ do |text, name| + current_email.should have_header(name, text) +end + +Then /^(?:I|they) should see \/([^\"]*)\/ in the email "([^"]*?)" header$/ do |text, name| + current_email.should have_header(name, Regexp.new(text)) +end + +# +# Inspect the Email Attachments +# + +Then /^(?:I|they) should see (an|no|\d+) attachments? with the email$/ do |amount| + current_email_attachments.size.should == parse_email_count(amount) +end + +Then /^there should be (an|no|\d+) attachments? named "([^"]*?)"$/ do |amount, filename| + current_email_attachments.select { |a| a.original_filename == filename }.size.should == parse_email_count(amount) +end + +Then /^attachment (\d+) should be named "([^"]*?)"$/ do |index, filename| + current_email_attachments[(index.to_i - 1)].original_filename.should == filename +end + +Then /^there should be (an|no|\d+) attachments? of type "([^"]*?)"$/ do |amount, content_type| + current_email_attachments.select { |a| a.content_type == content_type }.size.should == parse_email_count(amount) +end + +Then /^attachment (\d+) should be of type "([^"]*?)"$/ do |index, content_type| + current_email_attachments[(index.to_i - 1)].content_type.should == content_type +end + +Then /^all attachments should not be blank$/ do + current_email_attachments.each do |attachment| + attachment.size.should_not == 0 + end +end + +Then /^show me a list of email attachments$/ do + EmailSpec::EmailViewer::save_and_open_email_attachments_list(current_email) +end + +# +# Interact with Email Contents +# + +When /^(?:I|they) follow "([^"]*?)" in the email$/ do |link| + visit_in_email(link) +end + +When /^(?:I|they) click the first link in the email$/ do + click_first_link_in_email +end + +# +# Debugging +# These only work with Rails and OSx ATM since EmailViewer uses RAILS_ROOT and OSx's 'open' command. +# Patches accepted. ;) +# + +Then /^save and open current email$/ do + EmailSpec::EmailViewer::save_and_open_email(current_email) +end + +Then /^save and open all text emails$/ do + EmailSpec::EmailViewer::save_and_open_all_text_emails +end + +Then /^save and open all html emails$/ do + EmailSpec::EmailViewer::save_and_open_all_html_emails +end + +Then /^save and open all raw emails$/ do + EmailSpec::EmailViewer::save_and_open_all_raw_emails +end diff --git a/features/support/env.rb b/features/support/env.rb index e684386..c9c899a 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -53,6 +53,7 @@ Spork.prefork do require 'cucumber/rails/active_record' require 'cucumber/web/tableish' + require 'email_spec/cucumber' require 'webrat' require 'webrat/core/matchers' diff --git a/script/delayed_job b/script/delayed_job new file mode 100755 index 0000000..edf1959 --- /dev/null +++ b/script/delayed_job @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby + +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment')) +require 'delayed/command' +Delayed::Command.new(ARGV).daemonize diff --git a/spec/models/user_mailer_spec.rb b/spec/models/user_mailer_spec.rb new file mode 100644 index 0000000..e5852f3 --- /dev/null +++ b/spec/models/user_mailer_spec.rb @@ -0,0 +1,14 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe UserMailer do + include EmailSpec::Helpers + include EmailSpec::Matchers + include ActionController::UrlWriter + + it "should send email" do + # We didn't forget password + # Just need to make sure sendmail works + @email = UserMailer.create_forgot_password(users(:council_member), 'dddd') + @email.should deliver_to(users(:council_member).email_address) + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8030ac9..c28a659 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,6 +4,7 @@ ENV["RAILS_ENV"] ||= 'test' require File.expand_path(File.join(File.dirname(__FILE__),'..','config','environment')) require 'spec/autorun' require 'spec/rails' +require 'email_spec' # Uncomment the next line to use webrat's matchers #require 'webrat/integrations/rspec-rails' |