Add couchbase with modifications, formalize broadcaster and make testable and some other stuff

This commit is contained in:
2014-03-06 18:08:39 +01:00
parent 3f117c76b0
commit 0e7a39b819
28 changed files with 456 additions and 35 deletions
+32
View File
@@ -122,4 +122,36 @@ describe List do
end
end
describe '#place_order' do
it 'returns an order object' do
list.place_order(user, product.id => 7).should be_a Order
end
it 'creates an order' do
expect{ list.place_order(user, product.id => 7) }.to change{ Order.count }.by(1)
end
describe 'broadcasting' do
it 'broadcasts to the user and the supplier the active order counter' do
list.place_order(user, product.id => 7)
expect{
list.place_order(user, product.id => 3)
}.to broadcast_to_user(user.id).message('orders_in_process_count').with(count: 2)
expect{
list.place_order(user, product.id => 5)
}.to broadcast_to_supplier(supplier.id).message('orders_in_process_count').with(count: 3)
end
end
it 'sets the list price as kind of caching' do
list.place_order(user, product.id => 7)
list.reload
list.price.should == 3
end
describe 'product order creation'
end
end
+60
View File
@@ -37,4 +37,64 @@ describe Order do
it 'paginates'
end
describe '#is_being_processed!' do
describe 'broadcasting' do
it 'broadcasts order info to the user' do
expect{ order.is_being_processed! }.to broadcast_to_user(user.id).message( 'order_being_processed' ).with(id: order.id, list_id: list.id)
end
describe 'counters' do
before do
# hack some initial values
Qwaiter::Counter.set "supplier:#{supplier.id}:orders_in_process", 7
Qwaiter::Counter.set "supplier:#{supplier.id}:orders_delivered", 9
end
it 'reduces the orders_in_process count and communicates it to user' do
expect{ order.is_being_processed! }.to broadcast_to_user(user.id).message( 'orders_in_process_count' ).with(count: 6)
end
it 'increases the orders_delivered count and communicates it to user' do
expect{ order.is_being_processed! }.to broadcast_to_user(user.id).message( 'orders_delivered_count' ).with(count: 10)
end
it 'reduces the orders_in_process count and communicates it to supplier' do
expect{ order.is_being_processed! }.to broadcast_to_supplier(supplier.id).message( 'orders_in_process_count' ).with(count: 6)
end
it 'increases the orders_in_process count and communicates it to supplier' do
expect{ order.is_being_processed! }.to broadcast_to_supplier(supplier.id).message( 'orders_delivered_count' ).with(count: 10)
end
end
it 'broadcasts order info to the supplier' do
expect{ order.is_being_processed! }.to broadcast_to_supplier(supplier.id).message( 'order_being_processed' ).with(id: order.id, list_id: list.id)
end
end
end
describe '#is_delivered!' do
describe 'broadcasting' do
describe 'counters' do
before do
# hack some initial values
Qwaiter::Counter.set "supplier:#{supplier.id}:orders_in_process", 7
Qwaiter::Counter.set "supplier:#{supplier.id}:orders_delivered", 9
end
it 'decreases the orders_delivered count and communicates it to user' do
expect{ order.is_delivered! }.to broadcast_to_user(user.id).message( 'orders_delivered_count' ).with(count: 8)
end
it 'decreases the orders_in_process count and communicates it to supplier' do
expect{ order.is_delivered! }.to broadcast_to_supplier(supplier.id).message( 'orders_delivered_count' ).with(count: 8)
end
end
end
end
end
+22 -17
View File
@@ -1,62 +1,67 @@
require 'spec_helper'
describe Supplier do
before :each do
@supplier = build :supplier
end
let(:supplier){ build :supplier }
# property open
describe :open do
it 'should be false by default' do
@supplier.open.should == false
supplier.open.should == false
end
it 'should not be open? by default' do
@supplier.open?.should == false
supplier.open?.should == false
end
it 'should be closed? by default' do
@supplier.closed?.should == true
supplier.closed?.should == true
end
describe :mark_as_open! do
before :each do
@supplier.mark_as_open!
supplier.mark_as_open!
end
it 'should be persisted in the database' do
@supplier.reload
@supplier.open.should == true
supplier.reload
supplier.open.should == true
end
it 'should be open?' do
@supplier.open?.should == true
supplier.open?.should == true
end
it 'should not be closed?' do
@supplier.closed?.should == false
supplier.closed?.should == false
end
end
describe :mark_as_closed! do
before :each do
@supplier.mark_as_open!
@supplier.mark_as_closed!
supplier.mark_as_open!
supplier.mark_as_closed!
end
it 'should be persisted in the database' do
@supplier.reload
@supplier.open.should == false
supplier.reload
supplier.open.should == false
end
it 'should be open?' do
@supplier.open?.should == false
supplier.open?.should == false
end
it 'should not be closed?' do
@supplier.closed?.should == true
supplier.closed?.should == true
end
end
end
describe '#decrement_orders_delivered_count!' do
it 'decreases orders_delivered' do
Qwaiter::Counter.set "supplier:#{supplier.id}:orders_delivered", 9
supplier.decrement_orders_delivered_count!.should == 8
end
end
end
+6
View File
@@ -43,6 +43,10 @@ module SpecSelectorHelpers
%x(launchy http://localhost:3000/capybara.html)
end
end
# NOT THREADSAFE!!!!!! but good enough for testing since the real couchbase flush is slowwwwww....
Qwaiter::Counter.connection = InMemoryQCounter.new
RSpec.configure do |config|
# == Mock Framework
#
@@ -56,6 +60,7 @@ RSpec.configure do |config|
config.include FactoryAttributesFor
config.include Devise::TestHelpers, type: :controller
config.include EndWithMatcher
config.include Matchers
config.include Features::BasicHelpers, type: :feature
config.include SpecRouteHelpers, type: :feature
#config.use_transactional_fixtures = true
@@ -98,6 +103,7 @@ RSpec.configure do |config|
config.before :each do
CouchPotato.couchrest_database.recreate!
Qwaiter::Counter.connection.flush
end
config.before :each, type: :feature do
+29
View File
@@ -0,0 +1,29 @@
# This is a non thread safe replacement for the
# couchbase counter mechanism since every test needs
# a clean start and Hash#clear is soooo much faster than
# a couchbase bucket flush
class InMemoryQCounter
STORE = {}
def get(key)
STORE[key]
end
def set(key, value)
STORE[key] = value
end
def incr(key, options = {})
STORE[key] ||= options[:initial].to_i
STORE[key] += 1
end
def decr(key, options = {})
STORE[key] ||= options[:initial].to_i
STORE[key] -= 1
end
def flush
STORE.clear
end
end
@@ -0,0 +1,49 @@
module Matchers
class BroadcastToSupplier
class TestBroadcaster
attr_reader :broadcasts
def initialize
@broadcasts = []
end
def broadcast(object)
self.broadcasts << object
end
end
def initialize(supplier_id)
@supplier_id = supplier_id
end
def matches?(block)
old_broadcaster = Qwaiter.broadcaster
test_broadcaster = TestBroadcaster.new
Qwaiter.broadcaster = test_broadcaster
block.call
Qwaiter.broadcaster = old_broadcaster
relevant_broadcasts = test_broadcaster.broadcasts.select{|b| b[:channel] =~ /^\/supplier\/#{@supplier_id}/ && b[:data][:event] == @message}
@failure_debug_content = "was #{relevant_broadcasts.map{|b| b[:data][:data].inspect}.join(" and ")}"
relevant_broadcasts.any?{|b| b[:data][:data] == @target_object}
end
def message(msg)
@message = msg
self
end
def with(target_object)
@target_object = target_object
self
end
def failure_message
"supplier #{@supplier_id} did not receive broadcast #{@message} with #{@target_object.inspect} #{@failure_debug_content}"
end
end
def broadcast_to_supplier(*args, &block)
BroadcastToSupplier.new(*args, &block)
end
end
@@ -0,0 +1,49 @@
module Matchers
class BroadcastToUser
class TestBroadcaster
attr_reader :broadcasts
def initialize
@broadcasts = []
end
def broadcast(object)
self.broadcasts << object
end
end
def initialize(user_id)
@user_id = user_id
end
def matches?(block)
old_broadcaster = Qwaiter.broadcaster
test_broadcaster = TestBroadcaster.new
Qwaiter.broadcaster = test_broadcaster
block.call
Qwaiter.broadcaster = old_broadcaster
relevant_broadcasts = test_broadcaster.broadcasts.select{|b| b[:channel] =~ /^\/user\/#{@user_id}/ && b[:data][:event] == @message}
@failure_debug_content = "was #{relevant_broadcasts.map{|b| b[:data][:data].inspect}.join(" and ")}"
relevant_broadcasts.any?{|b| b[:data][:data] == @target_object}
end
def message(msg)
@message = msg
self
end
def with(target_object)
@target_object = target_object
self
end
def failure_message
"user #{@user_id} did not receive broadcast #{@message} with #{@target_object.inspect} #{@failure_debug_content}"
end
end
def broadcast_to_user(*args, &block)
BroadcastToUser.new(*args, &block)
end
end