Skip to content

Commit

Permalink
FIXED: attempts to use referenced blips, which are not defined, cause…
Browse files Browse the repository at this point in the history
…s error.
  • Loading branch information
bil-bas committed Dec 5, 2009
1 parent 123260f commit cc3e18d
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 16 deletions.
60 changes: 58 additions & 2 deletions lib/models/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
module Rave
module Models
class Context
attr_reader :waves, :wavelets, :blips, :operations, :users
attr_reader :waves, :wavelets, :blips, :operations, :users, :primary_wavelet

JAVA_CLASS = 'com.google.wave.api.impl.OperationMessageBundle' # :nodoc:

Expand All @@ -14,15 +14,71 @@ class Context
def initialize(options = {})
@waves = options[:waves] || {}
@waves.values.each { |wave| wave.context = self } #Set up self as this wave's context

@wavelets = options[:wavelets] || {}
@wavelets.values.each { |wavelet| wavelet.context = self } #Set up self as this wavelet's context
@primary_wavelet = @wavelets.values[0] # As opposed to any that are created later.

@blips = options[:blips] || {}
@blips.values.each { |blip| blip.context = self } #Set up self as this blip's context

@operations = options[:operations] || []

@users = options[:users] || {}
@users.values.each { |user| user.context = self } #Set up self as this user's context

resolve_blip_references
end


protected
# Resolve references to blips that otherwise aren't defined.
# NOTE: Should only be called during initialisation, since
# operation-generated blips can't have virtual references.
def resolve_blip_references # :nodoc:
@blips.values.each do |blip|
# Resolve virtual children.
blip.child_blip_ids.each do |child_id|
unless child_id.nil?
child = @blips[child_id]
if child.nil?
child = Blip.new(:id => child_id, :parent_blip_id => blip.id,
:wavelet_id => blip.wavelet.id)
add_blip(child)
else
# Since a child might have been created due to a reference from
# one of its real children, we still need to ensure that it knows
# about us.
if child.parent_blip_id.nil?
child.instance_eval do
@parent_blip_id = blip.id # TODO: unhack this!
end
end
end
end
end

# Resolve virtual parent.
unless blip.parent_blip_id.nil?
parent = @blips[blip.parent_blip_id]
if parent.nil?
parent = Blip.new(:id => blip.parent_blip_id, :child_blip_ids => [blip.id],
:wavelet_id => blip.wavelet.id)
add_blip(parent)
else
# Since there might be multiple "real" children, ensure that even
# if we don't have to create the virtual parent, ensure that
# it knows about us.
unless parent.child_blip_ids.include? blip.id
parent.instance_eval do
@child_blip_ids << blip.id # TODO: unhack this!
end
end
end
end
end
end

public
# Add a blip to blips (Use an Operation to actually add the blip to the Wave).
def add_blip(blip) # :nodoc:
@blips[blip.id] = blip
Expand Down
13 changes: 12 additions & 1 deletion lib/models/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ def initialize(options = {})
@modified_by = options[:modified_by]
@properties = options[:properties] || {}
@context = options[:context]

raise ArgumentError.new(":context option required") if @context.nil?
end

# Event factory.
Expand All @@ -41,7 +43,7 @@ def initialize(options = {})
def self.create(options = {})
event_class = EVENT_CLASSES.find { |e| e.type == options[:type] }

raise "Unknown event type #{options[:type]}" if event_class.nil?
raise ArgumentError.new("Unknown event type #{options[:type]}") if event_class.nil?

options[:type] = nil
event_class.new(options)
Expand Down Expand Up @@ -156,6 +158,15 @@ def self.type; BLIP_SUBMITTED; end

class BlipDeletedEvent < Event
def self.type; BLIP_DELETED; end

def initialize(options = {}) # :nodoc:
super(options)
# Create a virtual blip to represent the one deleted.
if @context.blips[@properties['blipId']].nil?
@context.add_blip(Blip.new(:id => @properties['blipId'],
:wavelet_id => @context.primary_wavelet.id))
end
end
end

# General events.
Expand Down
34 changes: 33 additions & 1 deletion spec/model/test_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,37 @@
context.print_structure.should == "Wave:w+wave\n"
end
end


describe "primary_wavelet" do
it "should be the wavelet defined when creating the context" do
wavelet = Wavelet.new(:id => "w+wavelet")
context = Context.new(:wavelets => {'w+wavelet' => wavelet })

context.primary_wavelet.should == wavelet
end
end

describe "initialize()" do
it "should create a virtual child blips that are only in the json as a reference" do
blip = Blip.new(:id => "b+blip", :child_blip_ids => ["b+undef1", "b+undef2", "b+undef3"])
context = Context.new( :blips => { blip.id => blip })

blip.child_blips.size.should == 3
blip.child_blips.each_with_index do |child, i|
child.id.should == "b+undef#{i + 1}"
child.parent_blip.should == blip
context.blips[child.id].should == child
end
end

it "should return virtual parent blip that is only in the json as reference" do
blip = Blip.new(:id => "b+blip", :parent_blip_id => "b+undef")
context = Context.new(:blips => { blip.id => blip })

parent = blip.parent_blip
parent.id.should == "b+undef"
parent.child_blips.should == [blip]
context.blips[parent.id].should == parent
end
end
end
47 changes: 43 additions & 4 deletions spec/model/test_event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,22 @@
describe "create()" do
it "should return the appropriate event sub-class for all valid events" do
Rave::Models::Event::EVENT_CLASSES.each do |event|
Rave::Models::Event.create(:type => event.type).should be_a_kind_of event
Rave::Models::Event.create(:type => event.type,
:context => Context.new).should be_a_kind_of event
end
end

it "should raise an exception for an invalid event" do
lambda { Rave::Models::Event.create(:type => "INVALID_EVENT") }.should raise_error Exception
lambda { Rave::Models::Event.create(:type => "INVALID_EVENT",
:context => Context.new) }.should raise_error Exception
end

it "should raise an exception without a context given" do
lambda { Rave::Models::Event.create(:type => "BLIP_DELETED") }.should raise_error ArgumentError
end

it "should raise an exception without a type specified" do
lambda { Rave::Models::Event.create }.should raise_error Exception
lambda { Rave::Models::Event.create }.should raise_error ArgumentError
end
end

Expand All @@ -43,5 +49,38 @@
Rave::Models::Event::BlipSubmittedEvent.type.should == 'BLIP_SUBMITTED'
end
end


describe Rave::Models::Event::BlipDeletedEvent do
describe "blip" do
it "should return a virtual blip if it is not referenced anywhere" do
wavelet = Wavelet.new(:id => "w+wavelet")
context = Context.new(:wavelets => {'w+wavelet' => wavelet })
event = Rave::Models::Event::BlipDeletedEvent.new(:context => context,
:properties => { 'blipId' => 'b+undef' })

deleted_blip = event.blip
deleted_blip.id.should == 'b+undef'
deleted_blip.parent_blip.should be_nil
deleted_blip.child_blips.should == []
deleted_blip.wavelet.should == wavelet
context.blips['b+undef'].should == deleted_blip
end

it "should return a generated blip if it is already referenced from another blip" do
blip = Blip.new(:id => 'b+blip', :parent_blip_id => 'b+undef', :wavelet_id => 'w+wavelet')
wavelet = Wavelet.new(:id => "w+wavelet")
context = Context.new(:blips => {'b+blip' => blip}, :wavelets => {'w+wavelet' => wavelet })
event = Rave::Models::Event::BlipDeletedEvent.new(:context => context,
:properties => { 'blipId' => 'b+undef' })

deleted_blip = event.blip
deleted_blip.should == blip.parent_blip
deleted_blip.id.should == 'b+undef'
deleted_blip.parent_blip.should be_nil
deleted_blip.child_blips.should == [blip]
deleted_blip.wavelet.should == wavelet
context.blips['b+undef'].should == deleted_blip
end
end
end
end
16 changes: 8 additions & 8 deletions spec/model/test_robot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ def handler2(event, context)

describe "handle_event()" do
it "should ignore unhandled events" do
event = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_TITLE_CHANGED)
event = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_TITLE_CHANGED, :context => Context.new)
@obj.handle_event(event, Context.new)
@obj.instance_eval do
@handled.should == nil
end
end
it "should call the given handler" do
event = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_VERSION_CHANGED)
event = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_VERSION_CHANGED, :context => Context.new)
@obj.register_handler(event.type, :handler1)
@obj.handle_event(event, Context.new)
@obj.instance_eval do
Expand All @@ -92,8 +92,8 @@ def handler2(event, context)

describe "capabilities_xml()" do
it "should return the list of capabilities" do
event1 = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_TITLE_CHANGED)
event2 = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_VERSION_CHANGED)
event1 = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_TITLE_CHANGED, :context => Context.new)
event2 = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_VERSION_CHANGED, :context => Context.new)
cron1 = [:cron_handler1, 60]
cron2 = [:cron_handler2, 3600]
@obj.register_handler(event1.type, :handler1)
Expand All @@ -104,8 +104,8 @@ def handler2(event, context)
end

it "should not include an empty crons tag" do
event1 = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_TITLE_CHANGED)
event2 = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_VERSION_CHANGED)
event1 = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_TITLE_CHANGED, :context => Context.new)
event2 = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_VERSION_CHANGED, :context => Context.new)
@obj.register_handler(event1.type, :handler1)
@obj.register_handler(event2.type, :handler2)
@obj.capabilities_xml.should == "<?xml version=\"1.0\" encoding=\"UTF-8\"?><w:robot xmlns:w=\"http://wave.google.com/extensions/robots/1.0\"><w:version>1</w:version><w:capabilities><w:capability name=\"DOCUMENT_CHANGED\"/><w:capability name=\"WAVELET_TITLE_CHANGED\"/><w:capability name=\"WAVELET_VERSION_CHANGED\"/></w:capabilities><w:profile name=\"testbot\" imageurl=\"http://localhost/image\" profileurl=\"http://localhost/profile\"/></w:robot>"
Expand All @@ -116,8 +116,8 @@ def handler2(event, context)
@image_url = nil
@profile_url = nil
end
event1 = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_TITLE_CHANGED)
event2 = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_VERSION_CHANGED)
event1 = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_TITLE_CHANGED, :context => Context.new)
event2 = Rave::Models::Event.create(:type => Rave::Models::Event::WAVELET_VERSION_CHANGED, :context => Context.new)
cron1 = [:cron_handler1, 60]
cron2 = [:cron_handler2, 3600]
@obj.register_handler(event1.type, :handler1)
Expand Down

0 comments on commit cc3e18d

Please sign in to comment.