Author: assaf
Date: Mon Jun  2 21:53:34 2008
New Revision: 662651

URL: http://svn.apache.org/viewvc?rev=662651&view=rev
Log:
Now meeting all activity specs.

Modified:
    ode/sandbox/singleshot/app/models/person.rb
    ode/sandbox/singleshot/app/models/task.rb
    ode/sandbox/singleshot/spec/common.rb
    ode/sandbox/singleshot/spec/models/activities.rb
    ode/sandbox/singleshot/spec/models/stakeholder_spec.rb
    ode/sandbox/singleshot/spec/models/task_spec.rb

Modified: ode/sandbox/singleshot/app/models/person.rb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/app/models/person.rb?rev=662651&r1=662650&r2=662651&view=diff
==============================================================================
--- ode/sandbox/singleshot/app/models/person.rb (original)
+++ ode/sandbox/singleshot/app/models/person.rb Mon Jun  2 21:53:34 2008
@@ -117,4 +117,7 @@
     read_attribute(:identity)
   end
 
+  has_many :activities, :dependent=>:delete_all
+  has_many :stakeholders, :dependent=>:delete_all
+
 end

Modified: ode/sandbox/singleshot/app/models/task.rb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/app/models/task.rb?rev=662651&r1=662650&r2=662651&view=diff
==============================================================================
--- ode/sandbox/singleshot/app/models/task.rb (original)
+++ ode/sandbox/singleshot/app/models/task.rb Mon Jun  2 21:53:34 2008
@@ -57,28 +57,12 @@
   # * suspended -- Task is suspended.
   # * completed -- Task has completed.
   # * cancelled -- Task was cancelled.
-  
-  # A task can start as reserved and remain there until populated with enough
-  # information to transition to ready.  From ready, a stakeholder can claim
-  # the task, transitioning it to active.  The task transitions back to ready
-  # if stakeholder releases that claim.
-  #
-  # Task can transition from ready/active to suspended and back.  Task can
-  # transition to completed only from active, and transition to cancelled from
-  # any other state but completed.  Completed and cancelled are terminal
-  # states.
   STATUSES = ['reserved', 'ready', 'active', 'suspended', 'completed', 
'cancelled']
 
-
-  # Cannot change in mass update.
   validates_inclusion_of :status, :in=>STATUSES
 
   # Check method for each status (active?, completed?, etc).
-  STATUSES.each do |status|
-    define_method "#{status}?" do
-      self.status == status
-    end
-  end
+  STATUSES.each { |status| define_method("#{status}?") { self.status == status 
} }
 
   before_validation do |task|
     # Default status is ready.
@@ -86,39 +70,42 @@
     case task.status
     when 'ready'
       # When task first created, if we only have one potential owner, pick 
them as owner.
-      task.owner = task.potential_owners.first unless task.owner || 
task.potential_owners.size > 1
+      task.owner = task.potential_owners.first if task.owner.nil? && 
task.potential_owners.size == 1
       # Assigned task => active.
       task.status = 'active' if task.owner
     when 'active'
       # Unassigned task => ready.
       task.status = 'ready' unless task.owner
-    when 'completed', 'cancelled'
-      # Cannot modify completed/cancelled tasks.
-      task.readonly! unless task.status_changed?
     end
   end
 
   validate do |task|
     # Check state transitions.
     from, to = task.status_change
-    if from == 'completed' 
+    case from # States you cannot transition from.
+    when 'suspended'
+      task.errors.add :status, 'You are not allowed to resume this task.' 
unless task.admin?(task.modified_by)
+    when 'completed'
       task.errors.add :status, 'Cannot change status of completed task.'
-    elsif from == 'cancelled'
+    when 'cancelled'
       task.errors.add :status, 'Cannot change status of cancelled task.'
-    elsif to == 'reserved'
+    end or case to # or, states you cannot transition to.
+    when 'reserved'
       task.errors.add :status, 'Cannot change status to reserved.' unless 
from.nil?
-    elsif to == 'completed'
-      task.errors.add :status, 'Only owner can complete task.' unless 
task.owner
+    when 'active'
+      #task.errors.add :status, "#{task.owner.fullname} is not allowed to 
claim this task." unless
+      #  task.potential_owners.empty? || task.potential_owner?(task.owner) || 
task.admin?(task.owner)
+    when 'suspended'
+      task.errors.add :status, 'You are not allowed to suspend this task.' 
unless task.admin?(task.modified_by)
+    when 'completed'
       task.errors.add :status, 'Cannot change to completed from any status but 
