bang! kill redis cache.
This commit is contained in:
parent
d1a82d288d
commit
4f7dda6012
22 changed files with 3 additions and 863 deletions
|
|
@ -12,7 +12,6 @@ class ShareVisibilitiesController < ApplicationController
|
|||
params[:shareable_type] ||= 'Post'
|
||||
|
||||
vis = current_user.toggle_hidden_shareable(accessible_post)
|
||||
RedisCache.update_cache_for(current_user, accessible_post, vis)
|
||||
render :nothing => true, :status => 200
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -21,9 +21,7 @@ class Contact < ActiveRecord::Base
|
|||
validates_presence_of :user
|
||||
validates_uniqueness_of :person_id, :scope => :user_id
|
||||
|
||||
before_destroy :destroy_notifications,
|
||||
:repopulate_cache!
|
||||
|
||||
before_destroy :destroy_notifications
|
||||
|
||||
scope :all_contacts_of_person, lambda {|x| where(:person_id => x.id)}
|
||||
|
||||
|
|
@ -53,13 +51,6 @@ class Contact < ActiveRecord::Base
|
|||
:type => "Notifications::StartedSharing").delete_all
|
||||
end
|
||||
|
||||
def repopulate_cache!
|
||||
if RedisCache.configured? && self.user.present?
|
||||
cache = RedisCache.new(self.user)
|
||||
cache.repopulate!
|
||||
end
|
||||
end
|
||||
|
||||
def dispatch_request
|
||||
request = self.generate_request
|
||||
Postzord::Dispatcher.build(self.user, request).post
|
||||
|
|
|
|||
|
|
@ -52,8 +52,6 @@ class Post < ActiveRecord::Base
|
|||
|
||||
belongs_to :o_embed_cache
|
||||
|
||||
after_create :cache_for_author
|
||||
|
||||
#scopes
|
||||
scope :includes_for_a_stream, includes(:o_embed_cache, {:author => :profile}, :mentions => {:person => :profile}) #note should include root and photos, but i think those are both on status_message
|
||||
|
||||
|
|
@ -123,19 +121,4 @@ class Post < ActiveRecord::Base
|
|||
def comment_email_subject
|
||||
I18n.t('notifier.a_post_you_shared')
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
def cache_for_author
|
||||
if self.should_cache_for_author?
|
||||
cache = RedisCache.new(self.author.owner, 'created_at')
|
||||
cache.add(self.created_at.to_i, self.id)
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
def should_cache_for_author?
|
||||
self.triggers_caching? && RedisCache.configured? &&
|
||||
RedisCache.acceptable_types.include?(self.type) && user = self.author.owner
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,27 +26,6 @@ defaults: &defaults
|
|||
# leave it empty for the default (localhost)
|
||||
redis_url: ''
|
||||
|
||||
# Redis cache
|
||||
|
||||
# Enable the cache layer (Redis)
|
||||
# If you expect to have thousands of users on your pod,
|
||||
# we *highly* suggest you enable this.
|
||||
# IMPORTANT: THE CACHE REQUIRES REDIS 2.4 OR LATER.
|
||||
#
|
||||
# By default, the cache layer will piggyback off of the Redis
|
||||
# database used by your Resque workers.
|
||||
redis_cache: false
|
||||
|
||||
# The location of your redis cache.
|
||||
# IMPORTANT: DO NOT CHANGE THIS IF YOU DO NOT KNOW WHAT YOU ARE DOING!
|
||||
#
|
||||
# Leave this blank to use the same Redis database
|
||||
# that your Resque workers use (happy path).
|
||||
#
|
||||
# This takes an ip (or DNS record). It assumes that your Redis database
|
||||
# is running on the default Redis port.
|
||||
redis_location: ''
|
||||
|
||||
# Amazon S3 for photos
|
||||
|
||||
# s3 config - if set, carrierwave will store your photos on s3. Otherwise they're on the filesystem.
|
||||
|
|
|
|||
|
|
@ -54,12 +54,8 @@ ServiceUser.import((1..40).map{|n| Factory.build(:service_user, :service => eve_
|
|||
puts "done!"
|
||||
|
||||
require File.join(File.dirname(__FILE__), '..', 'spec', 'support', 'fake_resque')
|
||||
require File.join(File.dirname(__FILE__), '..', 'spec', 'support', 'fake_redis')
|
||||
require File.join(File.dirname(__FILE__), '..', 'spec', 'support', 'user_methods')
|
||||
|
||||
old_cache_setting = AppConfig[:redis_cache]
|
||||
AppConfig[:redis_cache] = false
|
||||
|
||||
print "Seeding post data..."
|
||||
time_interval = 1000
|
||||
(1..25).each do |n|
|
||||
|
|
@ -82,8 +78,6 @@ time_interval = 1000
|
|||
end
|
||||
puts " done!"
|
||||
|
||||
AppConfig[:redis_cache] = old_cache_setting
|
||||
|
||||
puts "Successfully seeded the db with users eve, bob, and alice (password: 'evankorth')"
|
||||
puts ""
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ require File.join(File.dirname(__FILE__), "database_cleaner_patches")
|
|||
require File.join(File.dirname(__FILE__), "integration_sessions_controller")
|
||||
require File.join(File.dirname(__FILE__), "poor_mans_webmock")
|
||||
|
||||
require File.join(File.dirname(__FILE__), "..", "..", "spec", "support", "fake_redis")
|
||||
require File.join(File.dirname(__FILE__), "..", "..", "spec", "helper_methods")
|
||||
require File.join(File.dirname(__FILE__), "..", "..", "spec", "support","user_methods")
|
||||
include HelperMethods
|
||||
|
|
|
|||
|
|
@ -1,143 +0,0 @@
|
|||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
class RedisCache
|
||||
|
||||
SUPPORTED_CACHES = [:created_at]
|
||||
CACHE_LIMIT = 100
|
||||
|
||||
def initialize(user, order_field=:created_at)
|
||||
@user = user
|
||||
@order_field = order_field.to_s
|
||||
end
|
||||
|
||||
# Checks to see if the necessary redis cache variables are set in application.yml
|
||||
#
|
||||
# @return [Boolean]
|
||||
def self.configured?
|
||||
AppConfig[:redis_cache].present?
|
||||
end
|
||||
|
||||
def self.update_cache_for(user, post, post_was_hidden)
|
||||
return unless RedisCache.configured?
|
||||
|
||||
cache = RedisCache.new(user, 'created_at')
|
||||
|
||||
if post_was_hidden
|
||||
cache.remove(post.id)
|
||||
else
|
||||
cache.add(post.created_at.to_i, post.id)
|
||||
end
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
def cache_exists?
|
||||
self.redis.exists(set_key)
|
||||
end
|
||||
|
||||
# @return [Integer] the cardinality of the redis set
|
||||
def size
|
||||
redis.zcard(set_key)
|
||||
end
|
||||
|
||||
def post_ids(time=Time.now, limit=15)
|
||||
post_ids = redis.zrevrangebyscore(set_key, time.to_i, "-inf")
|
||||
post_ids[0...limit]
|
||||
end
|
||||
|
||||
def ensure_populated!(opts = {})
|
||||
self.repopulate!(opts) unless cache_exists?
|
||||
end
|
||||
|
||||
def repopulate!(opts = {})
|
||||
self.purge!
|
||||
self.populate!(opts) && self.trim!
|
||||
end
|
||||
|
||||
def purge!
|
||||
self.redis.del(set_key)
|
||||
end
|
||||
|
||||
def populate!(opts = {})
|
||||
# user executes query and gets back hashes
|
||||
opts.merge!({
|
||||
:type => RedisCache.acceptable_types,
|
||||
:limit => CACHE_LIMIT,
|
||||
:order => self.order
|
||||
})
|
||||
|
||||
sql = @user.visible_shareable_sql(Post, opts)
|
||||
hashes = Post.connection.select_all(sql)
|
||||
|
||||
# hashes are inserted into set in a single transaction
|
||||
redis.multi do
|
||||
hashes.each do |h|
|
||||
self.redis.zadd(set_key, h[@order_field].to_i, h["id"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def trim!
|
||||
self.redis.zremrangebyrank(set_key, 0, -(CACHE_LIMIT+1))
|
||||
end
|
||||
|
||||
# @param order [Symbol, String]
|
||||
# @return [Boolean]
|
||||
def self.supported_order?(order)
|
||||
SUPPORTED_CACHES.include?(order.to_sym)
|
||||
end
|
||||
|
||||
def order
|
||||
"#{@order_field} DESC"
|
||||
end
|
||||
|
||||
def add(score, id)
|
||||
return unless self.cache_exists?
|
||||
self.redis.zadd(set_key, score.to_i, id)
|
||||
self.trim!
|
||||
end
|
||||
|
||||
def remove(id)
|
||||
return unless self.cache_exists?
|
||||
self.redis.zrem(set_key, id)
|
||||
end
|
||||
|
||||
# exposing the need to tie cache to a stream
|
||||
# @return [Array<String>] Acceptable Post types for the given cache
|
||||
def self.acceptable_types
|
||||
Stream::Base::TYPES_OF_POST_IN_STREAM
|
||||
end
|
||||
|
||||
# Instantiate a redis connection
|
||||
#
|
||||
# @return [Redis]
|
||||
def self.redis_connection
|
||||
Redis.new(:host => RedisCache.redis_host, :port => RedisCache.redis_port)
|
||||
end
|
||||
|
||||
protected
|
||||
# @see .redis_connection
|
||||
# @return [Redis]
|
||||
def redis
|
||||
@redis ||= RedisCache.redis_connection
|
||||
end
|
||||
|
||||
def self.redis_host
|
||||
(AppConfig[:redis_location].blank?) ? nil : AppConfig[:redis_location]
|
||||
end
|
||||
|
||||
def self.redis_port
|
||||
(AppConfig[:redis_port].blank?) ? nil : AppConfig[:redis_port]
|
||||
end
|
||||
|
||||
# @return [String]
|
||||
def self.cache_prefix
|
||||
"cache_stream"
|
||||
end
|
||||
|
||||
# @return [String]
|
||||
def set_key
|
||||
@set_key ||= "#{RedisCache.cache_prefix}_#{@user.id}_#{@order_field}"
|
||||
end
|
||||
end
|
||||
|
|
@ -2,8 +2,6 @@
|
|||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
require File.join(Rails.root, 'lib', 'diaspora', 'redis_cache')
|
||||
|
||||
require File.join(Rails.root, 'lib', 'evil_query')
|
||||
|
||||
|
||||
|
|
@ -24,32 +22,10 @@ module Diaspora
|
|||
klass.where(:id => shareable_ids).select('DISTINCT '+klass.to_s.tableize+'.*').limit(opts[:limit]).order(opts[:order_with_table])
|
||||
end
|
||||
|
||||
def visible_shareables_from_cache(klass, opts)
|
||||
cache = RedisCache.new(self, opts[:order_field])
|
||||
|
||||
#total hax
|
||||
if self.contacts.where(:sharing => true, :receiving => true).count > 0
|
||||
cache.ensure_populated!(opts)
|
||||
end
|
||||
|
||||
name = klass.to_s.downcase + "_ids"
|
||||
cached_ids = cache.send(name, opts[:max_time], opts[:limit] +1)
|
||||
|
||||
if perform_db_query?(cached_ids, cache, opts)
|
||||
visible_ids_from_sql(klass, opts)
|
||||
else
|
||||
cached_ids
|
||||
end
|
||||
end
|
||||
|
||||
def visible_shareable_ids(klass, opts={})
|
||||
opts = prep_opts(klass, opts)
|
||||
if use_cache?(opts)
|
||||
visible_shareables_from_cache(klass, opts)
|
||||
else
|
||||
visible_ids_from_sql(klass, opts)
|
||||
end
|
||||
end
|
||||
|
||||
# @return [Array<Integer>]
|
||||
def visible_ids_from_sql(klass, opts={})
|
||||
|
|
@ -170,18 +146,6 @@ module Diaspora
|
|||
end
|
||||
|
||||
protected
|
||||
# @return [Boolean]
|
||||
|
||||
def use_cache?(opts)
|
||||
RedisCache.configured? && RedisCache.supported_order?(opts[:order_field]) && opts[:all_aspects?].present?
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
def perform_db_query?(shareable_ids, cache, opts)
|
||||
return true if cache == nil
|
||||
return false if cache.size <= opts[:limit]
|
||||
shareable_ids.blank? || shareable_ids.length < opts[:limit]
|
||||
end
|
||||
|
||||
# @return [Hash]
|
||||
def prep_opts(klass, opts)
|
||||
|
|
|
|||
|
|
@ -8,16 +8,7 @@ class Postzord::Receiver
|
|||
require File.join(Rails.root, 'lib/postzord/receiver/public')
|
||||
|
||||
def perform!
|
||||
if self.receive!
|
||||
self.update_cache! if cache?
|
||||
end
|
||||
end
|
||||
|
||||
# @return [Boolean]
|
||||
def cache?
|
||||
self.respond_to?(:update_cache!) && RedisCache.configured? &&
|
||||
@object.respond_to?(:triggers_caching?) && @object.triggers_caching? &&
|
||||
@object.respond_to?(:type) && RedisCache.acceptable_types.include?(@object.type)
|
||||
self.receive!
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -26,17 +26,6 @@ class Postzord::Receiver::LocalBatch < Postzord::Receiver
|
|||
true
|
||||
end
|
||||
|
||||
def update_cache!
|
||||
@users.each do |user|
|
||||
# (NOTE) this can be optimized furter to not use n-query
|
||||
contact = user.contact_for(object.author)
|
||||
if contact && contact.aspect_memberships.size > 0
|
||||
cache = RedisCache.new(user, "created_at")
|
||||
cache.add(@object.created_at.to_i, @object.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# NOTE(copied over from receiver public)
|
||||
# @return [Object]
|
||||
def receive_relayable
|
||||
|
|
|
|||
|
|
@ -48,13 +48,6 @@ class Postzord::Receiver::Private < Postzord::Receiver
|
|||
obj
|
||||
end
|
||||
|
||||
def update_cache!
|
||||
if @user.contact_for(@author).aspect_memberships.size > 0
|
||||
cache = RedisCache.new(@user, "created_at")
|
||||
cache.add(@object.created_at.to_i, @object.id)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
def salmon
|
||||
@salmon ||= Salmon::EncryptedSlap.from_xml(@salmon_xml, @user)
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
namespace :cache do
|
||||
|
||||
desc "Clear all caches"
|
||||
task :clear => :environment do
|
||||
if RedisCache.configured?
|
||||
redis = RedisCache.redis_connection
|
||||
puts "Clearing Cache..."
|
||||
redis.keys do |k|
|
||||
if k.match(/^#{RedisCache.cache_prefix}/).present?
|
||||
redis.del(k)
|
||||
end
|
||||
end
|
||||
puts "Done!"
|
||||
else
|
||||
puts "Redis Cache is not configured"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -11,21 +11,12 @@ describe ShareVisibilitiesController do
|
|||
end
|
||||
|
||||
describe '#update' do
|
||||
before do
|
||||
@controller.stub(:update_cache)
|
||||
end
|
||||
|
||||
context "on a post you can see" do
|
||||
it 'succeeds' do
|
||||
put :update, :format => :js, :id => 42, :post_id => @status.id
|
||||
response.should be_success
|
||||
end
|
||||
|
||||
it 'calls #update_cache' do
|
||||
RedisCache.should_receive(:update_cache_for).with(an_instance_of(User), an_instance_of(Post), true)
|
||||
put :update, :format => :js, :id => 42, :post_id => @status.id
|
||||
end
|
||||
|
||||
it 'it calls toggle_hidden_shareable' do
|
||||
@controller.current_user.should_receive(:toggle_hidden_shareable).with(an_instance_of(Post))
|
||||
put :update, :format => :js, :id => 42, :post_id => @status.id
|
||||
|
|
|
|||
|
|
@ -1,249 +0,0 @@
|
|||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||
# licensed under the Affero General Public License version 3 or later. See
|
||||
# the COPYRIGHT file.
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe RedisCache do
|
||||
before do
|
||||
@redis = MockRedis.new
|
||||
@cache = RedisCache.new(bob, :created_at)
|
||||
@cache.stub(:redis).and_return(@redis)
|
||||
end
|
||||
|
||||
it 'gets initialized with user and an created_at order' do
|
||||
cache = RedisCache.new(bob, :created_at)
|
||||
[:@user, :@order_field].each do |var|
|
||||
cache.instance_variable_get(var).should_not be_blank
|
||||
end
|
||||
end
|
||||
|
||||
describe "#cache_exists?" do
|
||||
it 'returns true if the sorted set exists' do
|
||||
timestamp = Time.now.to_i
|
||||
@redis.zadd("cache_stream_#{bob.id}_created_at", timestamp, "post_1")
|
||||
|
||||
@cache.cache_exists?.should be_true
|
||||
end
|
||||
|
||||
it 'returns false if there is nothing in the set' do
|
||||
@cache.cache_exists?.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#post_ids" do
|
||||
before do
|
||||
@timestamps = []
|
||||
@timestamp = Time.now.to_i
|
||||
30.times do |n|
|
||||
created_time = @timestamp - n*1000
|
||||
@redis.zadd("cache_stream_#{bob.id}_created_at", created_time, n.to_s)
|
||||
@timestamps << created_time
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns the most recent post ids (default created at, limit 15)' do
|
||||
@cache.post_ids.should =~ 15.times.map { |n| n.to_s }
|
||||
end
|
||||
|
||||
it 'returns posts ids after the specified time' do
|
||||
@cache.post_ids(@timestamps[15]).should =~ (15...30).map { |n| n.to_s }
|
||||
end
|
||||
|
||||
it 'returns post ids with a non-default limit' do
|
||||
@cache.post_ids(@timestamp, 20).should =~ 20.times.map { |n| n.to_s }
|
||||
end
|
||||
end
|
||||
|
||||
describe "#ensure_populated!" do
|
||||
it 'does nothing if the cache is populated' do
|
||||
@cache.stub(:cache_exists?).and_return(true)
|
||||
@cache.should_not_receive(:repopulate!)
|
||||
|
||||
@cache.ensure_populated!
|
||||
end
|
||||
|
||||
it 'calls #repopulate' do
|
||||
opts = {:here_is => "something"}
|
||||
@cache.stub(:cache_exists?).and_return(false)
|
||||
@cache.should_receive(:repopulate!).with(opts)
|
||||
|
||||
@cache.ensure_populated!(opts)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#repopulate!" do
|
||||
it 'calls #purge!' do
|
||||
@cache.should_receive(:purge!)
|
||||
@cache.repopulate!
|
||||
end
|
||||
|
||||
it 'populates' do
|
||||
opts = {:here_is => "something"}
|
||||
@cache.stub(:trim!).and_return(true)
|
||||
@cache.should_receive(:populate!).with(opts).and_return(true)
|
||||
@cache.repopulate!(opts)
|
||||
end
|
||||
|
||||
it 'trims' do
|
||||
@cache.stub(:populate!).and_return(true)
|
||||
@cache.should_receive(:trim!)
|
||||
@cache.repopulate!
|
||||
end
|
||||
end
|
||||
|
||||
describe '#purge!' do
|
||||
it 'clears the set in redis' do
|
||||
@cache.stub(:redis).and_return(@redis)
|
||||
@redis.should_receive(:del).with(@cache.send(:set_key))
|
||||
@cache.purge!
|
||||
end
|
||||
end
|
||||
|
||||
describe "#populate!" do
|
||||
it 'queries the db with the visible post sql string' do
|
||||
sql = "long_sql"
|
||||
order = "created_at DESC"
|
||||
@cache.should_receive(:order).and_return(order)
|
||||
bob.should_receive(:visible_shareable_sql).with(
|
||||
Post,
|
||||
hash_including(
|
||||
:type => RedisCache.acceptable_types,
|
||||
:limit => RedisCache::CACHE_LIMIT,
|
||||
:order => order)).
|
||||
and_return(sql)
|
||||
|
||||
Post.connection.should_receive(:select_all).with(sql).and_return([])
|
||||
|
||||
@cache.populate!
|
||||
end
|
||||
end
|
||||
|
||||
describe "#trim!" do
|
||||
it 'does nothing if the set is smaller than the cache limit' do
|
||||
@timestamps = []
|
||||
@timestamp = Time.now.to_i
|
||||
30.times do |n|
|
||||
created_time = @timestamp - n*1000
|
||||
@redis.zadd("cache_stream_#{bob.id}_created_at", created_time, n.to_s)
|
||||
@timestamps << created_time
|
||||
end
|
||||
|
||||
post_ids = @cache.post_ids(Time.now.to_i, @cache.size)
|
||||
@cache.trim!
|
||||
@cache.post_ids(Time.now.to_i, @cache.size).should == post_ids
|
||||
end
|
||||
|
||||
it 'trims the set to the cache limit' do
|
||||
@timestamps = []
|
||||
@timestamp = Time.now.to_i
|
||||
120.times do |n|
|
||||
created_time = @timestamp - n*1000
|
||||
@redis.zadd("cache_stream_#{bob.id}_created_at", created_time, n.to_s)
|
||||
@timestamps << created_time
|
||||
end
|
||||
|
||||
post_ids = 100.times.map { |n| n.to_s }
|
||||
@cache.trim!
|
||||
@cache.post_ids(Time.now.to_i, @cache.size).should == post_ids[0...100]
|
||||
end
|
||||
end
|
||||
|
||||
describe "#add" do
|
||||
before do
|
||||
@cache.stub(:cache_exists?).and_return(true)
|
||||
@id = 1
|
||||
@score = 123
|
||||
end
|
||||
|
||||
it "adds an id with a given score" do
|
||||
@redis.should_receive(:zadd).with(@cache.send(:set_key), @score, @id)
|
||||
@cache.add(@score, @id)
|
||||
end
|
||||
|
||||
it 'trims' do
|
||||
@cache.should_receive(:trim!)
|
||||
@cache.add(@score, @id)
|
||||
end
|
||||
|
||||
it "doesn't add if the cache does not exist" do
|
||||
@cache.stub(:cache_exists?).and_return(false)
|
||||
|
||||
@redis.should_not_receive(:zadd)
|
||||
@cache.add(@score, @id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#remove" do
|
||||
before do
|
||||
@id = 1
|
||||
end
|
||||
|
||||
it "doesn't add if the cache does not exist" do
|
||||
@cache.stub(:cache_exists?).and_return(false)
|
||||
|
||||
@redis.should_not_receive(:zrem)
|
||||
@cache.remove(@id).should be_false
|
||||
end
|
||||
|
||||
it "removes a given id" do
|
||||
@cache.stub(:cache_exists?).and_return(true)
|
||||
|
||||
@redis.should_receive(:zrem).with(@cache.send(:set_key), @id)
|
||||
@cache.remove(@id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#set_key" do
|
||||
it 'uses the correct prefix and order' do
|
||||
user = @cache.instance_variable_get(:@user)
|
||||
order_field = @cache.instance_variable_get(:@order_field)
|
||||
@cache.send(:set_key).should == "#{RedisCache.cache_prefix}_#{user.id}_#{order_field}"
|
||||
end
|
||||
end
|
||||
|
||||
describe '.cache_setup?' do
|
||||
it 'returns true if configuration is properly set' do
|
||||
AppConfig[:redis_cache] = true
|
||||
RedisCache.should be_configured
|
||||
end
|
||||
|
||||
it 'returns false if configuration is not present' do
|
||||
AppConfig[:redis_cache] = false
|
||||
RedisCache.should_not be_configured
|
||||
end
|
||||
end
|
||||
|
||||
describe '.acceptable_types' do
|
||||
#exposing the need to tie cache to a stream
|
||||
it 'returns the types from the aspect stream' do
|
||||
RedisCache.acceptable_types.should =~ Stream::Base::TYPES_OF_POST_IN_STREAM
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update_cache' do
|
||||
before do
|
||||
@cache = RedisCache.new(bob, 'created_at')
|
||||
RedisCache.stub(:new).and_return(@cache)
|
||||
RedisCache.stub(:configured?).and_return(true)
|
||||
@post = Factory(:status_message)
|
||||
end
|
||||
|
||||
it 'does nothing if cache is not configured' do
|
||||
RedisCache.stub(:configured?).and_return(false)
|
||||
RedisCache.should_not_receive(:new)
|
||||
RedisCache.update_cache_for(bob, @post, true)
|
||||
end
|
||||
|
||||
it 'removes the post from the cache if visibility is marked as hidden' do
|
||||
@cache.should_receive(:remove).with(@post.id)
|
||||
RedisCache.update_cache_for(bob, @post, true)
|
||||
end
|
||||
|
||||
it 'adds the post from the cache if visibility is unmarked as hidden' do
|
||||
@cache.should_receive(:add).with(@post.created_at.to_i, @post.id)
|
||||
RedisCache.update_cache_for(bob, @post, false)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -91,43 +91,4 @@ describe Postzord::Receiver::LocalBatch do
|
|||
receiver.perform!
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update_cache!' do
|
||||
before do
|
||||
|
||||
end
|
||||
|
||||
it 'adds to a redis cache for users sharing with author' do
|
||||
users = [bob]
|
||||
@zord = Postzord::Receiver::LocalBatch.new(@object, users.map{|u| u.id})
|
||||
|
||||
sort_order = "created_at"
|
||||
|
||||
cache = mock
|
||||
RedisCache.should_receive(:new).exactly(users.length).times.with(instance_of(User), sort_order).and_return(cache)
|
||||
|
||||
cache.should_receive(:add).exactly(users.length).times.with(@object.created_at.to_i, @object.id)
|
||||
|
||||
@zord.update_cache!
|
||||
end
|
||||
|
||||
it 'does not add to the redis cache of the users not contact with author' do
|
||||
users = [bob, eve]
|
||||
@zord = Postzord::Receiver::LocalBatch.new(@object, users.map{|u| u.id})
|
||||
|
||||
RedisCache.should_receive(:new).once.with(bob, anything()).and_return(stub.as_null_object)
|
||||
|
||||
@zord.update_cache!
|
||||
end
|
||||
|
||||
it 'does not add to the redis cache of users not sharing with the author' do
|
||||
alice.share_with(eve.person, alice.aspects.first)
|
||||
users = [bob, eve]
|
||||
@zord = Postzord::Receiver::LocalBatch.new(@object, users.map{|u| u.id})
|
||||
|
||||
RedisCache.should_receive(:new).once.with(bob, anything()).and_return(stub.as_null_object)
|
||||
|
||||
@zord.update_cache!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -96,29 +96,4 @@ describe Postzord::Receiver::Private do
|
|||
@zord.receive_object
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update_cache!' do
|
||||
it 'adds to redis cache if the contact has aspect visibilities' do
|
||||
@alices_post.save!
|
||||
|
||||
@zord = Postzord::Receiver::Private.new(bob, :person => alice.person, :object => @alices_post)
|
||||
|
||||
sort_order = "created_at"
|
||||
cache = RedisCache.new(bob, sort_order)
|
||||
RedisCache.should_receive(:new).with(bob, sort_order).and_return(cache)
|
||||
cache.should_receive(:add).with(@alices_post.created_at.to_i, @alices_post.id)
|
||||
@zord.update_cache!
|
||||
end
|
||||
|
||||
it 'does not add to redis cache if the receiving user is not sharing with the sender' do
|
||||
alice.share_with(eve.person, alice.aspects.first)
|
||||
@alices_post.save!
|
||||
|
||||
@zord = Postzord::Receiver::Private.new(eve, :person => alice.person, :object => @alices_post)
|
||||
|
||||
sort_order = "created_at"
|
||||
RedisCache.should_not_receive(:new)
|
||||
@zord.update_cache!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,68 +20,6 @@ describe Postzord::Receiver do
|
|||
@receiver.should_receive(:receive!)
|
||||
@receiver.perform!
|
||||
end
|
||||
|
||||
context 'update_cache!' do
|
||||
before do
|
||||
@receiver.stub(:cache?).and_return(true)
|
||||
end
|
||||
|
||||
it "gets called if cache?" do
|
||||
@receiver.should_receive(:update_cache!)
|
||||
@receiver.perform!
|
||||
end
|
||||
|
||||
it "doesn't get called if !cache?" do
|
||||
@receiver.stub(:cache?).and_return(false)
|
||||
@receiver.should_not_receive(:update_cache!)
|
||||
@receiver.perform!
|
||||
end
|
||||
|
||||
it 'does not get called if receive! is false' do
|
||||
@receiver.stub(:receive!).and_return(false)
|
||||
@receiver.should_not_receive(:update_cache!)
|
||||
@receiver.perform!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#cache?" do
|
||||
before do
|
||||
@receiver.stub(:respond_to?).with(:update_cache!).and_return(true)
|
||||
AppConfig[:redis_cache] = true
|
||||
|
||||
RedisCache.stub(:acceptable_types).and_return(["StatusMessage"])
|
||||
@receiver.instance_variable_set(:@object, mock(:triggers_caching? => true, :type => "StatusMessage"))
|
||||
end
|
||||
|
||||
it 'returns true if the receiver responds to update_cache and the application has caching enabled' do
|
||||
@receiver.cache?.should be_true
|
||||
end
|
||||
|
||||
it 'returns false if the receiver does not respond to update_cache' do
|
||||
@receiver.stub(:respond_to?).with(:update_cache!).and_return(false)
|
||||
@receiver.cache?.should be_false
|
||||
end
|
||||
|
||||
it 'returns false if the application does not have caching set' do
|
||||
AppConfig[:redis_cache] = false
|
||||
@receiver.cache?.should be_false
|
||||
end
|
||||
|
||||
it 'returns false if the object is does not respond to triggers_caching' do
|
||||
@receiver.instance_variable_set(:@object, mock)
|
||||
@receiver.cache?.should be_false
|
||||
end
|
||||
|
||||
it 'returns false if the object is not cacheable' do
|
||||
@receiver.instance_variable_set(:@object, mock(:triggers_caching? => false))
|
||||
@receiver.cache?.should be_false
|
||||
end
|
||||
|
||||
it 'returns false if the object is not of acceptable type for the cache' do
|
||||
@receiver.instance_variable_set(:@object, mock(:triggers_caching? => true, :type => "Photo"))
|
||||
@receiver.cache?.should be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -10,14 +10,6 @@ describe Stream::Multi do
|
|||
it_should_behave_like 'it is a stream'
|
||||
end
|
||||
|
||||
describe '#is_in?' do
|
||||
it 'handles when the cache returns strings' do
|
||||
p = Factory(:status_message)
|
||||
@stream.should_receive(:aspects_post_ids).and_return([p.id.to_s])
|
||||
@stream.send(:is_in?, :aspects, p).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe '#publisher_opts' do
|
||||
it 'prefills, sets public, and autoexpands if welcome? is set' do
|
||||
prefill_text = "sup?"
|
||||
|
|
|
|||
|
|
@ -194,31 +194,6 @@ describe Contact do
|
|||
end
|
||||
end
|
||||
|
||||
describe "#repopulate_cache" do
|
||||
before do
|
||||
@contact = bob.contact_for(alice.person)
|
||||
end
|
||||
|
||||
it "repopulates the cache if the cache exists" do
|
||||
cache = stub(:repopulate!)
|
||||
RedisCache.stub(:configured? => true, :new => cache)
|
||||
|
||||
cache.should_receive(:repopulate!)
|
||||
@contact.repopulate_cache!
|
||||
end
|
||||
|
||||
it "does not touch the cache if it is not configured" do
|
||||
RedisCache.stub(:configured?).and_return(false)
|
||||
RedisCache.should_not_receive(:new)
|
||||
@contact.repopulate_cache!
|
||||
end
|
||||
|
||||
it "gets called on destroy" do
|
||||
@contact.should_receive(:repopulate_cache!)
|
||||
@contact.destroy
|
||||
end
|
||||
end
|
||||
|
||||
describe "#not_blocked_user" do
|
||||
before do
|
||||
@contact = alice.contact_for(bob.person)
|
||||
|
|
|
|||
|
|
@ -229,74 +229,6 @@ describe Post do
|
|||
end
|
||||
end
|
||||
|
||||
describe "triggers_caching?" do
|
||||
it 'returns true' do
|
||||
Post.new.triggers_caching?.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "after_create" do
|
||||
it "calls cache_for_author only on create" do
|
||||
post = Factory.build(:status_message, :author => bob.person)
|
||||
post.should_receive(:cache_for_author).once
|
||||
post.save
|
||||
post.save
|
||||
end
|
||||
end
|
||||
|
||||
describe '#cache_for_author' do
|
||||
before do
|
||||
@post = Factory.build(:status_message, :author => bob.person)
|
||||
@post.stub(:should_cache_for_author?).and_return(true)
|
||||
end
|
||||
|
||||
it 'caches with valid conditions' do
|
||||
cache = mock.as_null_object
|
||||
RedisCache.should_receive(:new).and_return(cache)
|
||||
cache.should_receive(:add)
|
||||
@post.cache_for_author
|
||||
end
|
||||
|
||||
it 'does nothing if should not cache' do
|
||||
@post.stub(:should_cache_for_author?).and_return(false)
|
||||
RedisCache.should_not_receive(:new)
|
||||
@post.cache_for_author
|
||||
end
|
||||
end
|
||||
|
||||
describe "#should_cache_for_author?" do
|
||||
before do
|
||||
@post = Factory.build(:status_message, :author => bob.person)
|
||||
RedisCache.stub(:configured?).and_return(true)
|
||||
RedisCache.stub(:acceptable_types).and_return(['StatusMessage'])
|
||||
@post.stub(:triggers_caching?).and_return(true)
|
||||
end
|
||||
|
||||
it 'returns true under valid conditions' do
|
||||
@post.should_cache_for_author?.should be_true
|
||||
end
|
||||
|
||||
it 'does not cache if the author is not a local user' do
|
||||
@post.author = Factory(:person)
|
||||
@post.should_cache_for_author?.should be_false
|
||||
end
|
||||
|
||||
it 'does not cache if the cache is not configured' do
|
||||
RedisCache.stub(:configured?).and_return(false)
|
||||
@post.should_cache_for_author?.should be_false
|
||||
end
|
||||
|
||||
it 'does not cache if the object does not triggers caching' do
|
||||
@post.stub(:triggers_caching?).and_return(false)
|
||||
@post.should_cache_for_author?.should be_false
|
||||
end
|
||||
|
||||
it 'does not cache if the object is not of an acceptable cache type' do
|
||||
@post.stub(:type).and_return("Photo")
|
||||
@post.should_cache_for_author?.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe "#receive" do
|
||||
it 'returns false if the post does not verify' do
|
||||
@post = Factory(:status_message, :author => bob.person)
|
||||
|
|
|
|||
|
|
@ -91,90 +91,6 @@ describe User do
|
|||
alice.visible_shareable_ids(Post).include?(@status.id).should be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "RedisCache" do
|
||||
before do
|
||||
AppConfig[:redis_cache] = true
|
||||
@opts = {:order => "created_at DESC", :order_field => "created_at", :all_aspects? => true}
|
||||
end
|
||||
|
||||
after do
|
||||
AppConfig[:redis_cache] = nil
|
||||
end
|
||||
|
||||
it "populates the cache if the user has a mutual contact" do
|
||||
RedisCache.any_instance.should_receive(:ensure_populated!)
|
||||
alice.stub(:use_cache?).and_return(true)
|
||||
alice.visible_shareable_ids(Post)
|
||||
end
|
||||
|
||||
it 'does not get used if if all_aspects? option is not present' do
|
||||
RedisCache.should_not_receive(:new)
|
||||
alice.visible_shareable_ids(Post, @opts.merge({:all_aspects? => false}))
|
||||
end
|
||||
|
||||
describe '#use_cache?' do
|
||||
before do
|
||||
cache = mock(:cache_exists? => true, :supported_order? => true, :ensure_populated! => mock, :post_ids => [])
|
||||
RedisCache.stub(:new).and_return(cache)
|
||||
end
|
||||
|
||||
it 'returns true if redis cache is set' do
|
||||
AppConfig[:redis_cache] = true
|
||||
alice.send(:use_cache?, @opts).should be_true
|
||||
end
|
||||
|
||||
it 'returns false if redis cache is set' do
|
||||
AppConfig[:redis_cache] = nil
|
||||
alice.send(:use_cache?, @opts).should be_false
|
||||
end
|
||||
end
|
||||
|
||||
describe '#perform_db_query?' do
|
||||
before do
|
||||
@opts = {:limit => 15}
|
||||
end
|
||||
|
||||
it 'returns true if cache is nil' do
|
||||
alice.send(:perform_db_query?, [1,2,3], nil, @opts).should be_true
|
||||
end
|
||||
|
||||
it 'returns true if cache shareable_ids is blank' do
|
||||
cache = mock(:size => 100)
|
||||
alice.send(:perform_db_query?, [], cache, @opts).should be_true
|
||||
end
|
||||
|
||||
it 'returns true if cache shareable_ids length is less than opts[:limit]' do
|
||||
cache = mock(:size => 100)
|
||||
alice.send(:perform_db_query?, [1,2,3], cache, @opts).should be_true
|
||||
end
|
||||
|
||||
it 'returns false if cache size is less than opts[:limit]' do
|
||||
cache = mock(:size => 10)
|
||||
alice.send(:perform_db_query?, [1,2,3], cache, @opts).should be_false
|
||||
end
|
||||
end
|
||||
|
||||
context 'populated cache' do
|
||||
before do
|
||||
@cache = mock(:cache_exists? => true, :size => 100, :ensure_populated! => mock)
|
||||
RedisCache.stub(:new).and_return(@cache)
|
||||
end
|
||||
|
||||
it "reads from the cache" do
|
||||
@cache.should_receive(:post_ids).and_return([1,2,3])
|
||||
|
||||
alice.visible_shareable_ids(Post, @opts.merge({:limit => 3})).should == [1,2,3]
|
||||
end
|
||||
|
||||
it "queries if maxtime is later than the last cached post" do
|
||||
@cache.stub(:post_ids).and_return([])
|
||||
alice.should_receive(:visible_ids_from_sql)
|
||||
|
||||
alice.visible_shareable_ids(Post, @opts)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#prep_opts" do
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
module Diaspora::WebSocket
|
||||
def self.redis
|
||||
MockRedis.new
|
||||
end
|
||||
end
|
||||
|
||||
class RedisCache
|
||||
def self.redis_connection
|
||||
MockRedis.new
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue