aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock12
-rw-r--r--app/controllers/admin_controller.rb2
-rw-r--r--app/controllers/application_controller.rb11
-rw-r--r--app/models/incoming_message.rb1
-rw-r--r--app/models/info_request.rb16
-rw-r--r--app/models/outgoing_message.rb5
-rw-r--r--app/models/public_body.rb7
-rw-r--r--app/models/purge_request.rb41
-rw-r--r--app/models/track_thing.rb4
-rw-r--r--app/models/user.rb7
-rw-r--r--config/environment.rb1
-rw-r--r--config/environments/development.rb2
-rw-r--r--config/general.yml-example4
-rw-r--r--config/purge-varnish-debian.ugly81
-rw-r--r--config/test.yml1
-rw-r--r--config/varnish-alaveteli.vcl24
-rw-r--r--db/migrate/111_create_purge_requests.rb14
-rw-r--r--doc/CHANGES.md11
-rw-r--r--lib/quiet_opener.rb34
-rwxr-xr-xscript/purge-varnish11
-rw-r--r--spec/controllers/admin_censor_rule_controller_spec.rb19
-rw-r--r--spec/controllers/request_controller_spec.rb58
-rw-r--r--spec/models/purge_request_spec.rb32
-rw-r--r--spec/models/track_thing_spec.rb2
-rw-r--r--spec/spec_helper.rb3
27 files changed, 387 insertions, 24 deletions
diff --git a/.gitignore b/.gitignore
index 527bccb44..1155b055d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,4 +18,5 @@ TAGS
/public/download
/public/*theme
/vendor/bundle
-.bundle \ No newline at end of file
+.bundle
+bin/ \ No newline at end of file
diff --git a/Gemfile b/Gemfile
index 39469aaf6..29319e41a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -16,6 +16,7 @@ gem 'json', '~> 1.5.1'
gem 'mahoro'
gem 'memcache-client', :require => 'memcache'
gem 'locale', '>= 2.0.5'
+gem 'net-purge'
gem 'rack', '~> 1.1.0'
gem 'rdoc', '~> 2.4.3'
gem 'recaptcha', '~> 0.3.1', :require => 'recaptcha/rails'
@@ -37,3 +38,7 @@ group :test do
gem 'fakeweb'
gem 'rspec-rails', '~> 1.3.4'
end
+
+group :develop do
+ gem 'ruby-debug'
+end
diff --git a/Gemfile.lock b/Gemfile.lock
index 36ef12525..f92be20a9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -17,14 +17,18 @@ GEM
activeresource (2.3.14)
activesupport (= 2.3.14)
activesupport (2.3.14)
+ columnize (0.3.6)
fakeweb (1.3.0)
fast_gettext (0.6.1)
gettext (2.1.0)
locale (>= 2.0.5)
json (1.5.4)
+ linecache (0.46)
+ rbx-require-relative (> 0.0.4)
locale (2.0.5)
mahoro (0.3)
memcache-client (1.8.5)
+ net-purge (0.1.0)
pg (0.11.0)
rack (1.1.0)
rails (2.3.14)
@@ -35,6 +39,7 @@ GEM
activesupport (= 2.3.14)
rake (>= 0.8.3)
rake (0.9.2)
+ rbx-require-relative (0.0.9)
rdoc (2.4.3)
recaptcha (0.3.1)
rmagick (2.13.1)
@@ -44,6 +49,11 @@ GEM
rspec-rails (1.3.4)
rack (>= 1.0.0)
rspec (~> 1.3.1)
+ ruby-debug (0.10.4)
+ columnize (>= 0.1)
+ ruby-debug-base (~> 0.10.4.0)
+ ruby-debug-base (0.10.4)
+ linecache (>= 0.3)
ruby-msg (1.5.0)
ruby-ole (>= 1.2.8)
vpim (>= 0.360)
@@ -64,6 +74,7 @@ DEPENDENCIES
locale (>= 2.0.5)
mahoro
memcache-client
+ net-purge
pg
rack (~> 1.1.0)
rails (= 2.3.14)
@@ -73,6 +84,7 @@ DEPENDENCIES
routing-filter (~> 0.2.4)
rspec (~> 1.3.2)
rspec-rails (~> 1.3.4)
+ ruby-debug
ruby-msg (~> 1.5.0)
vpim
will_paginate (~> 2.3.11)
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb
index adb506b91..1612e5179 100644
--- a/app/controllers/admin_controller.rb
+++ b/app/controllers/admin_controller.rb
@@ -36,6 +36,8 @@ class AdminController < ApplicationController
# also force a search reindexing (so changed text reflected in search)
info_request.reindex_request_events
+ # and remove from varnsi
+ info_request.purge_in_cache
end
# Expire cached attachment files for a user
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 0ec8e206e..0d0cca3e4 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
# controllers/application.rb:
# Parent class of all controllers in FOI site. Filters added to this controller
# apply to all controllers in the application. Likewise, all the methods added
@@ -543,16 +544,6 @@ class ApplicationController < ActionController::Base
return country
end
- def quietly_try_to_open(url)
- begin
- result = open(url).read.strip
- rescue OpenURI::HTTPError, SocketError, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::EHOSTUNREACH
- logger.warn("Unable to open third-party URL #{url}")
- result = ""
- end
- return result
- end
-
# URL generating functions are needed by all controllers (for redirects),
# views (for links) and mailers (for use in emails), so include them into
# all of all.
diff --git a/app/models/incoming_message.rb b/app/models/incoming_message.rb
index cbbcf5aa6..2896de68a 100644
--- a/app/models/incoming_message.rb
+++ b/app/models/incoming_message.rb
@@ -816,7 +816,6 @@ class IncomingMessage < ActiveRecord::Base
:filename => _get_part_file_name(leaf),
:charset => leaf.charset,
:within_rfc822_subject => within_rfc822_subject,
- :display_size => "0K",
:body => body)
attachment.save!
attachments << attachment.id
diff --git a/app/models/info_request.rb b/app/models/info_request.rb
index b5a1cd833..78121f5ea 100644
--- a/app/models/info_request.rb
+++ b/app/models/info_request.rb
@@ -23,6 +23,9 @@
require 'digest/sha1'
class InfoRequest < ActiveRecord::Base
+ include ActionView::Helpers::UrlHelper
+ include ActionController::UrlWriter
+
strip_attributes!
validates_presence_of :title, :message => N_("Please enter a summary of your request")
@@ -453,7 +456,6 @@ public
# An annotation (comment) is made
def add_comment(body, user)
comment = Comment.new
-
ActiveRecord::Base.transaction do
comment.body = body
comment.user = user
@@ -1042,6 +1044,18 @@ public
end
return ret
end
+
+ before_save :purge_in_cache
+ def purge_in_cache
+ if !MySociety::Config.get('VARNISH_HOST').nil? && !self.id.nil?
+ # we only do this for existing info_requests (new ones have a nil id)
+ path = url_for(:controller => 'request', :action => 'show', :url_title => self.url_title, :only_path => true, :locale => :none)
+ req = PurgeRequest.new(:url => path,
+ :model => self.class.base_class.to_s,
+ :model_id => self.id)
+ req.save()
+ end
+ end
end
diff --git a/app/models/outgoing_message.rb b/app/models/outgoing_message.rb
index cc561b21d..de3c916aa 100644
--- a/app/models/outgoing_message.rb
+++ b/app/models/outgoing_message.rb
@@ -267,7 +267,10 @@ class OutgoingMessage < ActiveRecord::Base
end
end
-
+ after_save(:purge_in_cache)
+ def purge_in_cache
+ self.info_request.purge_in_cache
+ end
end
diff --git a/app/models/public_body.rb b/app/models/public_body.rb
index a18af8c69..2a0661fab 100644
--- a/app/models/public_body.rb
+++ b/app/models/public_body.rb
@@ -240,7 +240,7 @@ class PublicBody < ActiveRecord::Base
# Return the short name if present, or else long name
def short_or_long_name
if self.short_name.nil? || self.short_name.empty? # 'nil' can happen during construction
- self.name
+ self.name.nil? ? "" : self.name
else
self.short_name
end
@@ -547,6 +547,11 @@ class PublicBody < ActiveRecord::Base
}
end
+ after_save(:purge_in_cache)
+ def purge_in_cache
+ self.info_requests.each {|x| x.purge_in_cache}
+ end
+
end
diff --git a/app/models/purge_request.rb b/app/models/purge_request.rb
new file mode 100644
index 000000000..1450058b1
--- /dev/null
+++ b/app/models/purge_request.rb
@@ -0,0 +1,41 @@
+# models/purge_request.rb:
+# A queue of URLs to purge
+#
+# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved.
+# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+#
+
+class PurgeRequest < ActiveRecord::Base
+ def self.purge_all
+ done_something = false
+ for item in PurgeRequest.all()
+ item.purge
+ done_something = true
+ end
+ return done_something
+ end
+
+ def self.purge_all_loop
+ # Run purge_all in an endless loop, sleeping when there is nothing to do
+ while true
+ sleep_seconds = 1
+ while !purge_all
+ sleep sleep_seconds
+ sleep_seconds *= 2
+ sleep_seconds = 300 if sleep_seconds > 300
+ end
+ end
+ end
+
+ def purge
+ config = MySociety::Config.load_default()
+ varnish_url = config['VARNISH_HOST']
+ result = quietly_try_to_purge(varnish_url, self.url)
+ if result == "200"
+ self.delete()
+ end
+ end
+end
+
+
+
diff --git a/app/models/track_thing.rb b/app/models/track_thing.rb
index 58d70ed86..3d147b8e6 100644
--- a/app/models/track_thing.rb
+++ b/app/models/track_thing.rb
@@ -108,7 +108,7 @@ class TrackThing < ActiveRecord::Base
end
descriptions = []
if varieties.include? _("requests")
- descriptions << _("requests which are {{list_of_statuses}}", :list_of_statuses => Array(statuses).join(_(' or ')))
+ descriptions << _("requests which are {{list_of_statuses}}", :list_of_statuses => Array(statuses).sort.join(_(' or ')))
varieties -= [_("requests")]
end
if descriptions.empty? and varieties.empty?
@@ -116,7 +116,7 @@ class TrackThing < ActiveRecord::Base
end
descriptions += Array(varieties)
parsed_text = parsed_text.strip
- descriptions = descriptions.join(_(" or "))
+ descriptions = descriptions.sort.join(_(" or "))
if !parsed_text.empty?
descriptions += _("{{list_of_things}} matching text '{{search_query}}'", :list_of_things => "", :search_query => parsed_text)
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 59a84b7aa..73d65a8ca 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -422,5 +422,12 @@ class User < ActiveRecord::Base
end
return true
end
+
+ after_save(:purge_in_cache)
+ def purge_in_cache
+ # XXX should only be if specific attributes have changed
+ self.info_requests.each {|x| x.purge_in_cache}
+ end
+
end
diff --git a/config/environment.rb b/config/environment.rb
index e35194bc7..b958c6475 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -135,6 +135,7 @@ require 'i18n_fixes.rb'
require 'rack_quote_monkeypatch.rb'
require 'world_foi_websites.rb'
require 'alaveteli_external_command.rb'
+require 'quiet_opener.rb'
ExceptionNotification::Notifier.sender_address = MySociety::Config::get('EXCEPTION_NOTIFICATIONS_FROM')
ExceptionNotification::Notifier.exception_recipients = MySociety::Config::get('EXCEPTION_NOTIFICATIONS_TO')
diff --git a/config/environments/development.rb b/config/environments/development.rb
index d5f2f5772..a1e8133a8 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -1,5 +1,7 @@
# Settings specified here will take precedence over those in config/environment.rb
+config.log_level = :info
+
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the webserver when you make code changes.
diff --git a/config/general.yml-example b/config/general.yml-example
index ed04e0fd5..84980c353 100644
--- a/config/general.yml-example
+++ b/config/general.yml-example
@@ -142,3 +142,7 @@ EXCEPTION_NOTIFICATIONS_TO:
# This rate limiting can be turned off per-user via the admin interface
MAX_REQUESTS_PER_USER_PER_DAY: 6
+
+# This is used to work out where to send purge requests. Should be
+# unset if you aren't running behind varnish
+VARNISH_HOST: localhost
diff --git a/config/purge-varnish-debian.ugly b/config/purge-varnish-debian.ugly
new file mode 100644
index 000000000..3e77c09c3
--- /dev/null
+++ b/config/purge-varnish-debian.ugly
@@ -0,0 +1,81 @@
+#!/bin/bash
+#
+### BEGIN INIT INFO
+# Provides: purge-varnish
+# Required-Start: $local_fs $syslog
+# Required-Stop: $local_fs $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: purge-varnish is a daemon running the Alaveteli email alerts
+# Description: purge-varnish send Alaveteli email alerts as required
+### END INIT INFO
+#
+# !!(*= $daemon_name *)!! Start the Alaveteli email alert daemon
+
+NAME=!!(*= $daemon_name *)!!
+DAEMON=/data/vhost/!!(*= $vhost *)!!/alaveteli/script/runner
+DAEMON_ARGS="--daemon PurgeRequest.purge_all_loop"
+PIDFILE=/data/vhost/!!(*= $vhost *)!!/purge-varnish.pid
+LOGFILE=/data/vhost/!!(*= $vhost *)!!/logs/purge-varnish.log
+DUSER=!!(*= $user *)!!
+
+trap "" 1
+
+export PIDFILE LOGFILE
+
+quietly_start_daemon() {
+ /sbin/start-stop-daemon --quiet --start --pidfile "$PIDFILE" --chuid "$DUSER" --startas "$DAEMON" -- $DAEMON_ARGS
+}
+
+start_daemon() {
+ /sbin/start-stop-daemon --start --pidfile "$PIDFILE" --chuid "$DUSER" --startas "$DAEMON" -- $DAEMON_ARGS
+}
+
+stop_daemon() {
+ /sbin/start-stop-daemon --stop --oknodo --pidfile "$PIDFILE"
+}
+
+restart() { stop; start; }
+
+case "$1" in
+ check)
+ quietly_start_daemon
+ if [ $? -ne 1 ]
+ then
+ echo "Alaveteli alert daemon was not running; now restarted"
+ exit 1
+ else
+ exit 0
+ fi
+ ;;
+
+ start)
+ echo -n "Starting Alaveteli alert daemon: $NAME"
+ start_daemon
+ ;;
+
+ stop)
+ echo -n "Stopping Alaveteli alert daemon: $NAME"
+ stop_daemon
+ ;;
+
+ restart)
+ echo -n "Restarting Alaveteli alert daemon: $NAME"
+ stop_daemon
+ start_daemon
+ ;;
+
+ *)
+ echo "Usage: /etc/init.d/$NAME {start|stop|restart|check}"
+ exit 1
+ ;;
+esac
+
+if [ $? -eq 0 ]; then
+ echo .
+ exit 0
+else
+ echo " failed"
+ exit 1
+fi
+
diff --git a/config/test.yml b/config/test.yml
index 90689395a..c35001747 100644
--- a/config/test.yml
+++ b/config/test.yml
@@ -124,3 +124,4 @@ EXCEPTION_NOTIFICATIONS_TO:
MAX_REQUESTS_PER_USER_PER_DAY: 2
+VARNISH_HOST: varnish.localdomain
diff --git a/config/varnish-alaveteli.vcl b/config/varnish-alaveteli.vcl
index 7eedf83fc..f81ec2295 100644
--- a/config/varnish-alaveteli.vcl
+++ b/config/varnish-alaveteli.vcl
@@ -9,12 +9,18 @@
backend default {
.host = "127.0.0.1";
- .port = "80";
+ .port = "3000";
.connect_timeout = 600s;
.first_byte_timeout = 600s;
.between_bytes_timeout = 600s;
}
+// set the servers alaveteli can issue a purge from
+acl purge {
+ "localhost";
+ "127.0.0.1";
+}
+
sub vcl_recv {
# Handle IPv6
@@ -54,12 +60,13 @@ sub vcl_recv {
req.request != "HEAD" &&
req.request != "POST" &&
req.request != "PUT" &&
+ req.request != "PURGE" &&
req.request != "DELETE" ) {
# We don't allow any other methods.
error 405 "Method Not Allowed";
}
- if (req.request != "GET" && req.request != "HEAD") {
+ if (req.request != "GET" && req.request != "HEAD" && req.request != "PURGE") {
/* We only deal with GET and HEAD by default, the rest get passed direct to backend */
return (pass);
}
@@ -73,15 +80,21 @@ sub vcl_recv {
if (req.http.Authorization || req.http.Cookie) {
return (pass);
}
-
# Let's have a little grace
set req.grace = 30s;
+ # Handle PURGE requests
+ if (req.request == "PURGE") {
+ if (!client.ip ~ purge) {
+ error 405 "Not allowed.";
+ }
+ ban("obj.http.x-url ~ " + req.url);
+ error 200 "Banned";
+ }
return (lookup);
}
-
sub vcl_fetch {
-
+ set beresp.http.x-url = req.url;
if (req.url ~ "\.(png|gif|jpg|jpeg|swf|css|js|rdf|ico|txt)(\?.*|)$") {
# Ignore backend headers..
remove beresp.http.set-Cookie;
@@ -94,3 +107,4 @@ sub vcl_fetch {
return (deliver);
}
}
+
diff --git a/db/migrate/111_create_purge_requests.rb b/db/migrate/111_create_purge_requests.rb
new file mode 100644
index 000000000..0b4fd1d1d
--- /dev/null
+++ b/db/migrate/111_create_purge_requests.rb
@@ -0,0 +1,14 @@
+class CreatePurgeRequests < ActiveRecord::Migration
+ def self.up
+ create_table :purge_requests do |t|
+ t.column :url, :string
+ t.column :created_at, :datetime, :null => false
+ t.column :model, :string, :null => false
+ t.column :model_id, :integer, :null => false
+ end
+ end
+
+ def self.down
+ drop_table :purge_requests
+ end
+end
diff --git a/doc/CHANGES.md b/doc/CHANGES.md
index 51da903b1..fe79a6e13 100644
--- a/doc/CHANGES.md
+++ b/doc/CHANGES.md
@@ -3,6 +3,10 @@
## Highlighted features
* Ruby dependencies are now handled by Bundler
+* Support for invalidating accelerator cache -- this makes it much
+ less likely, when using Varnish, that users will be presented with
+ stale content. Fixes
+ [issue #436](https://github.com/sebbacon/alaveteli/issues/436)
## Upgrade notes
@@ -14,6 +18,13 @@
install various things. Part of this is compiling xapian, which may
take a *long* time (subsequent deployments should be much faster)
+* To support invalidating the Varnish cache, ensure that there's a
+ value for `VARNISH_HOST` in `general.yml` (normally this would be
+ `localhost`). You will also need to update your Varnish server to
+ support PURGE requests. The example configuration provided at
+ `config/varnish-alaveteli.vcl` will work for Varnish 3 and above. If
+ you leave `VARNISH_HOST` blank, it will have no effect.
+
# Version 0.5.1
## Highlighted features
diff --git a/lib/quiet_opener.rb b/lib/quiet_opener.rb
new file mode 100644
index 000000000..a077ca323
--- /dev/null
+++ b/lib/quiet_opener.rb
@@ -0,0 +1,34 @@
+require 'open-uri'
+require 'net-purge'
+
+def quietly_try_to_open(url)
+ begin
+ result = open(url).read.strip
+ rescue OpenURI::HTTPError, SocketError, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::EHOSTUNREACH
+ logger.warn("Unable to open third-party URL #{url}")
+ result = ""
+ end
+ return result
+end
+
+def quietly_try_to_purge(host, url)
+ begin
+ result = ""
+ result_body = ""
+ Net::HTTP.start(host) {|http|
+ request = Net::HTTP::Purge.new(url)
+ response = http.request(request)
+ result = response.code
+ result_body = response.body
+ }
+ rescue OpenURI::HTTPError, SocketError, Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::EHOSTUNREACH
+ logger.warn("Unable to reach host #{host}")
+ end
+ if result == "200"
+ logger.info("Purged URL #{url} at #{host}: #{result}")
+ else
+ logger.warn("Unable to purge URL #{url} at #{host}: status #{result}")
+ end
+ return result
+end
+
diff --git a/script/purge-varnish b/script/purge-varnish
new file mode 100755
index 000000000..932cf6635
--- /dev/null
+++ b/script/purge-varnish
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+LOC=`dirname $0`
+
+if [ "$1" == "--loop" ]
+then
+ "$LOC/runner" 'PurgeRequest.purge_all_loop'
+else
+ "$LOC/runner" 'PurgeRequest.purge_all'
+fi
+
diff --git a/spec/controllers/admin_censor_rule_controller_spec.rb b/spec/controllers/admin_censor_rule_controller_spec.rb
new file mode 100644
index 000000000..8893a858b
--- /dev/null
+++ b/spec/controllers/admin_censor_rule_controller_spec.rb
@@ -0,0 +1,19 @@
+require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+
+describe AdminCensorRuleController, "when making censor rules from the admin interface" do
+ integrate_views
+ before { basic_auth_login @request }
+
+ it "should create a censor rule and purge the corresponding request from varnish" do
+ ir = info_requests(:fancy_dog_request)
+ post :create, :censor_rule => {
+ :text => "meat",
+ :replacement => "tofu",
+ :last_edit_comment => "none",
+ :info_request => ir
+ }
+ PurgeRequest.all().first.model_id.should == ir.id
+ end
+
+
+end
diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb
index 81c69db76..c79ddab36 100644
--- a/spec/controllers/request_controller_spec.rb
+++ b/spec/controllers/request_controller_spec.rb
@@ -117,6 +117,57 @@ describe RequestController, "when listing recent requests" do
end
+describe RequestController, "when changing things that appear on the request page" do
+
+ integrate_views
+
+ it "should purge the downstream cache when mail is received" do
+ ir = info_requests(:fancy_dog_request)
+ receive_incoming_mail('incoming-request-plain.email', ir.incoming_email)
+ PurgeRequest.all().first.model_id.should == ir.id
+ end
+ it "should purge the downstream cache when a comment is added" do
+ ir = info_requests(:fancy_dog_request)
+ new_comment = info_requests(:fancy_dog_request).add_comment('I also love making annotations.', users(:bob_smith_user))
+ PurgeRequest.all().first.model_id.should == ir.id
+ end
+ it "should purge the downstream cache when a followup is made" do
+ session[:user_id] = users(:bob_smith_user).id
+ ir = info_requests(:fancy_dog_request)
+ post :show_response, :outgoing_message => { :body => "What a useless response! You suck.", :what_doing => 'normal_sort' }, :id => ir.id, :incoming_message_id => incoming_messages(:useless_incoming_message), :submitted_followup => 1
+ PurgeRequest.all().first.model_id.should == ir.id
+ end
+ it "should purge the downstream cache when the request is categorised" do
+ ir = info_requests(:fancy_dog_request)
+ ir.set_described_state('waiting_clarification')
+ PurgeRequest.all().first.model_id.should == ir.id
+ end
+ it "should purge the downstream cache when the authority data is changed" do
+ ir = info_requests(:fancy_dog_request)
+ ir.public_body.name = "Something new"
+ ir.public_body.save!
+ PurgeRequest.all().map{|x| x.model_id}.should =~ ir.public_body.info_requests.map{|x| x.id}
+ end
+ it "should purge the downstream cache when the user details are changed" do
+ ir = info_requests(:fancy_dog_request)
+ ir.user.name = "Something new"
+ ir.user.save!
+ PurgeRequest.all().map{|x| x.model_id}.should =~ ir.user.info_requests.map{|x| x.id}
+ end
+ it "should purge the downstream cache when censor rules have changed" do
+ # XXX really, CensorRules should execute expiry logic as part
+ # of the after_save of the model. Currently this is part of
+ # the AdminCensorRuleController logic, so must be tested from
+ # there. Leaving this stub test in place as a reminder
+ end
+ it "should purge the downstream cache when something is hidden by an admin" do
+ ir = info_requests(:fancy_dog_request)
+ ir.prominence = 'hidden'
+ ir.save!
+ PurgeRequest.all().first.model_id.should == ir.id
+ end
+end
+
describe RequestController, "when showing one request" do
before(:each) do
@@ -185,7 +236,7 @@ describe RequestController, "when showing one request" do
describe 'when handling incoming mail' do
integrate_views
-
+
it "should receive incoming messages, send email to creator, and show them" do
ir = info_requests(:fancy_dog_request)
ir.incoming_messages.each { |x| x.parse_raw_email! }
@@ -991,6 +1042,7 @@ describe RequestController, "when classifying an information request" do
session[:user_id] = @admin_user.id
@dog_request = info_requests(:fancy_dog_request)
InfoRequest.stub!(:find).and_return(@dog_request)
+ @dog_request.stub!(:each).and_return([@dog_request])
end
it 'should update the status of the request' do
@@ -1032,6 +1084,7 @@ describe RequestController, "when classifying an information request" do
@dog_request.user = @admin_user
@dog_request.save!
InfoRequest.stub!(:find).and_return(@dog_request)
+ @dog_request.stub!(:each).and_return([@dog_request])
end
it 'should update the status of the request' do
@@ -1068,6 +1121,7 @@ describe RequestController, "when classifying an information request" do
@request_owner = users(:bob_smith_user)
session[:user_id] = @request_owner.id
@dog_request.awaiting_description.should == true
+ @dog_request.stub!(:each).and_return([@dog_request])
end
it "should successfully classify response if logged in as user controlling request" do
@@ -1135,6 +1189,7 @@ describe RequestController, "when classifying an information request" do
@request_owner = users(:bob_smith_user)
session[:user_id] = @request_owner.id
@dog_request = info_requests(:fancy_dog_request)
+ @dog_request.stub!(:each).and_return([@dog_request])
InfoRequest.stub!(:find).and_return(@dog_request)
@old_filters = ActionController::Routing::Routes.filters
ActionController::Routing::Routes.filters = RoutingFilter::Chain.new
@@ -1768,6 +1823,7 @@ describe RequestController, "when showing similar requests" do
get :similar, :url_title => "there_is_really_no_such_path_owNAFkHR"
}.should raise_error(ActiveRecord::RecordNotFound)
end
+
end
diff --git a/spec/models/purge_request_spec.rb b/spec/models/purge_request_spec.rb
new file mode 100644
index 000000000..f7d01f784
--- /dev/null
+++ b/spec/models/purge_request_spec.rb
@@ -0,0 +1,32 @@
+require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
+require 'fakeweb'
+
+describe PurgeRequest, "purging things" do
+ before do
+ FakeWeb.last_request = nil
+ end
+
+ it 'should issue purge requests to the server' do
+ req = PurgeRequest.new(:url => "/begone_from_here",
+ :model => "don't care",
+ :model_id => "don't care")
+ req.save()
+ PurgeRequest.all().count.should == 1
+ PurgeRequest.purge_all()
+ PurgeRequest.all().count.should == 0
+ end
+
+ it 'should fail silently for a misconfigured server' do
+ FakeWeb.register_uri(:get, %r|brokenv|, :body => "BROKEN")
+ config = MySociety::Config.load_default()
+ config['VARNISH_HOST'] = "brokencache"
+ req = PurgeRequest.new(:url => "/begone_from_here",
+ :model => "don't care",
+ :model_id => "don't care")
+ req.save()
+ PurgeRequest.all().count.should == 1
+ PurgeRequest.purge_all()
+ PurgeRequest.all().count.should == 1
+ end
+end
+
diff --git a/spec/models/track_thing_spec.rb b/spec/models/track_thing_spec.rb
index bd122941a..93f407475 100644
--- a/spec/models/track_thing_spec.rb
+++ b/spec/models/track_thing_spec.rb
@@ -36,7 +36,7 @@ describe TrackThing, "when tracking changes" do
it "will make some sane descriptions of search-based tracks" do
tests = [['bob variety:user', "users matching text 'bob'"],
- ['bob (variety:sent OR variety:followup_sent OR variety:response OR variety:comment) (latest_status:successful OR latest_status:partially_successful OR latest_status:rejected OR latest_status:not_held)', "requests which are successful or unsuccessful or comments matching text 'bob'"],
+ ['bob (variety:sent OR variety:followup_sent OR variety:response OR variety:comment) (latest_status:successful OR latest_status:partially_successful OR latest_status:rejected OR latest_status:not_held)', "comments or requests which are successful or unsuccessful matching text 'bob'"],
['(latest_status:waiting_response OR latest_status:waiting_clarification OR waiting_classification:true)', 'requests which are awaiting a response']]
for query, description in tests
track_thing = TrackThing.create_track_for_search_query(query)
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 99cf8a2c8..a98a5113d 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -13,6 +13,9 @@ config['ADMIN_PASSWORD'] = 'baz'
# tests assume 20 days
config['REPLY_LATE_AFTER_DAYS'] = 20
+# register a fake Varnish server
+require 'fakeweb'
+FakeWeb.register_uri(:purge, %r|varnish.localdomain|, :body => "OK")
# Uncomment the next line to use webrat's matchers
#require 'webrat/integrations/rspec-rails'