active.' unless from =='active'
+      task.errors.add :status, 'Only owner can complete task.' unless 
task.owner && task.modified_by == task.owner && !task.owner_changed?
+    when 'cancelled'
+      task.errors.add :status, 'You are not allowed to cancel this task.' 
unless task.admin?(task.modified_by)
     end
   end
 
 
-  # -- Common task attributes --
-
-  validates_presence_of :title
-
-
   # -- View and perform ---
 
   # Some tasks are performed offline, for example, calling a customer.  Other
@@ -169,6 +156,11 @@
   validates_url :details_url, :allow_nil=>true
 
 
+  # -- Common task attributes --
+
+  validates_presence_of :title
+
+
   # --- Task data ---
 
   serialize :data
@@ -206,15 +198,17 @@
       new_value = set_role(role, identity)
       changed_attributes[role] = old_value unless 
changed_attributes.has_key?(role) || old_value == new_value
     end
+    define_method("#{role}_changed?") { attribute_changed?(role) }
+    define_method("#{role}_change") { attribute_change(role) }
+    define_method("#{role}_was") { attribute_was(role) }
   end
 
   def creator=(identity)
-    return creator unless new_record?
     set_role 'creator', identity
   end
 
-  ACCESSOR_FROM_ROLE = { 'potential'=>'potential_owners', 
'excluded'=>'excluded_owners', 'observer'=>'observers', 'admin'=>'admins' }
-  ACCESSOR_FROM_ROLE.default = lambda { |role| role }
+  ACCESSOR_FROM_ROLE = { 'creator'=>'creator', 'owner'=>'owner', 
'potential'=>'potential_owners', 'excluded'=>'excluded_owners',
+                         'observer'=>'observers', 'admin'=>'admins' }
 
   # Task observer, admins and potential/excluded owner.  Adds three methods 
for each role:
   # * {plural}            -- Returns people associated with this role.
@@ -252,20 +246,24 @@
     return new_set
   end
 
-  # Can only have one member of a singular role.
-  validate do |record|
+  validate do |task|
+    # Can only have one member of a singular role.
     Stakeholder::SINGULAR_ROLES.each do |role|
-      record.errors.add role, "Can only have one #{role}." if 
record.stakeholders.select { |sh| sh.role == role }.size > 1
+      task.errors.add role, "Can only have one #{role}." if 
task.stakeholders.select { |sh| sh.role == role }.size > 1
     end
-  end
-
-  validate do |record|
-    creator = record.stakeholders.detect { |sh| sh.role == 'creator' }
-    record.errors.add :creator, 'Cannot change creator.' if 
record.changed.include?(:creator) && !record.new_record?
-    record.errors.add :owner, "#{record.owner.fullname} is on the excluded 
owners list and cannot be owner of this task." if
-      record.excluded_owner?(record.owner)
-    conflicting = record.potential_owners & record.excluded_owners
-    record.errors.add :potential_owners, 
"#{conflicting.map(&:fullname).join(', ')} listed on both excluded and 
potential owners list" unless
+    task.errors.add :creator, 'Cannot change creator.' if 
task.creator_changed? && !task.new_record?
+    task.errors.add :owner, "#{task.owner.fullname} is on the excluded owners 
list and cannot be owner of this task." if
+      task.excluded_owner?(task.owner)
+    to, from = task.owner_change
+    if task.potential_owners.empty?
+      # With no potential owners, task must have a set owner.
+      #task.errors.add :owner, "This task intended for one owner." unless 
task.owner || task.reserved?
+    else
+      # We have a limited set of potential owners, owner must be one of them.
+      #task.errors.add :owner, "#{task.owner.fullname} is not allowd as owner 
of this task" unless task.owner && task.potential_owners?(task.owner)
+    end
+    conflicting = task.potential_owners & task.excluded_owners
+    task.errors.add :potential_owners, "#{conflicting.map(&:fullname).join(', 
')} listed on both excluded and potential owners list" unless
       conflicting.empty?
   end
 
@@ -306,6 +304,8 @@
         [ person == task.owner ? 1 : 0, task.can_claim?(person) ? 1 : 0,
           (task.due_on && task.due_on <= today) ? today - task.due_on : -1,
           -task.priority, today - task.created_at.to_date ] }
+        # involved.role <> 'owner'
+        # tasks.priority, tasks.created_at
       self.sort { |a,b| rank[b] <=> rank[a] }
     end
 
