diff options
Diffstat (limited to 'spec/mailers')
-rw-r--r-- | spec/mailers/application_mailer_spec.rb | 158 | ||||
-rw-r--r-- | spec/mailers/outgoing_mailer_spec.rb | 140 | ||||
-rw-r--r-- | spec/mailers/request_mailer_spec.rb | 376 | ||||
-rw-r--r-- | spec/mailers/track_mailer_spec.rb | 200 |
4 files changed, 874 insertions, 0 deletions
diff --git a/spec/mailers/application_mailer_spec.rb b/spec/mailers/application_mailer_spec.rb new file mode 100644 index 000000000..d8993f78f --- /dev/null +++ b/spec/mailers/application_mailer_spec.rb @@ -0,0 +1,158 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + + +describe ApplicationMailer do + + context 'when using plugins' do + + def set_base_views + ApplicationMailer.class_eval do + @previous_view_paths = self.view_paths.dup + self.view_paths = [File.join(Rails.root, 'spec', 'fixtures', 'theme_views', 'core')] + end + end + + def add_mail_methods(method_names) + method_names.each{ |method_name| ApplicationMailer.send(:define_method, method_name){} } + end + + def remove_mail_methods(method_names) + method_names.each do |method_name| + if ApplicationMailer.respond_to?(method_name) + ApplicationMailer.send(:remove_method, method_name) + end + end + end + + def prepend_theme_views(theme_name) + ApplicationMailer.class_eval do + prepend_view_path File.join(Rails.root, 'spec', 'fixtures', 'theme_views', theme_name) + end + end + + def append_theme_views(theme_name) + ApplicationMailer.class_eval do + append_view_path File.join(Rails.root, 'spec', 'fixtures', 'theme_views', theme_name) + end + end + + def reset_views + ApplicationMailer.class_eval do + self.view_paths = @previous_view_paths + end + end + + def create_multipart_method(method_name) + ApplicationMailer.send(:define_method, method_name) do + attachments['original.eml'] = 'xxx' + mail + end + end + + before do + set_base_views + add_mail_methods(['simple', 'theme_only', 'core_only', 'neither']) + end + + describe 'when a plugin prepends its mail templates to the view paths' do + + it 'should render a theme template in preference to a core template' do + prepend_theme_views('theme_one') + @mail = ApplicationMailer.simple + @mail.body.should match('Theme simple') + end + + it 'should render the template provided by the theme if no template is available in core' do + prepend_theme_views('theme_one') + @mail = ApplicationMailer.theme_only + @mail.body.should match('Theme only') + end + + it 'should render the template provided by core if there is no theme template' do + prepend_theme_views('theme_one') + @mail = ApplicationMailer.core_only + @mail.body.should match('Core only') + end + + it 'should render an empty body if the template is in neither core nor theme' do + prepend_theme_views('theme_one') + @mail = ApplicationMailer.neither + @mail.body.should be_empty + end + + it 'should render a multipart email using a theme template' do + prepend_theme_views('theme_one') + create_multipart_method('multipart_theme_only') + @mail = ApplicationMailer.multipart_theme_only + @mail.parts.size.should == 2 + message_part = @mail.parts[0].to_s + message_part.should match("Theme multipart") + end + + it 'should render a multipart email using a core template' do + prepend_theme_views('theme_one') + create_multipart_method('multipart_core_only') + @mail = ApplicationMailer.multipart_core_only + @mail.parts.size.should == 2 + message_part = @mail.parts[0].to_s + message_part.should match("Core multipart") + end + + end + + describe 'when a plugin appends its mail templates to the view paths' do + + it 'should render a core template in preference to a theme template' do + append_theme_views('theme_one') + @mail = ApplicationMailer.simple + @mail.body.should match('Core simple') + end + + it 'should render the template provided by the theme if no template is available in core' do + append_theme_views('theme_one') + @mail = ApplicationMailer.theme_only + @mail.body.should match('Theme only') + end + + it 'should render the template provided by core if there is no theme template' do + append_theme_views('theme_one') + @mail = ApplicationMailer.core_only + @mail.body.should match('Core only') + end + + it 'should render an empty body if the template is in neither core nor theme' do + append_theme_views('theme_one') + @mail = ApplicationMailer.neither + @mail.body.should be_empty + end + + it 'should render a multipart email using a core template' do + append_theme_views('theme_one') + create_multipart_method('multipart_core_only') + @mail = ApplicationMailer.multipart_core_only + @mail.parts.size.should == 2 + message_part = @mail.parts[0].to_s + message_part.should match("Core multipart") + end + + it 'should render a multipart email using a theme template' do + append_theme_views('theme_one') + create_multipart_method('multipart_theme_only') + @mail = ApplicationMailer.multipart_theme_only + @mail.parts.size.should == 2 + message_part = @mail.parts[0].to_s + message_part.should match("Theme multipart") + end + + end + + after do + reset_views + remove_mail_methods(['simple', 'theme_only', 'core_only', 'neither', 'multipart']) + end + end + +end + + + diff --git a/spec/mailers/outgoing_mailer_spec.rb b/spec/mailers/outgoing_mailer_spec.rb new file mode 100644 index 000000000..5d1ea2dfb --- /dev/null +++ b/spec/mailers/outgoing_mailer_spec.rb @@ -0,0 +1,140 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe OutgoingMailer, " when working out follow up addresses" do + # This is done with fixtures as the code is a bit tangled with the way it + # calls TMail. XXX untangle it and make these tests spread out and using + # mocks. Put parts of the tests in spec/lib/tmail_extensions.rb + before(:each) do + load_raw_emails_data + end + + it "should parse them right" do + ir = info_requests(:fancy_dog_request) + im = ir.incoming_messages[0] + + # check the basic entry in the fixture is fine + OutgoingMailer.name_and_email_for_followup(ir, im).should == "FOI Person <foiperson@localhost>" + OutgoingMailer.name_for_followup(ir, im).should == "FOI Person" + OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost" + end + + it "should work when there is only an email address" do + ir = info_requests(:fancy_dog_request) + im = ir.incoming_messages[0] + + im.raw_email.data = im.raw_email.data.sub("\"FOI Person\" <foiperson@localhost>", "foiperson@localhost") + im.parse_raw_email! true + + # check the basic entry in the fixture is fine + OutgoingMailer.name_and_email_for_followup(ir, im).should == "foiperson@localhost" + OutgoingMailer.name_for_followup(ir, im).should == "Geraldine Quango" + OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost" + end + + it "should quote funny characters" do + ir = info_requests(:fancy_dog_request) + im = ir.incoming_messages[0] + + im.raw_email.data = im.raw_email.data.sub("FOI Person", "FOI [ Person") + im.parse_raw_email! true + + # check the basic entry in the fixture is fine + OutgoingMailer.name_and_email_for_followup(ir, im).should == "\"FOI [ Person\" <foiperson@localhost>" + OutgoingMailer.name_for_followup(ir, im).should == "FOI [ Person" + OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost" + end + + it "should quote quotes" do + ir = info_requests(:fancy_dog_request) + im = ir.incoming_messages[0] + + im.raw_email.data = im.raw_email.data.sub("FOI Person", "FOI \\\" Person") + im.parse_raw_email! true + + # check the basic entry in the fixture is fine + OutgoingMailer.name_and_email_for_followup(ir, im).should == "\"FOI \\\" Person\" <foiperson@localhost>" + OutgoingMailer.name_for_followup(ir, im).should == "FOI \" Person" + OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost" + end + + it "should quote @ signs" do + ir = info_requests(:fancy_dog_request) + im = ir.incoming_messages[0] + + im.raw_email.data = im.raw_email.data.sub("FOI Person", "FOI @ Person") + im.parse_raw_email! true + + # check the basic entry in the fixture is fine + OutgoingMailer.name_and_email_for_followup(ir, im).should == "\"FOI @ Person\" <foiperson@localhost>" + OutgoingMailer.name_for_followup(ir, im).should == "FOI @ Person" + OutgoingMailer.email_for_followup(ir, im).should == "foiperson@localhost" + end + +end + +describe OutgoingMailer, "when working out follow up subjects" do + + before(:each) do + load_raw_emails_data + end + + it "should prefix the title with 'Freedom of Information request -' for initial requests" do + ir = info_requests(:fancy_dog_request) + im = ir.incoming_messages[0] + + ir.email_subject_request.should == "Freedom of Information request - Why do you have & such a fancy dog?" + end + + it "should use 'Re:' and inital request subject for followups which aren't replies to particular messages" do + ir = info_requests(:fancy_dog_request) + om = outgoing_messages(:useless_outgoing_message) + + OutgoingMailer.subject_for_followup(ir, om).should == "Re: Freedom of Information request - Why do you have & such a fancy dog?" + end + + it "should prefix with Re: the subject of the message being replied to" do + ir = info_requests(:fancy_dog_request) + im = ir.incoming_messages[0] + om = outgoing_messages(:useless_outgoing_message) + om.incoming_message_followup = im + + OutgoingMailer.subject_for_followup(ir, om).should == "Re: Geraldine FOI Code AZXB421" + end + + it "should not add Re: prefix if there already is such a prefix" do + ir = info_requests(:fancy_dog_request) + im = ir.incoming_messages[0] + om = outgoing_messages(:useless_outgoing_message) + om.incoming_message_followup = im + + im.raw_email.data = im.raw_email.data.sub("Subject: Geraldine FOI Code AZXB421", "Subject: Re: Geraldine FOI Code AZXB421") + OutgoingMailer.subject_for_followup(ir, om).should == "Re: Geraldine FOI Code AZXB421" + end + + it "should not add Re: prefix if there already is a lower case re: prefix" do + ir = info_requests(:fancy_dog_request) + im = ir.incoming_messages[0] + om = outgoing_messages(:useless_outgoing_message) + om.incoming_message_followup = im + + im.raw_email.data = im.raw_email.data.sub("Subject: Geraldine FOI Code AZXB421", "Subject: re: Geraldine FOI Code AZXB421") + im.parse_raw_email! true + + OutgoingMailer.subject_for_followup(ir, om).should == "re: Geraldine FOI Code AZXB421" + end + + it "should use 'Re:' and initial request subject when replying to failed delivery notifications" do + ir = info_requests(:fancy_dog_request) + im = ir.incoming_messages[0] + om = outgoing_messages(:useless_outgoing_message) + om.incoming_message_followup = im + + im.raw_email.data = im.raw_email.data.sub("foiperson@localhost", "postmaster@localhost") + im.raw_email.data = im.raw_email.data.sub("Subject: Geraldine FOI Code AZXB421", "Subject: Delivery Failed") + im.parse_raw_email! true + + OutgoingMailer.subject_for_followup(ir, om).should == "Re: Freedom of Information request - Why do you have & such a fancy dog?" + end +end + + diff --git a/spec/mailers/request_mailer_spec.rb b/spec/mailers/request_mailer_spec.rb new file mode 100644 index 000000000..68cef2f0b --- /dev/null +++ b/spec/mailers/request_mailer_spec.rb @@ -0,0 +1,376 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe RequestMailer, " when receiving incoming mail" do + before(:each) do + load_raw_emails_data + ActionMailer::Base.deliveries = [] + end + + it "should append it to the appropriate request" do + ir = info_requests(:fancy_dog_request) + ir.incoming_messages.size.should == 1 # in the fixture + receive_incoming_mail('incoming-request-plain.email', ir.incoming_email) + ir.incoming_messages.size.should == 2 # one more arrives + ir.info_request_events[-1].incoming_message_id.should_not be_nil + + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + mail = deliveries[0] + mail.to.should == [ 'bob@localhost' ] # to the user who sent fancy_dog_request + deliveries.clear + end + + it "should store mail in holding pen and send to admin when the email is not to any information request" do + ir = info_requests(:fancy_dog_request) + ir.incoming_messages.size.should == 1 + InfoRequest.holding_pen_request.incoming_messages.size.should == 0 + receive_incoming_mail('incoming-request-plain.email', 'dummy@localhost') + ir.incoming_messages.size.should == 1 + InfoRequest.holding_pen_request.incoming_messages.size.should == 1 + last_event = InfoRequest.holding_pen_request.incoming_messages[0].info_request.info_request_events.last + last_event.params[:rejected_reason].should == "Could not identify the request from the email address" + + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + mail = deliveries[0] + mail.to.should == [ AlaveteliConfiguration::contact_email ] + deliveries.clear + end + + it "should store mail in holding pen and send to admin when the from email is empty and only authorites can reply" do + ir = info_requests(:fancy_dog_request) + ir.allow_new_responses_from = 'authority_only' + ir.handle_rejected_responses = 'holding_pen' + ir.save! + ir.incoming_messages.size.should == 1 + InfoRequest.holding_pen_request.incoming_messages.size.should == 0 + receive_incoming_mail('incoming-request-plain.email', ir.incoming_email, "") + ir.incoming_messages.size.should == 1 + InfoRequest.holding_pen_request.incoming_messages.size.should == 1 + last_event = InfoRequest.holding_pen_request.incoming_messages[0].info_request.info_request_events.last + last_event.params[:rejected_reason].should =~ /there is no "From" address/ + + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + mail = deliveries[0] + mail.to.should == [ AlaveteliConfiguration::contact_email ] + deliveries.clear + end + + it "should store mail in holding pen and send to admin when the from email is unknown and only authorites can reply" do + ir = info_requests(:fancy_dog_request) + ir.allow_new_responses_from = 'authority_only' + ir.handle_rejected_responses = 'holding_pen' + ir.save! + ir.incoming_messages.size.should == 1 + InfoRequest.holding_pen_request.incoming_messages.size.should == 0 + receive_incoming_mail('incoming-request-plain.email', ir.incoming_email, "frob@nowhere.com") + ir.incoming_messages.size.should == 1 + InfoRequest.holding_pen_request.incoming_messages.size.should == 1 + last_event = InfoRequest.holding_pen_request.incoming_messages[0].info_request.info_request_events.last + last_event.params[:rejected_reason].should =~ /Only the authority can reply/ + + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + mail = deliveries[0] + mail.to.should == [ AlaveteliConfiguration::contact_email ] + deliveries.clear + end + + it "should return incoming mail to sender when a request is stopped fully for spam" do + # mark request as anti-spam + ir = info_requests(:fancy_dog_request) + ir.allow_new_responses_from = 'nobody' + ir.handle_rejected_responses = 'bounce' + ir.save! + + # test what happens if something arrives + ir.incoming_messages.size.should == 1 # in the fixture + receive_incoming_mail('incoming-request-plain.email', ir.incoming_email) + ir.incoming_messages.size.should == 1 # nothing should arrive + + # should be a message back to sender + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + mail = deliveries[0] + mail.to.should == [ 'geraldinequango@localhost' ] + # check attached bounce is good copy of incoming-request-plain.email + mail.multipart?.should == true + mail.parts.size.should == 2 + message_part = mail.parts[0].to_s + bounced_mail = MailHandler.mail_from_raw_email(mail.parts[1].body.to_s) + bounced_mail.to.should == [ ir.incoming_email ] + bounced_mail.from.should == [ 'geraldinequango@localhost' ] + bounced_mail.body.include?("That's so totally a rubbish question").should be_true + message_part.include?("marked to no longer receive responses").should be_true + deliveries.clear + end + + it "should return incoming mail to sender if not authority when a request is stopped for non-authority spam" do + # mark request as anti-spam + ir = info_requests(:fancy_dog_request) + ir.allow_new_responses_from = 'authority_only' + ir.handle_rejected_responses = 'bounce' + ir.save! + + # Test what happens if something arrives from authority domain (@localhost) + ir.incoming_messages.size.should == 1 # in the fixture + receive_incoming_mail('incoming-request-plain.email', ir.incoming_email, "Geraldine <geraldinequango@localhost>") + ir.incoming_messages.size.should == 2 # one more arrives + + # ... should get "responses arrived" message for original requester + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + mail = deliveries[0] + mail.to.should == [ 'bob@localhost' ] # to the user who sent fancy_dog_request + deliveries.clear + + # Test what happens if something arrives from another domain + ir.incoming_messages.size.should == 2 # in fixture and above + receive_incoming_mail('incoming-request-plain.email', ir.incoming_email, "dummy-address@dummy.localhost") + ir.incoming_messages.size.should == 2 # nothing should arrive + + # ... should be a bounce message back to sender + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + mail = deliveries[0] + mail.to.should == [ 'dummy-address@dummy.localhost' ] + deliveries.clear + end + + it "should send all new responses to holding pen if a request is marked to do so" do + # mark request as anti-spam + ir = info_requests(:fancy_dog_request) + ir.allow_new_responses_from = 'nobody' + ir.handle_rejected_responses = 'holding_pen' + ir.save! + + # test what happens if something arrives + ir = info_requests(:fancy_dog_request) + ir.incoming_messages.size.should == 1 + InfoRequest.holding_pen_request.incoming_messages.size.should == 0 + receive_incoming_mail('incoming-request-plain.email', ir.incoming_email) + ir.incoming_messages.size.should == 1 + InfoRequest.holding_pen_request.incoming_messages.size.should == 1 # arrives in holding pen + last_event = InfoRequest.holding_pen_request.incoming_messages[0].info_request.info_request_events.last + last_event.params[:rejected_reason].should =~ /allow new responses from nobody/ + + # should be a message to admin regarding holding pen + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + mail = deliveries[0] + mail.to.should == [ AlaveteliConfiguration::contact_email ] + deliveries.clear + end + + it "should destroy the messages sent to a request if marked to do so" do + ActionMailer::Base.deliveries.clear + # mark request as anti-spam + ir = info_requests(:fancy_dog_request) + ir.allow_new_responses_from = 'nobody' + ir.handle_rejected_responses = 'blackhole' + ir.save! + + # test what happens if something arrives - should be nothing + ir = info_requests(:fancy_dog_request) + ir.incoming_messages.size.should == 1 + InfoRequest.holding_pen_request.incoming_messages.size.should == 0 + receive_incoming_mail('incoming-request-plain.email', ir.incoming_email) + ir.incoming_messages.size.should == 1 + InfoRequest.holding_pen_request.incoming_messages.size.should == 0 + + # should be no messages to anyone + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 0 + end + + + it "should not mutilate long URLs when trying to word wrap them" do + long_url = 'http://www.this.is.quite.a.long.url.flourish.org/there.is.no.way.it.is.short.whatsoever' + body = "This is a message with quite a long URL in it. It also has a paragraph, being this one that has quite a lot of text in it to. Enough to test the wrapping of itself. + +#{long_url} + +And a paragraph afterwards." + wrapped = MySociety::Format.wrap_email_body_by_paragraphs(body) + wrapped.should include(long_url) + end +end + + +describe RequestMailer, "when sending reminders to requesters to classify a response to their request" do + + before do + Time.stub!(:now).and_return(Time.utc(2007, 11, 12, 23, 59)) + @mock_event = mock_model(InfoRequestEvent) + @mock_response = mock_model(IncomingMessage) + @mock_user = mock_model(User) + @mock_request = mock_model(InfoRequest, :get_last_response_event_id => @mock_event.id, + :get_last_response => @mock_response, + :user_id => 2, + :url_title => 'test_title', + :user => @mock_user) + InfoRequest.stub!(:find).and_return([@mock_request]) + mail_mock = mock("mail") + mail_mock.stub(:deliver) + RequestMailer.stub(:new_response_reminder_alert).and_return(mail_mock) + @sent_alert = mock_model(UserInfoRequestSentAlert, :user= =>nil, + :info_request= => nil, + :alert_type= => nil, + :info_request_event_id= => nil, + :save! => true) + UserInfoRequestSentAlert.stub!(:new).and_return(@sent_alert) + end + + def send_alerts + RequestMailer.alert_new_response_reminders_internal(7, 'new_response_reminder_1') + end + + it 'should ask for all requests that are awaiting description and whose latest response is older + than the number of days given and that are not the holding pen' do + expected_conditions = [ "awaiting_description = ? + AND (SELECT created_at + FROM info_request_events + WHERE info_request_events.info_request_id = info_requests.id + AND info_request_events.event_type = 'response' + ORDER BY created_at desc LIMIT 1) < ? + AND url_title != 'holding_pen' + AND user_id IS NOT NULL".split(' ').join(' '), + true, Time.now() - 7.days ] + + # compare the query string ignoring any spacing differences + InfoRequest.should_receive(:find) do |all, query_params| + query_string = query_params[:conditions][0] + query_params[:conditions][0] = query_string.split(' ').join(' ') + query_params[:conditions].should == expected_conditions + query_params[:include].should == [ :user ] + query_params[:order].should == 'info_requests.id' + end.and_return [@mock_request] + + send_alerts + end + + it 'should raise an error if a request does not have a last response event id' do + @mock_request.stub!(:get_last_response_event_id).and_return(nil) + expected_message = "internal error, no last response while making alert new response reminder, request id #{@mock_request.id}" + lambda{ send_alerts }.should raise_error(expected_message) + end + + it 'should check to see if an alert matching the attributes of the one to be sent has already been sent' do + expected_params = {:conditions => [ "alert_type = ? and user_id = ? and info_request_id = ? and info_request_event_id = ?", + 'new_response_reminder_1', 2, @mock_request.id, @mock_event.id]} + UserInfoRequestSentAlert.should_receive(:find).with(:first, expected_params) + send_alerts + end + + describe 'if an alert matching the attributes of the reminder to be sent has already been sent' do + + before do + UserInfoRequestSentAlert.stub!(:find).and_return(mock_model(UserInfoRequestSentAlert)) + end + + it 'should not send the reminder' do + RequestMailer.should_not_receive(:new_response_reminder_alert) + send_alerts + end + + end + + describe 'if no alert matching the attributes of the reminder to be sent has already been sent' do + + before do + UserInfoRequestSentAlert.stub!(:find).and_return(nil) + end + + it 'should store the information that the reminder has been sent' do + mock_sent_alert = mock_model(UserInfoRequestSentAlert) + UserInfoRequestSentAlert.stub!(:new).and_return(mock_sent_alert) + mock_sent_alert.should_receive(:info_request=).with(@mock_request) + mock_sent_alert.should_receive(:user=).with(@mock_user) + mock_sent_alert.should_receive(:alert_type=).with('new_response_reminder_1') + mock_sent_alert.should_receive(:info_request_event_id=).with(@mock_request.get_last_response_event_id) + mock_sent_alert.should_receive(:save!) + send_alerts + end + + it 'should send the reminder' do + RequestMailer.should_receive(:new_response_reminder_alert) + send_alerts + end + end + +end + +describe RequestMailer, 'when sending mail when someone has updated an old unclassified request' do + + before do + @user = mock_model(User, :name_and_email => 'test name and email') + @public_body = mock_model(PublicBody, :name => 'Test public body') + @info_request = mock_model(InfoRequest, :user => @user, + :law_used_full => 'Freedom of Information', + :title => 'Test request', + :public_body => @public_body, + :display_status => 'Refused.', + :url_title => 'test_request') + @mail = RequestMailer.old_unclassified_updated(@info_request) + end + + it 'should have the subject "Someone has updated the status of your request"' do + @mail.subject.should == 'Someone has updated the status of your request' + end + + it 'should tell them what status was picked' do + @mail.body.should match(/"refused."/) + end + + it 'should contain the request path' do + @mail.body.should match(/request\/test_request/) + end + +end + + +describe RequestMailer, 'when sending a new response email' do + + before do + @user = mock_model(User, :name_and_email => 'test name and email') + @public_body = mock_model(PublicBody, :name => 'Test public body') + @info_request = mock_model(InfoRequest, :user => @user, + :law_used_full => 'Freedom of Information', + :title => 'Here is a character that needs quoting …', + :public_body => @public_body, + :display_status => 'Refused.', + :url_title => 'test_request') + @incoming_message = mock_model(IncomingMessage, :info_request => @info_request) + end + + it 'should not error when sending mails requests with characters requiring quoting in the subject' do + @mail = RequestMailer.new_response(@info_request, @incoming_message) + end + +end + +describe RequestMailer, 'requires_admin' do + before(:each) do + user = mock_model(User, :name_and_email => 'Bruce Jones', + :name => 'Bruce Jones') + @info_request = mock_model(InfoRequest, :user => user, + :described_state => 'error_message', + :title => 'Test request', + :url_title => 'test_request', + :law_used_short => 'FOI', + :id => 123) + end + + it 'body should contain the full admin URL' do + mail = RequestMailer.requires_admin(@info_request).deliver + + mail.body.should include('http://test.host/en/admin/request/show/123') + end + + it "body should contain the message from the user" do + mail = RequestMailer.requires_admin(@info_request, nil, "Something has gone wrong").deliver + mail.body.should include 'Something has gone wrong' + end + +end diff --git a/spec/mailers/track_mailer_spec.rb b/spec/mailers/track_mailer_spec.rb new file mode 100644 index 000000000..07f0e073e --- /dev/null +++ b/spec/mailers/track_mailer_spec.rb @@ -0,0 +1,200 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe TrackMailer do + + describe 'when sending email alerts for tracked things' do + + before do + mail_mock = mock("mail") + mail_mock.stub(:deliver) + TrackMailer.stub!(:event_digest).and_return(mail_mock) + Time.stub!(:now).and_return(Time.utc(2007, 11, 12, 23, 59)) + end + + it 'should ask for all the users whose last daily track email was sent more than a day ago' do + expected_conditions = [ "last_daily_track_email < ?", Time.utc(2007, 11, 11, 23, 59)] + User.should_receive(:find).with(:all, :conditions => expected_conditions).and_return([]) + TrackMailer.alert_tracks + end + + describe 'for each user' do + + before do + @user = mock_model(User, :no_xapian_reindex= => false, + :last_daily_track_email= => true, + :save! => true, + :url_name => 'test-name', + :get_locale => 'en', + :should_be_emailed? => true) + User.stub!(:find).and_return([@user]) + @user.stub!(:receive_email_alerts).and_return(true) + @user.stub!(:no_xapian_reindex=) + end + + it 'should ask for any daily track things for the user' do + expected_conditions = [ "tracking_user_id = ? and track_medium = ?", @user.id, 'email_daily' ] + TrackThing.should_receive(:find).with(:all, :conditions => expected_conditions).and_return([]) + TrackMailer.alert_tracks + end + + + it 'should set the no_xapian_reindex flag on the user' do + @user.should_receive(:no_xapian_reindex=).with(true) + TrackMailer.alert_tracks + end + + it 'should update the time of the user\'s last daily tracking email' do + @user.should_receive(:last_daily_track_email=).with(Time.now) + @user.should_receive(:save!) + TrackMailer.alert_tracks + end + it 'should return true' do + TrackMailer.alert_tracks.should == true + end + + + describe 'for each tracked thing' do + + before do + @track_things_sent_emails_array = [] + @track_things_sent_emails_array.stub!(:find).and_return([]) # this is for the date range find (created in last 14 days) + @track_thing = mock_model(TrackThing, :track_query => 'test query', + :track_things_sent_emails => @track_things_sent_emails_array, + :created_at => Time.utc(2007, 11, 9, 23, 59)) + TrackThing.stub!(:find).and_return([@track_thing]) + @track_things_sent_email = mock_model(TrackThingsSentEmail, :save! => true, + :track_thing_id= => true, + :info_request_event_id= => true) + TrackThingsSentEmail.stub!(:new).and_return(@track_things_sent_email) + @xapian_search = mock('xapian search', :results => []) + @found_event = mock_model(InfoRequestEvent, :described_at => @track_thing.created_at + 1.day) + @search_result = {:model => @found_event} + InfoRequest.stub!(:full_search).and_return(@xapian_search) + end + + it 'should ask for the events returned by the tracking query' do + InfoRequest.should_receive(:full_search).with([InfoRequestEvent], 'test query', 'described_at', true, nil, 100, 1).and_return(@xapian_search) + TrackMailer.alert_tracks + end + + it 'should not include in the email any events that the user has already been sent a tracking email about' do + sent_email = mock_model(TrackThingsSentEmail, :info_request_event_id => @found_event.id) + @track_things_sent_emails_array.stub!(:find).and_return([sent_email]) # this is for the date range find (created in last 14 days) + @xapian_search.stub!(:results).and_return([@search_result]) + TrackMailer.should_not_receive(:event_digest) + TrackMailer.alert_tracks + end + + it 'should not include in the email any events not sent in a previous tracking email that were described before the track was set up' do + @found_event.stub!(:described_at).and_return(@track_thing.created_at - 1.day) + @xapian_search.stub!(:results).and_return([@search_result]) + TrackMailer.should_not_receive(:event_digest) + TrackMailer.alert_tracks + end + + it 'should include in the email any events that the user has not been sent a tracking email on that have been described since the track was set up' do + @found_event.stub!(:described_at).and_return(@track_thing.created_at + 1.day) + @xapian_search.stub!(:results).and_return([@search_result]) + TrackMailer.should_receive(:event_digest) + TrackMailer.alert_tracks + end + + it 'should raise an error if a non-event class is returned by the tracking query' do + @xapian_search.stub!(:results).and_return([{:model => 'string class'}]) + lambda{ TrackMailer.alert_tracks }.should raise_error('need to add other types to TrackMailer.alert_tracks (unalerted)') + end + + it 'should record that a tracking email has been sent for each event that has been included in the email' do + @xapian_search.stub!(:results).and_return([@search_result]) + sent_email = mock_model(TrackThingsSentEmail) + TrackThingsSentEmail.should_receive(:new).and_return(sent_email) + sent_email.should_receive(:track_thing_id=).with(@track_thing.id) + sent_email.should_receive(:info_request_event_id=).with(@found_event.id) + sent_email.should_receive(:save!) + TrackMailer.alert_tracks + end + end + + end + + describe 'when a user should not be emailed' do + before do + @user = mock_model(User, :no_xapian_reindex= => false, + :last_daily_track_email= => true, + :save! => true, + :url_name => 'test-name', + :should_be_emailed? => false) + User.stub!(:find).and_return([@user]) + @user.stub!(:receive_email_alerts).and_return(true) + @user.stub!(:no_xapian_reindex=) + end + + it 'should not ask for any daily track things for the user' do + expected_conditions = [ "tracking_user_id = ? and track_medium = ?", @user.id, 'email_daily' ] + TrackThing.should_not_receive(:find).with(:all, :conditions => expected_conditions) + TrackMailer.alert_tracks + end + + it 'should not ask for any daily track things for the user if they have receive_email_alerts off but could otherwise be emailed' do + @user.stub(:should_be_emailed?).and_return(true) + @user.stub(:receive_email_alerts).and_return(false) + expected_conditions = [ "tracking_user_id = ? and track_medium = ?", @user.id, 'email_daily' ] + TrackThing.should_not_receive(:find).with(:all, :conditions => expected_conditions) + TrackMailer.alert_tracks + end + + it 'should not set the no_xapian_reindex flag on the user' do + @user.should_not_receive(:no_xapian_reindex=).with(true) + TrackMailer.alert_tracks + end + + it 'should not update the time of the user\'s last daily tracking email' do + @user.should_not_receive(:last_daily_track_email=).with(Time.now) + @user.should_not_receive(:save!) + TrackMailer.alert_tracks + end + it 'should return false' do + TrackMailer.alert_tracks.should == false + end + end + + end + + describe 'delivering the email' do + + before do + @post_redirect = mock_model(PostRedirect, :save! => true, + :email_token => "token") + PostRedirect.stub!(:new).and_return(@post_redirect) + ActionMailer::Base.deliveries = [] + end + + it 'should deliver one email, with right headers' do + @user = mock_model(User, + :name_and_email => MailHandler.address_from_name_and_email('Tippy Test', 'tippy@localhost'), + :url_name => 'tippy_test' + ) + + TrackMailer.event_digest(@user, []).deliver # no items in it email for minimal test + deliveries = ActionMailer::Base.deliveries + if deliveries.size > 1 # debugging if there is an error + deliveries.each do |d| + $stderr.puts "------------------------------" + $stderr.puts d.body + $stderr.puts "------------------------------" + end + end + deliveries.size.should == 1 + mail = deliveries[0] + + mail['Auto-Submitted'].to_s.should == 'auto-generated' + mail['Precedence'].to_s.should == 'bulk' + + deliveries.clear + end + end + +end + + + |