aboutsummaryrefslogtreecommitdiffstats
path: root/spec/spec_helper.rb
blob: 74a4891c225f371f2300056f9baf7c60f513a788 (plain)
1
2
3
4
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
package FixMyStreet::Script::Reports;

use strict;
use warnings;

use CronFns;
use DateTime::Format::Pg;

use Utils;
use Utils::OpenStreetMap;

use FixMyStreet;
use FixMyStreet::Cobrand;
use FixMyStreet::DB;
use FixMyStreet::Email;
use FixMyStreet::Map;
use FixMyStreet::SendReport;

sub send(;$) {
    my ($site_override) = @_;
    my $rs<
require 'rubygems'
require 'spork'

#uncomment the following line to use spork with the debugger
#require 'spork/ext/ruby-debug'
require 'simplecov'
require 'coveralls'
# Generate coverage locally in html as well as in coveralls.io
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
    SimpleCov::Formatter::HTMLFormatter,
    Coveralls::SimpleCov::Formatter
]
SimpleCov.start('rails') do
    add_filter  'commonlib'
    add_filter  'vendor/plugins'
    add_filter  'lib/attachment_to_html'
    add_filter  'lib/strip_attributes'
    add_filter  'lib/has_tag_string'
    add_filter  'lib/acts_as_xapian'
    add_filter  'lib/themes'
end

Spork.prefork do
  # Loading more in this block will cause your tests to run faster. However,
  # if you change any configuration or code from libraries loaded here, you'll
  # need to restart spork for it take effect.

  # This file is copied to spec/ when you run 'rails generate rspec:install'
  ENV["RAILS_ENV"] ||= 'test'
  require File.expand_path("../../config/environment", __FILE__)
  require 'rspec/rails'
  require 'rspec/autorun'

  # Requires supporting ruby files with custom matchers and macros, etc,
  # in spec/support/ and its subdirectories.
  Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

  # Use test-specific translations
  AlaveteliLocalization.set_default_text_domain('app', File.join(File.dirname(__FILE__), 'fixtures', 'locale'))

  RSpec.configure do |config|
    # ## Mock Framework
    #
    # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
    #
    # config.mock_with :mocha
    # config.mock_with :flexmock
    # config.mock_with :rr

    # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
    config.fixture_path = "#{::Rails.root}/spec/fixtures"

    # The order (!) of this is important thanks to foreign keys
    config.global_fixtures = :users,
                             :public_bodies,
                             :public_body_translations,
                             :public_body_versions,
                             :info_requests,
                             :raw_emails,
                             :incoming_messages,
                             :outgoing_messages,
                             :comments,
                             :info_request_events,
                             :track_things,
                             :has_tag_string_tags,
                             :holidays

    # If you're not using ActiveRecord, or you'd prefer not to run each of your
    # examples within a transaction, remove the following line or assign false
    # instead of true.
    config.use_transactional_fixtures = true

    # If true, the base class of anonymous controllers will be inferred
    # automatically. This will be the default behavior in future versions of
    # rspec-rails.
    config.infer_base_class_for_anonymous_controllers = false

    # Run specs in random order to surface order dependencies. If you find an
    # order dependency and want to debug it, you can fix the order by providing
    # the seed, which is printed after each run.
    #     --seed 1234
    config.order = "random"

    # This is a workaround for a strange thing where ActionMailer::Base.deliveries isn't being
    # cleared out correctly in controller specs. So, do it here for everything.
    config.before(:each) do
      ActionMailer::Base.deliveries = []
    end

    # Any test that messes with the locale needs to restore the state afterwards so that it
    # doesn't interfere with any subsequent tests. This is made more complicated by the
    # ApplicationController#set_gettext_locale which sets the locale and so you may be setting
    # the locale in your tests and not even realising it. So, let's make things easier for
    # ourselves and just always restore the locale for all tests.
    config.after(:each) do
      AlaveteliLocalization.set_locales(AlaveteliConfiguration::available_locales,
                                        AlaveteliConfiguration::default_locale)
    end

    # Turn routing-filter off in functional and unit tests as per
    # https://github.com/svenfuchs/routing-filter/blob/master/README.markdown#testing
    config.before(:each) do
      RoutingFilter.active = false if [:controller, :helper, :model].include? example.metadata[:type]
    end

    config.after(:each) do
      RoutingFilter.active = true if [:controller, :helper, :model].include? example.metadata[:type]
    end

    # This section makes the garbage collector run less often to speed up tests
    last_gc_run = Time.now

    config.before(:each) do
      GC.disable
    end

    config.after(:each) do
      if Time.now - last_gc_run > 4
        GC.enable
        GC.start
        last_gc_run = Time.now
      end
    end
  end

  # TODO: No idea what namespace/class/module to put this in
  # Create a clean xapian index based on the fixture files and the raw_email data.
  def create_fixtures_xapian_index
      load_raw_emails_data
      rebuild_xapian_index
  end

  # Use the before create job hook to simulate a race condition with
  # another process by creating an acts_as_xapian_job record for the
  # same model:
  def with_duplicate_xapian_job_creation
      InfoRequestEvent.module_eval do
          def xapian_before_create_job_hook(action, model, model_id)
              ActsAsXapian::ActsAsXapianJob.create!(:model => model,
                                                    :model_id => model_id,
                                                    :action => action)
          end
      end
      yield
  ensure
      InfoRequestEvent.module_eval do
          def xapian_before_create_job_hook(action, model, model_id)
          end
      end
  end

  def with_env_tz(new_tz = 'US/Eastern')
    old_tz, ENV['TZ'] = ENV['TZ'], new_tz
    yield
  ensure
    old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
  end

  def with_active_record_default_timezone(zone)
    old_zone, ActiveRecord::Base.default_timezone = ActiveRecord::Base.default_timezone, zone
    yield
  ensure
    ActiveRecord::Base.default_timezone = old_zone
  end

  # To test the statistics calculations, it's helpful to have the
  # request fixtures in different states, but changing the fixtures
  # themselves disrupts many other tests.  This function takes a
  # block, and runs that block with the info requests for the
  # Geraldine Quango altered so that one is hidden and there's a
  # successful one.
  def with_hidden_and_successful_requests
    external = info_requests(:external_request)
    chicken = info_requests(:naughty_chicken_request)
    old_external_prominence = external.prominence
    old_chicken_described_state = chicken.described_state
    begin
      external.prominence = 'hidden'
      external.save!
      chicken.described_state = 'successful'
      chicken.save!
      yield
    ensure
      external.prominence = old_external_prominence
      external.save!
      chicken.described_state = old_chicken_described_state
      chicken.save!
    end
  end

  # Reset the default locale, making sure that the previous default locale
  # is also cleared from the fallbacks
  def with_default_locale(locale)
      original_default_locale = I18n.default_locale
      original_fallbacks = I18n.fallbacks
      I18n.fallbacks = nil
      I18n.default_locale = locale
      yield
  ensure
      I18n.fallbacks = original_fallbacks
      I18n.default_locale = original_default_locale
  end

  def basic_auth_login(request, username = nil, password = nil)
      username = AlaveteliConfiguration::admin_username if username.nil?
      password = AlaveteliConfiguration::admin_password if password.nil?
      request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64::encode64("#{username}:#{password}")
  end