@@ -313,52 +313,42 @@
 
 
   # --- Activities ---
- 
-  has_many :activities, :include=>[:task, :person], 
:order=>'activities.created_at DESC'
 
-  # Associate person with all modifications done on this task.
-  # This results in activities linked to the person and task when
-  # the task is saved.
-  def modified_by(person)
-    @modified_by = person
-    self
-  end
+  has_many :activities, :include=>[:task, :person], 
:order=>'activities.created_at DESC', :dependent=>:delete_all
 
   LOG_CHANGE_ATTRIBUTES = [:title, :description, :priority, :due_on]
 
   before_save :unless=>lambda { |task| task.status == 'reserved' } do |task|
-    task.log_activities do |log|
-      if task.status_changed?
-        from, to = task.status_change
-        log.add task.creator, 'created' if from.nil? || from == 'reserved'
-        case to
-        when 'ready'
-          log.add nil, 'resumed' if from == 'suspended'
-          log.add nil, 'released' if from == 'active'
-        when 'active'
-          log.add nil, 'resumed' if from == 'suspended'
-          log.add task.owner, 'is owner of' if task.changed.include?('owner')
-        when 'suspended' then log.add nil, 'suspended'
-        when 'completed' then log.add task.owner, 'completed'
-        when 'cancelled' then log.add nil, 'cancelled'
-        end
-      elsif task.changed.include?('owner')
-        # TODO: get this working!
-        log.add task.owner, 'is owner of'
-      elsif task.changed.any? { |attr| LOG_CHANGE_ATTRIBUTES.include?(attr) }
-        log.add nil, 'changed'
-      end
-    end
-  end
-
-  def log_activities
     log = Hash.new
     def log.add(person, action)
       self[person] = Array(self[person]).push(action)
     end
-    yield log
+    task.log_activities log
     log.each do |person, actions|
-      activities.build :person=>person || @modified_by, 
:action=>actions.to_sentence
+      task.activities.build :person=>person || task.modified_by, 
:action=>actions.to_sentence
+    end
+  end
+
+  def log_activities(log)
+    if status_changed?
+      from, to = status_change
+      log.add creator, 'created' if from.nil? || from == 'reserved'
+      case to
+      when 'ready'
+        log.add nil, 'resumed' if from == 'suspended'
+        log.add nil, 'released' if from == 'active'
+      when 'active'
+        log.add nil, 'resumed' if from == 'suspended'
+        log.add owner, 'is owner of' if changed.include?('owner')
+      when 'suspended' then log.add nil, 'suspended'
+      when 'completed' then log.add owner, 'completed'
+      when 'cancelled' then log.add nil, 'cancelled'
+      end
+    elsif changed.include?('owner')
+      # TODO: get this working!
+      log.add owner, 'is owner of'
+    elsif changed.any? { |attr| LOG_CHANGE_ATTRIBUTES.include?(attr) }
+      log.add nil, 'changed'
     end
   end
   
@@ -411,28 +401,36 @@
 
   # --- Access control ---
 
+  # Person who is modifying this task: required to activity logging and access 
control.
+  attr_reader :modified_by
+
+  # Changes the modified_by person and return self.
+  def modify_by(person)
+    @modified_by = person
+    self
+  end
+
+  after_save do |task|
+    task.modify_by nil
+  end
+
+
   enumerable :cancellation, [:admin, :owner], :default=>:admin
 
-  # Returns true if this person can cancel this task.
   def can_cancel?(person)
-    return false if completed? || cancelled?
-    #return true if person.admin? || admin?(person)
-    #return owner?(person) if cancellation == :owner
-    return true if admin?(person)
-    false
+    admin?(person) && !completed && !cancelled?
   end
 
-  # Returns true if this person can complete this task.
   def can_complete?(person)
     active? && owner?(person)
   end
 
   def can_suspend?(person)
-    admin?(person) && active? || ready? # || person.admin?
+    admin?(person) && (active? || ready? || suspended?)
   end
 
   def can_claim?(person)
-    owner.nil? && potential_owner?(person)
+    owner.nil? && (potential_owners.empty? || potential_owner?(person))
   end
 
   def can_delegate?(person)

Modified: ode/sandbox/singleshot/spec/common.rb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/spec/common.rb?rev=662651&r1=662650&r2=662651&view=diff
==============================================================================
--- ode/sandbox/singleshot/spec/common.rb (original)
+++ ode/sandbox/singleshot/spec/common.rb Mon Jun  2 21:53:34 2008
@@ -5,13 +5,12 @@
     def self.included(base)
       base.after :all do
         Person.delete_all
+        @authenticated = nil
       end
     end
 
     def person(identity)
-      @_people ||= {}
-      @_people[identity.to_s] ||= Person.identify(identity) ||
-        Person.create(:email=>"[EMAIL PROTECTED]", :password=>'secret')
+      Person.identify(identity) || Person.create(:email=>"[EMAIL PROTECTED]", 
:password=>'secret')
     end
 
     def people(*identities)
@@ -19,7 +18,7 @@
     end
 
     def su
-      @_su ||= Person.create(:email=>'[EMAIL PROTECTED]', :admin=>true)
+      Person.identify('super') || Person.create(:email=>'[EMAIL PROTECTED]', 
:admin=>true)
     end
 
     def authenticate(person)
@@ -50,9 +49,9 @@
       base.send :include, Authentication
     end
 
-    def default_task(with = {})
+    def default_task(attributes = {})
       { :title=>'Test this',
-        :outcome_url=>'http://test.host/outcome' }.merge(with)
+        :outcome_url=>'http://test.host/outcome' }.merge(attributes)
     end
 
     def task_with_status(status, attributes = nil)

Modified: ode/sandbox/singleshot/spec/models/activities.rb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/spec/models/activities.rb?rev=662651&r1=662650&r2=662651&view=diff
==============================================================================
--- ode/sandbox/singleshot/spec/models/activities.rb (original)
+++ ode/sandbox/singleshot/spec/models/activities.rb Mon Jun  2 21:53:34 2008
@@ -3,109 +3,123 @@
 describe Activity do
   include Specs::Tasks
 
-  before :all do
-    @person = person('person')
-    @task = Task.create(default_task)
-  end
-
   describe 'person' do
-    it 'should be stored' do
-      Activity.create! :person=>@person, :action=>'created', :task=>@task
-      Activity.last.person.should == @person
+    it 'should be part of activity' do
+      Task.create! default_task(:creator=>person('person'))
+      Activity.last.person.should == person('person')
     end
 
     it 'should be optional' do
-      lambda { Activity.create! :action=>'created', :task=>@task }.should_not 
raise_error
+      lambda { Task.create! default_task }.should_not raise_error
       Activity.last.person.should be_nil
     end
   end
 
   describe 'task' do
-    it 'should be stored' do
-      Activity.create! :person=>@person, :action=>'created', :task=>@task
-      Activity.last.task.should == @task
+    it 'should be part of activity' do
+      Task.create! default_task
+      Activity.last.task.should == Task.last
     end
 
     it 'should be required' do
-      Activity.create(:person=>@person, :action=>'created').should 
have(1).error_on(:task)
+      Activity.create(:person=>person('person'), :action=>'created').should 
have(1).error_on(:task)
     end
   end
 
   describe 'action' do
-    it 'should be stored' do
-      Activity.create! :person=>@person, :action=>'created', :task=>@task
+    it 'should be part of activity' do
+      Task.create! default_task
       Activity.last.action.should == 'created'
     end
 
     it 'should be required' do
-      Activity.create(:person=>@person, :task=>@task).should 
have(1).error_on(:action)
+      Task.create! default_task
+      Activity.create(:person=>person('person'), :task=>Task.last).should 
have(1).error_on(:action)
     end
   end
 
   it 'should have created_at timestamp' do
-    Activity.create!(:person=>@person, :action=>'created', 
:task=>@task).created_at.should be_close(Time.now, 2)
+    Task.create! default_task
+    Activity.last.created_at.should be_close(Time.now, 2)
   end
   
   it 'should allow creation but not modification' do
-    Activity.create! :person=>@person, :action=>'created', :task=>@task
+    Task.create! default_task
     lambda { Activity.last.update_attributes! :action=>'updated' }.should 
raise_error(ActiveRecord::ReadOnlyRecord)
   end
 
+  it 'should delete when destroying task' do
+    Task.create! default_task
+    lambda { Task.last.destroy }.should change(Activity, :count).to(0)
+  end
+
+  it 'should delete when destroying person' do
+    Task.create! default_task(:creator=>person('creator'))
+    lambda { person('creator').destroy }.should change(Activity, :count).to(0)
+  end
+
   describe 'for_dates' do
     it 'should return activities in date range' do