end

Spork.each_run do
    FactoryGirl.definition_file_paths = [ Rails.root.join('spec', 'factories') ]
    FactoryGirl.reload
  # This code will be run each time you run your specs.
end

def normalise_whitespace(s)
    s = s.gsub(/\A\s+|\s+\Z/, "")
    s = s.gsub(/\s+/, " ")
    return s
end

RSpec::Matchers.define :be_equal_modulo_whitespace_to do |expected|
  match do |actual|
    normalise_whitespace(actual) == normalise_whitespace(expected)
  end
end
s="w"> } unless ( keys %reporters ) { die 'Report not going anywhere for ID ' . $row->id . '!'; } next if $skip; if ($h{category} eq _('Other')) { $h{category_footer} = _('this type of local problem'); } else { $h{category_footer} = "'" . $h{category} . "'"; } $h{bodies_name} = join(_(' and '), @dear); if ($h{category} eq _('Other')) { $h{multiple} = @dear>1 ? "[ " . _("This email has been sent to both councils covering the location of the problem, as the user did not categorise it; please ignore it if you're not the correct council to deal with the issue, or let us know what category of problem this is so we can add it to our system.") . " ]\n\n" : ''; } else { $h{multiple} = @dear>1 ? "[ " . _("This email has been sent to several councils covering the location of the problem, as the category selected is provided for all of them; please ignore it if you're not the correct council to deal with the issue.") . " ]\n\n" : ''; } $h{missing} = ''; if ($missing) { $h{missing} = '[ ' . sprintf(_('We realise this problem might be the responsibility of %s; however, we don\'t currently have any contact details for them. If you know of an appropriate contact address, please do get in touch.'), $missing) . " ]\n\n"; } if (FixMyStreet->staging_flag('send_reports', 0)) { # on a staging server send emails to ourselves rather than the bodies %reporters = map { $_ => $reporters{$_} } grep { /FixMyStreet::SendReport::Email/ } keys %reporters; unless (%reporters) { %reporters = ( 'FixMyStreet::SendReport::Email' => FixMyStreet::SendReport::Email->new() ); } } # Multiply results together, so one success counts as a success. my $result = -1; my @methods; for my $sender ( keys %reporters ) { debug_print("sending using " . $sender, $row->id) if $debug_mode; $sender = $reporters{$sender}; my $res = $sender->send( $row, \%h ); $result *= $res; push @methods, $sender if !$res; if ( $sender->unconfirmed_counts) { foreach my $e (keys %{ $sender->unconfirmed_counts } ) { foreach my $c (keys %{ $sender->unconfirmed_counts->{$e} }) { $notgot{$e}{$c} += $sender->unconfirmed_counts->{$e}{$c}; } } %note = (%note, %{ $sender->unconfirmed_notes }); } $test_data->{test_req_used} = $sender->open311_test_req_used if FixMyStreet->test_mode && $sender->can('open311_test_req_used'); } # Add the send methods now because e.g. Open311 # send() calls $row->discard_changes foreach (@methods) { $row->add_send_method($_); } unless ($result) { $row->update( { whensent => \'current_timestamp', lastupdate => \'current_timestamp', } ); if ($send_confirmation_email && !$h{anonymous_report}) { $h{sent_confirm_id_ref} = $row->$send_confirmation_email; _send_report_sent_email( $row, \%h, $nomail, $cobrand ); } debug_print("send successful: OK", $row->id) if $debug_mode; } else { my @errors; for my $sender ( keys %reporters ) { unless ( $reporters{ $sender }->success ) { push @errors, $reporters{ $sender }->error; } } $row->update_send_failed( join( '|', @errors ) ); debug_print("send FAILED: " . join( '|', @errors ), $row->id) if $debug_mode; } } if ($debug_mode) { print "\n"; if ($debug_unsent_count) { debug_print("processed all unsent reports (total: $debug_unsent_count)"); } else { debug_print("no unsent reports were found (must have whensent=null and suitable bodies_str & state) -- nothing to send"); } } if ($verbose || $debug_mode) { print "Council email addresses that need checking:\n" if keys %notgot; foreach my $e (keys %notgot) { foreach my $c (keys %{$notgot{$e}}) { print " " . $notgot{$e}{$c} . " problem, to $e category $c (" . $note{$e}{$c}. ")\n"; } } my $sending_errors = ''; my $unsent = $rs->search( { state => [ FixMyStreet::DB::Result::Problem::open_states() ], whensent => undef, bodies_str => { '!=', undef }, send_fail_count => { '>', 0 } } ); while (my $row = $unsent->next) { my $base_url = FixMyStreet->config('BASE_URL'); $sending_errors .= "\n" . '=' x 80 . "\n\n" . "* " . $base_url . "/report/" . $row->id . ", failed " . $row->send_fail_count . " times, last at " . $row->send_fail_timestamp . ", reason " . $row->send_fail_reason . "\n"; } if ($sending_errors) { print "The following reports had problems sending:\n$sending_errors"; } } return $test_data; } sub _send_report_sent_email { my $row = shift; my $h = shift; my $nomail = shift; my $cobrand = shift; # Don't send 'report sent' text return unless $row->user->email_verified; my $contributed_as = $row->get_extra_metadata('contributed_as') || ''; return if $contributed_as eq 'body' || $contributed_as eq 'anonymous_user'; FixMyStreet::Email::send_cron( $row->result_source->schema, 'confirm_report_sent.txt', $h, { To => $row->user->email, }, undef, $nomail, $cobrand, $row->lang, ); } sub debug_print { my $msg = shift; my $id = shift || ''; $id = "report $id: " if $id; print "[] $id$msg\n"; } 1;