-      # 0 days (today) already created for activity associated with task 
creation.
-      now = Activity.last.created_at
-      activities = (1..3).each do |i|
-        last = Activity.create! :person=>@person, :action=>'created', 
:task=>@task
-        Activity.update_all(['created_at=?', now - i.day], ['id=?', last.id])
+      now = Time.zone.now
+      activities = (0..3).each do |i|
+        Task.create! default_task(:creator=>person('creator'))
+        Activity.update_all ['created_at=?', now - i.day], ['id=?', 
Activity.last.id]
       end
-      Activity.for_dates(now.to_date - 2.days..now.to_date).count == 1
-      Activity.for_dates(now.to_date - 2.days..now.to_date).each do |activity|
-        activity.created_at.should >= now - 2.days and activity.created_at <= 
now.end_of_date
+      min, max = Activity.minimum(:created_at) + 1.day, 
Activity.maximum(:created_at)
+      Activity.for_dates(min.to_date..max.to_date).count == 1
+      Activity.for_dates(min.to_date..max.to_date).each do |activity|
+        activity.created_at.should be_between(min, max)
       end
     end
   end
 
   describe 'for_stakeholder' do
-    before { Activity.delete_all }
 
     it 'should return activities for tasks associated with person' do
       for role in Stakeholder::ALL_ROLES - ['excluded_owners']
-        Task.create! 
default_task.merge(Task::ACCESSOR_FROM_ROLE[role]=>@person)
+        Task.create! 
default_task.merge(Task::ACCESSOR_FROM_ROLE[role]=>person('person'))
       end
-      Activity.for_stakeholder(@person).map(&:task).uniq.size.should == 
Stakeholder::ALL_ROLES.size - 1
+      Activity.for_stakeholder(person('person')).map(&:task).uniq.size.should 
== Stakeholder::ALL_ROLES.size - 1
     end
 
     it 'should not return activities for excluded owners' do
-      Task.create! default_task.merge(:excluded_owners=>@person)
-      Activity.for_stakeholder(@person).should be_empty
+      Task.create! default_task.merge(:excluded_owners=>person('person'))
+      Activity.for_stakeholder(person('person')).should be_empty
     end
 
     it 'should not return activities for other stakeholders' do
       Task.create! default_task.merge(:status=>'reserved', 
:potential_owners=>person('other'))
-      Activity.for_stakeholder(@person).should be_empty
+      Activity.for_stakeholder(person('person')).should be_empty
     end
 
     it 'should return activities for tasks with visible status' do
       for status in Task::STATUSES - ['reserved']
-        task_with_status status, :potential_owners=>@person
+        task_with_status status, :potential_owners=>person('person')
       end
-      Activity.for_stakeholder(@person).map(&:task).uniq.size.should == 
Task::STATUSES.size - 1
+      Activity.for_stakeholder(person('person')).map(&:task).uniq.size.should 
== Task::STATUSES.size - 1
     end
 
     it 'should not return activities for reserved tasks' do
-      Task.create! default_task.merge(:status=>'reserved', 
:potential_owners=>@person)
-      Activity.for_stakeholder(@person).should be_empty
+      Task.create! default_task.merge(:status=>'reserved', 
:potential_owners=>person('person'))
+      Activity.for_stakeholder(person('person')).should be_empty
     end
 
     it 'should return all activities for a visible task' do
       Task.create! default_task.merge(:creator=>person('creator'))
-      Task.last.update_attributes(:owner=>person('owner'))
+      Task.last.update_attributes! :owner=>person('owner')
       Activity.for_stakeholder(person('creator')).should == 
Activity.for_stakeholder(person('owner'))
       Activity.for_stakeholder(person('creator')).map(&:action).should 
include('created', 'is owner of')
       Activity.for_stakeholder(person('owner')).map(&:person).should 
include(person('creator'), person('owner'))
     end
 
+    it 'should return activities from most recent to last' do
+      Task.create! default_task.merge(:creator=>person('creator'))
+      Activity.update_all ['created_at=?', Time.zone.now - 5.seconds]
+      Task.last.update_attributes! :owner=>person('owner')
+      activities = Activity.for_stakeholder(person('creator'))
+      activities.first.created_at.should > activities.last.created_at
+    end
+
   end
 
 end

Modified: ode/sandbox/singleshot/spec/models/stakeholder_spec.rb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/spec/models/stakeholder_spec.rb?rev=662651&r1=662650&r2=662651&view=diff
==============================================================================
--- ode/sandbox/singleshot/spec/models/stakeholder_spec.rb (original)
+++ ode/sandbox/singleshot/spec/models/stakeholder_spec.rb Mon Jun  2 21:53:34 
2008
@@ -9,41 +9,74 @@
     @task = Task.create(default_task)
   end
 
-  it 'should have person' do
-    Stakeholder.create(:task=>@task, :role=>'admin').should 
have(1).error_on(:person)
-  end
+  describe 'person' do
+    it 'should be stored' do
+      Stakeholder.create! :task=>@task, :person=>@person, :role=>'admin'
+      Stakeholder.last.person.should == @person
+    end
 
-  it 'should have task' do
-    lambda { Stakeholder.create(:person=>@person, :role=>'admin') }.should 
raise_error(ActiveRecord::StatementInvalid)
+    it 'should be required' do
+      Stakeholder.create(:task=>@task, :role=>'admin').should 
have(1).error_on(:person)
+    end
   end
 
-  it 'should have role' do
-    Stakeholder.create(:person=>@person, :task=>@task).should 
have(1).error_on(:role)
-  end
 
-  it 'should have supported role' do
-    Stakeholder::ALL_ROLES.each do |role|
-      Stakeholder.create(:person=>@person, :task=>@task, :role=>role).should 
have(:no).errors
+  describe 'task' do
+    it 'should be stored' do
+      Stakeholder.create! :task=>@task, :person=>@person, :role=>'admin'
+      Stakeholder.last.task.should == @task
+    end
+
+    it 'should be required' do
+      lambda { Stakeholder.create(:person=>@person, :role=>'admin') }.should 
raise_error(ActiveRecord::StatementInvalid)
     end
   end
 
-  it 'should not have unsupported role' do
-    ['foo', 'bar'].each do |role|
-      Stakeholder.create(:person=>@person, :task=>@task, :role=>role).should 
have(1).error_on(:role)
+
+  describe 'role' do
+    it 'should be stored' do
+      Stakeholder.create! :task=>@task, :person=>@person, :role=>'admin'
+      Stakeholder.last.role.should == 'admin'
+    end
+
+    it 'should be required' do
+      Stakeholder.create(:person=>@person, :task=>@task).should 
have(1).error_on(:role)
+    end
+
+    it 'should be any valid role names' do
+      Stakeholder::ALL_ROLES.each do |role|
+        Stakeholder.create(:person=>@person, :task=>@task, :role=>role).should 
have(:no).errors
+      end
+    end
+
+    it 'should not allow unknown role names' do
+      ['foo', 'bar'].each do |role|
+        Stakeholder.create(:person=>@person, :task=>@task, :role=>role).should 
have(1).error_on(:role)
+      end
     end
   end
 
+
   it 'should be unique combination of task person and role' do
     Stakeholder.create(:person=>@person, :task=>@task, :role=>'admin').should 
have(:no).errors
     Stakeholder.create(:person=>@person, :task=>@task, 
:role=>'observer').should have(:no).errors
     Stakeholder.create(:person=>@person, :task=>@task, :role=>'admin').should 
have(1).errors_on(:role)
   end
+
+  it 'should be deleted when task destroyed' do
+    Stakeholder.create! :person=>@person, :task=>@task, :role=>'admin'
+    lambda { @task.destroy }.should change(Stakeholder, :count).to(0)
+  end
+
+  it 'should be deleted when person destroyed' do
+    Stakeholder.create! :person=>@person, :task=>@task, :role=>'admin'
+    lambda { @person.destroy }.should change(Stakeholder, :count).to(0)
+  end
+
 end
 
 
 shared_examples_for 'singular role' do
-  include Specs::Tasks
-
   it 'should not be required' do
     Task.create(default_task.except(@role)).should have(:no).errors
   end
@@ -70,75 +103,7 @@
 end
 
 
-describe Task, 'creator' do
-  before { @role = :creator }
-  it_should_behave_like 'singular role'
-
-  it 'should not allow changing creator' do
-    Task.create! default_task.merge(:creator=>person('creator'))
-    Task.last.update_attributes :creator=>person('other')
-    Task.last.creator.should == person('creator')
-  end
-
-  it 'should not allow setting creator on existing task' do
-    Task.create! default_task
-    Task.last.update_attributes :creator=>person('creator')
-    Task.last.creator.should be_nil
-  end
-
-end
-
-
-describe Task, 'owner' do
-  before { @role = :owner }
-  it_should_behave_like 'singular role'
-
-  it 'should allow changing owner on existing task' do
-    Task.create! default_task.merge(:owner=>person('owner'))
-    Task.last.update_attributes! :owner=>person('other')
-    Task.last.owner.should == person('other')
-  end
-
-  it 'should only store one owner association for task' do
-    Task.create! default_task.merge(:owner=>person('owner'))
-    Task.last.update_attributes! :owner=>person('other')
-    Stakeholder.find(:all, :conditions=>{:task_id=>Task.last.id}).size.should 
== 1
-  end
-
-  it 'should allow setting owner to nil' do
-    Task.create! default_task.merge(:owner=>person('owner'))
-    Task.last.update_attributes! :owner=>nil
-    Task.last.owner.should be_nil
-  end
-
-  it 'should not allow owner if listed in excluded owners' do
-    Task.create! default_task.merge(:excluded_owners=>person('excluded'))
-    lambda { Task.last.update_attributes! :owner=>person('excluded') }.should 
raise_error
-    Task.last.owner.should be_nil
-  end
-
-  it 'should be potential owner if task created with one potential owner' do
-    Task.create! default_task.merge(:potential_owners=>person('foo'))
-    Task.last.owner.should == person('foo')
-  end
-
-  it 'should not be potential owner if task created with more than one' do
-    Task.create! default_task.merge(:potential_owners=>people('foo', 'bar'))
-    Task.last.owner.should be_nil
-  end
-
-  it 'should not be potential owner if task updated to have no owner' do
-    Task.create! default_task.merge(:potential_owners=>person('foo'))
-    Task.last.update_attributes! :owner=>person('bar')
-    Task.last.update_attributes! :owner=>nil
-    Task.last.owner.should be(nil)
-  end
-end
-
-
 shared_examples_for 'plural role' do
-  include Specs::Tasks
-
   before do
     @people = person('foo'), person('bar'), person('baz')
   end
@@ -208,31 +173,100 @@
 end
 
 
-describe Task, 'potential_owners' do
-  before { @role = :potential_owners }
-  it_should_behave_like 'plural role'
-
-  it 'should not allow excluded owners' do
-    mixed_up = { :potential_owners=>[person('foo'), person('bar')],
-                 :excluded_owners=>[person('bar'), person('baz')] }
-    Task.create(default_task.merge(mixed_up)).should 
have(1).error_on(:potential_owners)
+describe Task do
+  include Specs::Tasks
+
+  describe 'creator' do
+    before { @role = :creator }
+    it_should_behave_like 'singular role'
+
+    it 'should not allow changing creator' do
+      Task.create! default_task.merge(:creator=>person('creator'))
+      Task.last.update_attributes :creator=>person('other')
+      Task.last.creator.should == person('creator')
+    end
+
+    it 'should not allow setting creator on existing task' do
+      Task.create! default_task
+      Task.last.update_attributes :creator=>person('creator')
+      Task.last.creator.should be_nil
+    end
   end
-end
 
 
-describe Task, 'excluded_owners' do
-  before { @role = :excluded_owners }
-  it_should_behave_like 'plural role'
-end
+  describe 'owner' do
+    before { @role = :owner }
+    it_should_behave_like 'singular role'
+
+    it 'should allow changing owner on existing task' do
+      Task.create! default_task.merge(:owner=>person('owner'))
+      Task.last.update_attributes! :owner=>person('other')
+      Task.last.owner.should == person('other')
+    end
 
+    it 'should only store one owner association for task' do
+      Task.create! default_task.merge(:owner=>person('owner'))
+      Task.last.update_attributes! :owner=>person('other')
+      Stakeholder.find(:all, 
:conditions=>{:task_id=>Task.last.id}).size.should == 1
+    end
 
-describe Task, 'observers' do
-  before { @role = :observers }
-  it_should_behave_like 'plural role'
-end
+    it 'should allow setting owner to nil' do
+      Task.create! default_task.merge(:owner=>person('owner'))
+      Task.last.update_attributes! :owner=>nil
+      Task.last.owner.should be_nil
+    end
 
+    it 'should not allow owner if listed in excluded owners' do
+      Task.create! default_task.merge(:excluded_owners=>person('excluded'))
+      lambda { Task.last.update_attributes! :owner=>person('excluded') 
}.should raise_error
+      Task.last.owner.should be_nil
+    end
 
-describe Task, 'admins' do
-  before { @role = :admins }
-  it_should_behave_like 'plural role'
+    it 'should be potential owner if task created with one potential owner' do
+      Task.create! default_task.merge(:potential_owners=>person('foo'))
+      Task.last.owner.should == person('foo')
+    end
+
+    it 'should not be potential owner if task created with more than one' do
+      Task.create! default_task.merge(:potential_owners=>people('foo', 'bar'))
+      Task.last.owner.should be_nil
+    end
+
+    it 'should not be potential owner if task updated to have no owner' do
+      Task.create! default_task.merge(:potential_owners=>person('foo'))
+      Task.last.update_attributes! :owner=>person('bar')
+      Task.last.update_attributes! :owner=>nil
+      Task.last.owner.should be(nil)
+    end
+  end
+
+
+  describe 'potential_owners' do
+    before { @role = :potential_owners }
+    it_should_behave_like 'plural role'
+
+    it 'should not allow excluded owners' do
+      mixed_up = { :potential_owners=>[person('foo'), person('bar')],
+                   :excluded_owners=>[person('bar'), person('baz')] }
+      Task.create(default_task.merge(mixed_up)).should 
have(1).error_on(:potential_owners)
+    end
+  end
+
+
+  describe 'excluded_owners' do
+    before { @role = :excluded_owners }
+    it_should_behave_like 'plural role'
+  end
+
+
+  describe 'observers' do
+    before { @role = :observers }
+    it_should_behave_like 'plural role'
+  end
+
+
+  describe 'admins' do
+    before { @role = :admins }
+    it_should_behave_like 'plural role'
+  end
 end

Modified: ode/sandbox/singleshot/spec/models/task_spec.rb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/spec/models/task_spec.rb?rev=662651&r1=662650&r2=662651&view=diff
==============================================================================
--- ode/sandbox/singleshot/spec/models/task_spec.rb (original)
+++ ode/sandbox/singleshot/spec/models/task_spec.rb Mon Jun  2 21:53:34 2008
@@ -80,12 +80,17 @@
 
     def task_with_status(status, attributes = nil)
       attributes ||= {}
+      attributes = attributes.reverse_merge(:admins=>person('admin'))
       task = case status
       when 'active'
-        Task.create!(default_task.merge(attributes).merge(:status=>status, 
:owner=>person('owner')))
-      when 'completed'
-        active = 
Task.create!(default_task.merge(attributes).merge(:status=>'active', 
:owner=>person('owner')))
-        active.update_attributes :status=>'completed'
+        Task.create!(default_task.merge(attributes).merge(:status=>'active', 
:owner=>person('owner')))
+      when 'completed' # Start as active, modified by owner.
+        active = task_with_status('active', attributes)
+        active.modify_by(person('owner')).update_attributes! 
:status=>'completed'
+        active
+      when 'cancelled', 'suspended' # Start as active, modified by admin.
+        active = task_with_status('active', attributes)
+        active.modify_by(person('admin')).update_attributes! :status=>status
         active
       else
         Task.create!(default_task.merge(attributes).merge(:status=>status))
@@ -93,7 +98,7 @@
 
       def task.transition_to(status, attributes = nil)
         attributes ||= {}
-        update_attributes attributes.merge(:status=>status)
+        modify_by(attributes.delete(:modified_by) || 
Person.identify('admin')).update_attributes attributes.merge(:status=>status)
         self
       end
       def task.can_transition?(status, attributes = nil)
@@ -146,8 +151,8 @@
       lambda { task.update_attributes :owner=>nil }.should change(task, 
:status).to('ready')
     end
 
-    it 'should accept suspended as initial value' do
-      Task.create!(default_task.merge(:status=>'suspended')).status.should == 
'suspended'
+    it 'should not accept suspended as initial value' do
+      Task.create(default_task.merge(:status=>'suspended')).should 
have(1).error_on(:status)
     end
 
     it 'should transition from ready to suspended' do
@@ -170,7 +175,7 @@
 
     it 'should only transition to completed from active' do
       for status in Task::STATUSES - ['completed']
-        task_with_status(status).can_transition?('completed').should == 
(status =='active')
+        task_with_status(status).can_transition?('completed', 
:modified_by=>person('owner')).should == (status =='active')
       end
     end
 
@@ -185,7 +190,7 @@
     end
 
     it 'should transition to cancelled from any other status but completed' do
-      for status in Task::STATUSES - ['cancelled']
+      for status in Task::STATUSES - ['reserved', 'cancelled']
         task_with_status(status).can_transition?('cancelled').should == 
(status !='completed')
       end
     end


Reply via email to