You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ode.apache.org by as...@apache.org on 2007/12/12 00:14:43 UTC

svn commit: r603406 [3/3] - in /ode/sandbox/singleshot: ./ app/controllers/ app/helpers/ app/models/ app/views/layouts/ app/views/sandwiches/ app/views/sessions/ app/views/tasks/ config/ config/environments/ config/initializers/ db/migrate/ doc/pages/ ...

Modified: ode/sandbox/singleshot/spec/controllers/tasks_controller_spec.rb
URL: http://svn.apache.org/viewvc/ode/sandbox/singleshot/spec/controllers/tasks_controller_spec.rb?rev=603406&r1=603405&r2=603406&view=diff
==============================================================================
--- ode/sandbox/singleshot/spec/controllers/tasks_controller_spec.rb (original)
+++ ode/sandbox/singleshot/spec/controllers/tasks_controller_spec.rb Tue Dec 11 15:14:39 2007
@@ -7,7 +7,7 @@
 
 describe TasksController, 'authentication' do
 
-  include Specs::Authentication, Specs::Tasks
+  include Specs::Tasks
 
   before :all do
     @person = person('assaf')
@@ -22,40 +22,40 @@
   end
 
   it 'should use session authentication for HTML requests' do
-    post :create, :task=>default_values
+    post :create, :task=>default_task
     response.should redirect_to(session_url)
   end
 
   it 'should accept session authentication' do
     session_authenticate @person
     Task.should_receive(:create!)
-    post :create, :task=>default_values
+    post :create, :task=>default_task
   end
 
   it 'should use HTTP Basic authentication for XML requests' do
-    post :create, :task=>default_values, :format=>'xml'
+    post :create, :task=>default_task, :format=>'xml'
     response.should be_unauthorized
   end
 
   it 'should use HTTP Basic authentication for JSON requests' do
-    post :create, :task=>default_values, :format=>'json'
+    post :create, :task=>default_task, :format=>'json'
     response.should be_unauthorized
   end
 
   it 'should use HTTP Basic authentication if authentication header provider' do
     http_authenticate 'assaf', 'wrong'
-    post :create, :task=>default_values
+    post :create, :task=>default_task
     response.should be_unauthorized
   end
 
   it 'should accept HTTP Basic authentication' do
     http_authenticate 'assaf', 'secret'
     Task.should_receive(:create!)
-    post :create, :task=>default_values
+    post :create, :task=>default_task
   end
 
   it 'should redirect to login page with return to self' do
-    post :create, :task=>default_values
+    post :create, :task=>default_task
     response.should redirect_to(session_url)
     flash[:return_to].should match(/^http:\/\/test.host\/tasks/)
   end
@@ -65,7 +65,7 @@
 
 describe TasksController, 'POST /tasks' do
 
-  include Specs::Authentication, Specs::Tasks
+  include Specs::Tasks
 
   before :each do
     authenticate person('assaf')
@@ -75,33 +75,44 @@
     route_for(:controller=>'tasks', :action=>'create').should eql('/tasks')
   end
 
-  it 'should err if not task specified' do
-    post :create
-    response.should be_bad_request
-    response.should have_text(/missing task/i)
+  it 'should create empty task if no input provided' do
+    post :create, :format=>'json'
+    response.should be_see_other
+    task = Task.find(:first)
+    task.should be_reserved
+    response.headers['Location'].should eql(task_url(task))
+  end
+
+  it 'should create task from supplied inputs' do
+    post :create, :task=>default_task, :format=>'json'
+    response.should be_created
+    task = Task.find(:first)
+    task.should be_active
+    response.headers['Location'].should eql(task_url(task))
+    default_task.each { |key, val| task.send(key).should eql(val) }
   end
 
   it 'should infer XML as outcome MIME type from accepted content type' do
     request.headers['CONTENT_TYPE'] = Mime::XML.to_s
-    post :create, :task=>default_values
-    Task.find(:first).outcome_type.should eql(Mime::XML)
+    post :create, :task=>default_task
+    Task.find(:first).outcome_type.should eql(Mime::XML.to_s)
   end
 
   it 'should infer JSON as outcome MIME type from accepted content type' do
     request.headers['CONTENT_TYPE'] = Mime::JSON.to_s
-    post :create, :task=>default_values
-    Task.find(:first).outcome_type.should eql(Mime::JSON)
+    post :create, :task=>default_task
+    Task.find(:first).outcome_type.should eql(Mime::JSON.to_s)
   end
 
   it 'should default to XML as outcome MIME type for all other content types' do
-    post :create, :task=>default_values
-    Task.find(:first).outcome_type.should eql(Mime::XML)
+    post :create, :task=>default_task
+    Task.find(:first).outcome_type.should eql(Mime::XML.to_s)
   end
 
   it 'should ignore outcome MIME type in request' do
     request.headers['CONTENT_TYPE'] = Mime::JSON.to_s
-    post :create, :task=>default_values.merge(:outcome_type=>'application/xml')
-    Task.find(:first).outcome_type.should eql(Mime::JSON)
+    post :create, :task=>default_task.merge(:outcome_type=>'application/xml')
+    Task.find(:first).outcome_type.should eql(Mime::JSON.to_s)
   end
 
   it 'should add authenticated user as task admin' do
@@ -110,7 +121,7 @@
       admins.size.should eql(1)
       admins.should include(person('assaf'))
     end
-    post :create, :task=>default_values
+    post :create, :task=>default_task
   end
 
   it 'should set authenticated user as task admin' do
@@ -119,19 +130,18 @@
       admins.size.should eql(2)
       admins.should include(person('assaf'), 'alex')
     end
-    post :create, :task=>default_values.merge(:admins=>['alex'])
+    post :create, :task=>default_task.merge(:admins=>['alex'])
   end
 
 end
 
 
 describe TasksController, 'GET /tasks/{id}' do
-  include Specs::Authentication, Specs::Tasks
+  include Specs::Tasks
 
   before :each do
-    authenticate person('admin')
-    @task = Task.create(default_values.merge(:admins=>authenticated, :owner=>person('owner'),
-      :creator=>person('creator'), :potential_owners=>person('potential')))
+    @task = Task.create(default_task.merge(@roles = all_roles))
+    authenticate person(@roles[:admins].first)
   end
 
   it 'should map to /tasks/{id}' do
@@ -143,6 +153,11 @@
     lambda { get :show, :id=>0 }.should raise_error(ActiveRecord::RecordNotFound)
   end
 
+  it 'should 404 if task not yet active' do
+    task = Task.reserve!(authenticated)
+    lambda { get :show, :id=>task.id }.should raise_error(ActiveRecord::RecordNotFound)
+  end
+
   it 'should 404 if task already cancelled' do
     @task.status = :cancelled ; @task.save!
     lambda { get :show, :id=>@task.id }.should raise_error(ActiveRecord::RecordNotFound)
@@ -153,232 +168,710 @@
     lambda { get :show, :id=>@task.id }.should raise_error(ActiveRecord::RecordNotFound)
   end
 
-  it 'should not be visible to excluded owners'
+  it 'should not be visible to admin' do
+    lambda { get :show, :id=>@task.id }.should_not raise_error
+  end
+
+  it 'should not be visible to owner' do
+    authenticate @roles[:owner]
+    lambda { get :show, :id=>@task.id }.should_not raise_error
+  end
+
+  it 'should not be visible to potential owner' do
+    authenticate @roles[:potential_owners].first
+    lambda { get :show, :id=>@task.id }.should_not raise_error
+  end
+
+  it 'should not be visible to excluded owners' do
+    authenticate @task.potential_owners[1]
+    @task.update_attributes! :excluded_owners=>[authenticated]
+    lambda { get :show, :id=>@task.id }.should raise_error(ActiveRecord::RecordNotFound)
+  end
 
 end
 
 
-describe TasksController, 'PUT /tasks/{id}' do
-  include Specs::Authentication, Specs::Tasks
 
-  before :each do
-    authenticate person('admin')
-    @task = Task.create(default_values.merge(:admins=>authenticated, :owner=>person('owner'),
-      :creator=>person('creator'), :potential_owners=>person('potential')))
+describe TasksController, 'PUT task', :shared=>true do
+  include Specs::Tasks
+
+  before :all do
+    @admin, @owner = people('admin', 'owner')
+    @observer, @excluded = people('observer', 'excluded')
+    @potential = people('potential', 'potential2')
   end
 
+  before :each do
+    @task = Task.create!(default_task.merge(:admins=>@admin, :potential_owners=>@potential,
+      :excluded_owners=>@excluded, :observers=>@observer))
+    controller.use_rails_error_handling!
+  end
+  
   it 'should map to /tasks/{id}' do
-    route_for(:controller=>'tasks', :action=>'update', :id=>1).should eql('/tasks/1')
+    route_for(:controller=>'tasks', :action=>'update', :id=>@task.id).should eql("/tasks/#{@task.id}")
     lambda { route_for(:controller=>'tasks', :action=>'update') }.should raise_error(ActionController::RoutingError)
   end
 
+end
+
+describe TasksController, 'PUT reserved task' do
+  include Specs::Tasks
+
+  before :each do
+    authenticate person('admin')
+    @task = Task.reserve!(authenticated)
+    controller.use_rails_error_handling!
+  end
+  
   it 'should 400 if no input provided' do
-    put :update, :id=>0
+    put :update, :id=>@task.id
     response.should be_bad_request
+    @task.reload.should be_reserved
   end
 
-  it 'should 404 if task not found' do
-    lambda { put :update, :id=>0, :task=>{} }.should raise_error(ActiveRecord::RecordNotFound)
+  it 'should 404 if not associated with task' do
+    authenticate person('unknown')
+    put :update, :id=>@task.id, :task=>default_task
+    response.should be_not_found
+    @task.reload.should be_reserved
   end
 
-  it 'should 404 if task already cancelled' do
-    @task.status = :cancelled ; @task.save!
-    lambda { put :update, :id=>@task.id, :task=>{} }.should raise_error(ActiveRecord::RecordNotFound)
+  it 'should 200 and redirect back if task updated' do
+    put :update, :id=>@task.id, :task=>default_task
+    response.should redirect_to(task_url)
   end
 
-  it 'should 404 unless allowed to view task' do
-    authenticate person('noone')
-    lambda { put :update, :id=>@task.id, :task=>{} }.should raise_error(ActiveRecord::RecordNotFound)
+  it 'should update task' do
+    put :update, :id=>@task.id, :task=>default_task
+    @task.reload
+    default_task.each do |key, value|
+      @task.send(key).should eql(value)
+    end
+  end
+
+  it 'should change task status to active' do
+    put :update, :id=>@task.id, :task=>default_task
+    @task.reload.should be_active
+  end
+
+  it 'should retain task administrator if no admins specified' do
+    put :update, :id=>@task.id, :task=>default_task.except(:admins)
+    @task.reload.admins.should eql([authenticated])
+  end
+
+  it 'should retain authenticated admin when other admins specified' do
+    admins = people('foo', 'bar')
+    put :update, :id=>@task.id, :task=>default_task.merge(:admins=>admins)
+    @task.reload.admins.sort_by(&:id).should eql([authenticated] + admins)
   end
 
+  it 'should 422 if task does not validate' do
+    put :update, :id=>@task.id, :task=>default_task.except(:title)
+    response.should be_unprocessable_entity
+  end
+
+  it 'should determine outcome type from content type if XML' do
+    request.headers['CONTENT_TYPE'] = 'application/xml'
+    put :update, :id=>@task.id, :task=>default_task
+    @task.reload.outcome_type.should eql('application/xml')
+  end
+
+  it 'should determine outcome type from content type if JSON' do
+    request.headers['CONTENT_TYPE'] = 'application/json'
+    put :update, :id=>@task.id, :task=>default_task
+    @task.reload.outcome_type.should eql('application/json')
+  end
 
+  it 'should allow changing of outcome type' do
+    put :update, :id=>@task.id, :task=>default_task.merge(:outcome_type=>'application/json')
+    @task.reload.outcome_type.should eql('application/json')
+  end
+ 
 end
 
+describe TasksController, 'PUT active task' do
+  it_should_behave_like 'TasksController PUT task'
 
-describe TasksController, 'DELETE /tasks/{id}' do
-  include Specs::Authentication, Specs::Tasks
+  it 'should 400 if no task input provided' do
+    authenticate @admin
+    put :update, :id=>@task.id
+    response.should be_bad_request
+  end
 
-  before :each do
-    authenticate person('admin')
-    @task = Task.create(default_values.merge(:admins=>authenticated, :owner=>person('owner'),
-      :creator=>person('creator'), :potential_owners=>person('potential')))
+  it 'should 404 if not associated with task' do
+    authenticate person('unknown')
+    put :update, :id=>@task.id, :task=>default_task
+    response.should be_not_found
   end
 
-  it 'should map to /tasks/{id}' do
-    route_for(:controller=>'tasks', :action=>'destroy', :id=>1).should eql('/tasks/1')
-    lambda { route_for(:controller=>'tasks', :action=>'destroy') }.should raise_error(ActionController::RoutingError)
+  it 'should allow administrator to change task' do
+    authenticate @admin
+    put :update, :id=>@task.id, :task=>{ :title=>'changed', :data=>{ 'foo'=>'bar'  } }
+    @task.reload.title.should eql('changed')
+    @task.data.should == { 'foo'=>'bar' }
   end
 
-  it 'should 404 if task not found' do
-    lambda { delete :destroy, :id=>0 }.should raise_error(ActiveRecord::RecordNotFound)
+  it 'should allow administrator to assign task' do
+    authenticate @admin
+    put :update, :id=>@task.id, :task=>{ :owner=>@potential.first }
+    @task.reload.owner.should eql(@potential.first)
   end
 
-  it 'should 404 if task already cancelled' do
-    @task.status = :cancelled ; @task.save!
-    lambda { delete :destroy, :id=>@task.id }.should raise_error(ActiveRecord::RecordNotFound)
+  it 'should not allow administrator to assign to excluded owner' do
+    authenticate @admin
+    put :update, :id=>@task.id, :task=>{ :owner=>@excluded }
+    response.should be_client_error
   end
 
-  it 'should 404 unless allowed to view task' do
-    authenticate person('noone')
-    lambda { delete :destroy, :id=>@task.id }.should raise_error(ActiveRecord::RecordNotFound)
+  it 'should allow potential owner to claim task' do
+    authenticate @potential.first
+    put :update, :id=>@task.id, :task=>{ :owner=>@potential.first }
+    @task.reload.owner.should eql(@potential.first)
+  end
+
+  it 'should 404 if excluded owner attempts to claim task' do
+    authenticate @excluded
+    put :update, :id=>@task.id, :task=>{ :owner=>@excluded }
+    response.should be_not_found
+  end
+
+  it 'should not allow anyone but administrator to assign task' do
+    authenticate @potential.first
+    put :update, :id=>@task.id, :task=>{ :owner=>@observer }
+    @task.reload.owner.should be_nil
+  end
+
+  it 'should 200 and redirect back after update' do
+    authenticate @admin
+    put :update, :id=>@task.id, :task=>{}
+    response.should redirect_to(task_url)
   end
 
-  it 'should 403 if task already completed' do
-    @task.status = :completed ; @task.save!
-    delete :destroy, :id=>@task.id, :format=>'xml'
+  it 'should keep task status as active' do
+    authenticate @admin
+    put :update, :id=>@task.id, :task=>{}
+    @task.reload.should be_active
+  end
+
+  it 'should allow adminstrator to change status to suspended' do
+    authenticate @admin
+    put :update, :id=>@task.id, :task=>{ :status=>'suspended' }
+    @task.reload.should be_suspended
+  end
+
+  it 'should 403 if anyone else attempts to change task' do
+    authenticate @observer
+    put :update, :id=>@task.id, :task=>{}
+    response.should be_forbidden
+  end
+
+  it 'should allow changing of outcome type' do
+    authenticate @admin
+    put :update, :id=>@task.id, :task=>{ :outcome_type=>'application/json' }
+    @task.reload.outcome_type.should eql('application/json')
+  end
+
+  it 'should not change outcome type unless specified' do
+    request.headers['CONTENT_TYPE'] = 'application/json'
+    @task.update_attributes! :outcome_type=>'application/json'
+    authenticate @admin
+    put :update, :id=>@task.id, :task=>{}
+    @task.reload.outcome_type.should eql('application/json')
+  end
+ 
+end
+
+describe TasksController, 'PUT claimed task' do
+  it_should_behave_like 'TasksController PUT task'
+
+  before(:each) { @task.owner = @owner ; @task.save! }
+
+  it 'should allow owner to release task if other potential owners' do
+    authenticate @owner
+    put :update, :id=>@task.id, :task=>{ :owner=>nil }
+    @task.reload.owner.should be_nil
+  end
+
+  it 'should allow owner to delegate task' do
+    authenticate @owner
+    put :update, :id=>@task.id, :task=>{ :owner=>@observer }
+    @task.reload.owner.should eql(@observer)
+  end
+
+  it 'should not allow assigning to excluded owner' do
+    authenticate @owner
+    put :update, :id=>@task.id, :task=>{ :owner=>@excluded }
+    response.should be_client_error
+    response.should have_text(/excluded owner/i)
+  end
+
+  it 'should allow owner to change task data' do
+    authenticate @owner
+    put :update, :id=>@task.id, :task=>{ :title=>'changed', :data=>{ 'foo'=>'bar'  } }
+    @task.reload.title.should eql(default_task[:title])
+    @task.data.should == { 'foo'=>'bar' }
+  end
+
+  it 'should allow administrator to change task state' do
+    authenticate @admin
+    put :update, :id=>@task.id, :task=>{ :title=>'changed', :data=>{ 'foo'=>'bar'  } }
+    @task.reload.title.should eql('changed')
+    @task.data.should == { 'foo'=>'bar' }
+  end
+
+  it 'should 403 if potential owner attempts to change task' do
+    authenticate @potential.first
+    put :update, :id=>@task.id, :task=>{ }
+    response.should be_forbidden
+  end
+
+  it 'should 403 if potential owner claims task' do
+    authenticate @potential.first
+    put :update, :id=>@task.id, :task=>{ :owner=>@potential.first }
+    response.should be_forbidden
+  end
+
+  it 'should 403 if owner releases task and no potential owners' do
+    @task.update_attributes! :potential_owners=>@owner
+    authenticate @owner
+    put :update, :id=>@task.id, :task=>{ :owner=>nil }
+    response.should be_forbidden
+  end
+
+end
+
+
+describe TasksController, 'PUT suspended task' do
+  it_should_behave_like 'TasksController PUT task'
+
+  before(:each) { @task.owner = @owner ; @task.status = :suspended ; @task.save! }
+
+  it 'should allow admin to change task' do
+    authenticate @admin
+    put :update, :id=>@task.id, :task=>{ :title=>'changed', :data=>{ 'foo'=>'bar'  } }
+    @task.reload.title.should eql('changed')
+    @task.data.should == { 'foo'=>'bar' }
+  end
+
+  it 'should keep task suspended' do
+    authenticate @admin
+    put :update, :id=>@task.id, :task=>{}
+    @task.reload.should be_suspended
+  end
+
+  it 'should allow admin to change status to active' do
+    authenticate @admin
+    put :update, :id=>@task.id, :task=>{ :status=>'active' }
+    @task.reload.should be_active
+  end
+
+  it 'should 403 if anyone else changes status to active' do
+    authenticate @owner
+    put :update, :id=>@task.id, :task=>{ :status=>'active' }
+    response.should be_forbidden
+  end
+
+  it 'should 403 if owner attempts to change task' do
+    authenticate @owner
+    put :update, :id=>@task.id, :task=>{}
     response.should be_forbidden
   end
 
-  it 'should cancel task if administrator' do
+  it 'should 403 if potential owner attempts to change task' do
+    authenticate @potential.first
+    put :update, :id=>@task.id, :task=>{ :owner=>@potential.first }
+    response.should be_forbidden
+  end
+
+end
+
+describe TasksController, 'PUT completed task' do
+  it_should_behave_like 'TasksController PUT task'
+
+  before(:each) { @task.status = :completed ; @task.owner = @owner ; @task.save! }
+
+  it 'should 404 if not associated with task' do
+    authenticate person('unknown')
+    put :update, :id=>@task.id, :task=>default_task
+    response.should be_not_found
+    @task.reload.should be_completed
+  end
+
+  it 'should 409 if associated with task' do
+    authenticate @admin
+    put :update, :id=>@task.id, :task=>default_task
+    response.should be_conflict
+    @task.reload.should be_completed
+  end
+
+  it 'should not change task' do
+    authenticate @admin
+    put :update, :id=>@task.id, :task=>default_task.merge(:title=>'changed')
+    @task.reload.title.should_not eql('changed')
+  end
+
+end
+
+describe TasksController, 'PUT cancelled task' do
+  it_should_behave_like 'TasksController PUT task'
+
+  before(:each) { @task.status = :cancelled ; @task.save! }
+
+  it 'should 404 if not associated with task' do
+    authenticate person('unknown')
+    put :update, :id=>@task.id, :task=>default_task
+    response.should be_not_found
+    @task.reload.should be_cancelled
+  end
+
+  it 'should 404 if associated with task' do
+    authenticate @admin
+    put :update, :id=>@task.id, :task=>default_task
+    response.should be_not_found
+    @task.reload.should be_cancelled
+  end
+
+end
+
+
+describe TasksController, 'DELETE task', :shared=>true do
+  include Specs::Tasks
+
+  before :each do
+    @admin, @owner = people('admin', 'owner')
+    @task = Task.create!(default_task.merge(:admins=>@admin, :owner=>@owner))
+    controller.use_rails_error_handling!
+  end
+  
+  it 'should map to /tasks/{id}' do
+    route_for(:controller=>'tasks', :action=>'destroy', :id=>@task.id).should eql("/tasks/#{@task.id}")
+    lambda { route_for(:controller=>'tasks', :action=>'destroy') }.should raise_error(ActionController::RoutingError)
+  end
+
+end
+
+describe TasksController, 'DELETE reserved task' do
+  include Specs::Tasks
+
+  before :each do
+    @admin = person('admin')
+    @task = Task.reserve!(@admin)
+    controller.use_rails_error_handling!
+  end
+  
+  it 'should 404 if not associated with task' do
+    authenticate person('unknown')
     delete :destroy, :id=>@task.id
-    Task.find(@task.id).status.should eql(:cancelled)
+    response.should be_not_found
+    Task.should have(1).record
   end
 
-  it 'should cancel task if owner and owner allowed to cancel' do
-    authenticate person('owner')
-    @task.cancellation = :owner ; @task.save!
+  it 'should 200 if task deleted' do
+    authenticate @admin
     delete :destroy, :id=>@task.id
-    Task.find(@task.id).status.should eql(:cancelled)
+    response.should be_ok
+    response.body.should be_blank
   end
 
-  it 'should 403 if owner and owner not allowed to cancel' do
-    authenticate person('owner')
+  it 'should delete task' do
+    authenticate @admin
     delete :destroy, :id=>@task.id
-    Task.find(@task.id).status.should eql(:active)
+    Task.should have(:no).records
   end
 
-  it 'should 403 if potential owner and not anyone allowed to cancel' do
-    authenticate person('potential')
+end
+
+describe TasksController, 'DELETE active task' do
+  it_should_behave_like 'TasksController DELETE task'
+
+  it 'should 404 if not associated with task' do
+    authenticate person('unknown')
     delete :destroy, :id=>@task.id
-    Task.find(@task.id).status.should eql(:active)
+    response.should be_not_found
+    @task.reload.should be_active
   end
 
-  it 'should redirect to tasks list if cancelled and responding with HTML' do
+  it 'should 403 if not task administrator' do
+    authenticate @owner
     delete :destroy, :id=>@task.id
-    response.should redirect_to(tasks_url)
+    response.should be_forbidden
+    @task.reload.should be_active
   end
 
-  it 'should return 200 if cancelled and responding with XML' do
-    delete :destroy, :id=>@task.id, :format=>'xml'
+  it 'should 200 if task cancelled' do
+    authenticate @admin
+    delete :destroy, :id=>@task.id
     response.should be_ok
+    response.body.should be_blank
+  end
+
+  it 'should change task status to cancelled' do
+    authenticate @admin
+    delete :destroy, :id=>@task.id
+    @task.reload.should be_cancelled
+  end
+
+  it 'should not cancel if owner and cancellation policy is admin' do
+    authenticate @owner
+    delete :destroy, :id=>@task.id
+    @task.reload.should be_active
   end
 
-  it 'should return 200 if cancelled and responding with JSON' do
-    delete :destroy, :id=>@task.id, :format=>'json'
+  it 'should cancel if owner and cancellation policy is owner' do
+    @task.update_attributes! :cancellation=>:owner
+    authenticate @owner
+    delete :destroy, :id=>@task.id
+    @task.reload.should be_cancelled
+  end
+
+end
+
+describe TasksController, 'DELETE suspended task' do
+  it_should_behave_like 'TasksController DELETE task'
+
+  before(:each) { @task.status = :suspended ; @task.save! }
+
+  it 'should 200 if task cancelled' do
+    authenticate @admin
+    delete :destroy, :id=>@task.id
     response.should be_ok
+    response.body.should be_blank
   end
 
-  it 'should redirect back and flash error if cancelled and responding with HTML' do
-    authenticate person('potential')
-    request.env['HTTP_REFERER'] = '/source/page'
+  it 'should change task status to cancelled' do
+    authenticate @admin
     delete :destroy, :id=>@task.id
-    flash[:error].should match(/not allowed to cancel/i)
-    response.should redirect_to('/source/page')
+    @task.reload.should be_cancelled
   end
 
-  it 'should return 403 if cancelled and responding with XML' do
-    authenticate person('potential')
-    delete :destroy, :id=>@task.id, :format=>'xml'
-    response.should be_forbidden
+end
+
+describe TasksController, 'DELETE completed task' do
+  it_should_behave_like 'TasksController DELETE task'
+
+  before(:each) { @task.status = :completed ; @task.save! }
+
+  it 'should 404 if not associated with task' do
+    authenticate person('unknown')
+    delete :destroy, :id=>@task.id
+    response.should be_not_found
+    @task.reload.should be_completed
   end
 
-  it 'should return 403 if cancelled and responding with JSON' do
-    authenticate person('potential')
-    delete :destroy, :id=>@task.id, :format=>'json'
-    response.should be_forbidden
+  it 'should 409 if associated with task' do
+    authenticate @admin
+    delete :destroy, :id=>@task.id
+    response.should be_conflict
+    @task.reload.should be_completed
   end
 
 end
 
+describe TasksController, 'DELETE cancelled task' do
+  it_should_behave_like 'TasksController DELETE task'
 
-describe TasksController, 'POST /tasks/{id}' do
-  include Specs::Authentication, Specs::Tasks
+  before(:each) { @task.status = :cancelled ; @task.save! }
 
-  before :each do
-    authenticate person('owner')
-    @task = Task.create(default_values.merge(:admins=>person('admin'), :owner=>authenticated,
-      :creator=>person('creator'), :potential_owners=>person('potential')))
+  it 'should 404 if not associated with task' do
+    authenticate person('unknown')
+    delete :destroy, :id=>@task.id
+    response.should be_not_found
+    Task.should have(1).record
   end
 
+  it 'should 404 if associated with task' do
+    authenticate @admin
+    delete :destroy, :id=>@task.id
+    response.should be_not_found
+    Task.should have(1).record
+  end
+
+end
+
+
+describe TasksController, 'POST task', :shared=>true do
+  include Specs::Tasks
+
+  before :each do
+    @admin, @owner = people('admin', 'owner')
+    @task = Task.create!(default_task.merge(:admins=>@admin, :owner=>@owner))
+    controller.use_rails_error_handling!
+  end
+  
   it 'should map to /tasks/{id}' do
-    route_for(:controller=>'tasks', :action=>'complete', :id=>1).should eql('/tasks/1')
+    route_for(:controller=>'tasks', :action=>'complete', :id=>@task.id).should eql("/tasks/#{@task.id}")
     lambda { route_for(:controller=>'tasks', :action=>'complete') }.should raise_error(ActionController::RoutingError)
   end
 
-  it 'should 400 if no input provided' do
-    post :complete, :id=>0
-    response.should be_bad_request
+  it 'should map to /tasks/{id}.{format}' do
+    route_for(:controller=>'tasks', :action=>'complete', :id=>@task.id, :format=>'xml').should eql("/tasks/#{@task.id}.xml")
   end
 
-  it 'should 404 if task not found' do
-    lambda { post :complete, :id=>0, :task=>{} }.should raise_error(ActiveRecord::RecordNotFound)
-  end
+end
 
-  it 'should 404 if task already cancelled' do
-    @task.status = :cancelled ; @task.save!
-    lambda { post :complete, :id=>@task.id, :task=>{} }.should raise_error(ActiveRecord::RecordNotFound)
+describe TasksController, 'POST reserved task' do
+  include Specs::Tasks
+
+  before :each do
+    @admin = person('admin')
+    @task = Task.reserve!(@admin)
+    controller.use_rails_error_handling!
   end
 
-  it 'should 404 unless allowed to view task' do
-    authenticate person('noone')
-    lambda { post :complete, :id=>@task.id, :task=>{} }.should raise_error(ActiveRecord::RecordNotFound)
+  it 'should 404' do
+    authenticate @admin
+    post :complete, :id=>@task.id
+    response.should be_not_found
+    Task.should have(1).record
   end
 
-  it 'should redirect back and flash error if task already completed and requesting HTML' do
-    @task.status = :completed ; @task.save!
-    request.env['HTTP_REFERER'] = '/source/page'
-    post :complete, :id=>@task.id, :task=>{}
-    flash[:error].should match(/not allowed to complete/i)
-    response.should redirect_to('/source/page')
+end
+
+describe TasksController, 'POST active task' do
+  it_should_behave_like 'TasksController POST task'
+
+  before(:each) { authenticate @owner }
+
+  it 'should 404 if not associated with task' do
+    authenticate person('unknown')
+    post :complete, :id=>@task.id
+    response.should be_not_found
+    @task.reload.should be_active
   end
 
-  it 'should 403 if task already completed and requesting XML' do
-    @task.status = :completed ; @task.save!
-    post :complete, :id=>@task.id, :task=>{}, :format=>'xml'
+  it 'should 403 if not task owner' do
+    authenticate @admin
+    post :complete, :id=>@task.id
     response.should be_forbidden
+    @task.reload.should be_active
+  end
+
+  it 'should 200 if task completed' do
+    post :complete, :id=>@task.id
+    response.should be_ok
   end
 
-  it 'should 403 if task already completed and requesting JSON' do
-    @task.status = :completed ; @task.save!
-    post :complete, :id=>@task.id, :task=>{}, :format=>'json'
+  it 'should change task status to completed' do
+    post :complete, :id=>@task.id
+    @task.reload.should be_completed
+  end
+
+  it 'should leave task data intact if no data provided' do
+    data = { 'foo'=>'cow', 'bar'=>'bell' }
+    @task.update_attributes! :data=>data
+    post :complete, :id=>@task.id
+    @task.reload.data.should == data
+  end
+
+  it 'should change task data if new data provided' do
+    @task.update_attributes! :data=>{ 'foo'=>'cow', 'bar'=>'bell' }
+    data = { 'foo'=>'more' }
+    post :complete, :id=>@task.id, :task=>{ :data=>data }
+    @task.reload.data.should == data
+  end
+
+end
+
+describe TasksController, 'POST suspended task' do
+  it_should_behave_like 'TasksController POST task'
+
+  before(:each) { @task.status = :suspended ; @task.save! }
+
+  it 'should 403' do
+    authenticate @owner
+    post :complete, :id=>@task.id
     response.should be_forbidden
   end
 
-  it 'should complete task if owner' do
-    post :complete, :id=>@task.id, :task=>{}
-    Task.find(@task.id).status.should eql(:completed)
+end
+
+describe TasksController, 'POST completed task' do
+  it_should_behave_like 'TasksController POST task'
+
+  before(:each) { @task.status = :completed ; @task.save! }
+
+  it 'should 409' do
+    authenticate @owner
+    post :complete, :id=>@task.id
+    response.should be_conflict
   end
 
-  it 'should 403 if not owner' do
-    authenticate person('admin')
-    post :complete, :id=>@task.id, :task=>{}, :format=>'xml'
+end
+
+describe TasksController, 'POST unclaimed task' do
+  it_should_behave_like 'TasksController POST task'
+
+  before(:each) { @task.owner = nil ; @task.save! }
+
+  it 'should 403' do
+    authenticate @admin
+    post :complete, :id=>@task.id
     response.should be_forbidden
   end
 
-  it 'should 200 and redirect back to tasks list if completed and requesting HTML' do
-    post :complete, :id=>@task.id, :task=>{}
-    response.should redirect_to(tasks_url)
+end
+
+describe TasksController, 'POST cancelled task' do
+  it_should_behave_like 'TasksController POST task'
+
+  before(:each) { @task.status = :cancelled ; @task.save! }
+
+  it 'should 404' do
+    authenticate @owner
+    post :complete, :id=>@task.id
+    response.should be_not_found
+    @task.reload.should be_cancelled
+  end
+
+end
+
+
+
+describe TasksController, 'token authentication' do
+  include Specs::Tasks
+
+  before :each do
+    @task = Task.create(default_task.merge(:owner=>person('owner'), :potential_owners=>person('excluded'),
+                                           :excluded_owners=>person('excluded')))
   end
 
-  it 'should 200 if completed and requesting XML' do
-    post :complete, :id=>@task.id, :task=>{}, :format=>'xml'
+  def authenticate(person)
+    credentials = ['_token', @task.token_for(person)]
+    request.headers['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(*credentials)
+  end
+
+  it 'should be used if provided' do
+    authenticate person('owner')
+    get :show, :id=>@task.id
     response.should be_ok
   end
 
-  it 'should 200 if completed and requesting JSON' do
-    post :complete, :id=>@task.id, :task=>{}, :format=>'json'
+  it 'should authenticate stakeholder' do
+    authenticate person('owner')
+    get :show, :id=>@task.id
     response.should be_ok
+    assigns[:authenticated] == person('owner')
   end
 
-  it 'should update task data if supplied' do
-    post :complete, :id=>@task.id, :task=>{ :data=>{ :foo=>:bar } }
-    Task.find(@task.id).data.should == {'foo'=>'bar'}
+  it 'should 404 if not stakeholder' do
+    authenticate person('noone')
+    lambda { get :show, :id=>@task.id }.should raise_error(ActiveRecord::RecordNotFound)
   end
 
-  it 'should leave task data intact if absent' do
-    @task.data = { 'bar'=>'baz' } ; @task.save!
-    post :complete, :id=>@task.id, :task=>{}
-    Task.find(@task.id).data.should == {'bar'=>'baz'}
+  it 'should 404 if excluded owner' do
+    authenticate person('excluded')
+    lambda { get :show, :id=>@task.id }.should raise_error(ActiveRecord::RecordNotFound)
   end
 
+  it 'should 404 if no such task' do
+    authenticate person('owner')
+    lambda { get :show, :id=>@task.id + 1 }.should raise_error(ActiveRecord::RecordNotFound)
+  end
+
+  it 'should 404 if task cancelled' do
+    @task.status = :cancelled ; @task.save!
+    authenticate person('owner')
+    lambda { get :show, :id=>@task.id }.should raise_error(ActiveRecord::RecordNotFound)
+  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=603406&r1=603405&r2=603406&view=diff
==============================================================================
--- ode/sandbox/singleshot/spec/models/task_spec.rb (original)
+++ ode/sandbox/singleshot/spec/models/task_spec.rb Tue Dec 11 15:14:39 2007
@@ -1,43 +1,75 @@
 require File.dirname(__FILE__) + '/../spec_helper'
 
 
-describe Task, 'to_param' do
+describe Task, 'reserve!' do
   include Specs::Tasks
 
-  before :each do
-    @task = Task.create!
+  before :all do
+    @admin = person('admin')
+    @task = Task.reserve!(@admin)
+  end
+
+  it 'should create new task' do
+    Task.should have(1).record
+  end
+
+  it 'should be reserved' do
+    @task.should be_reserved
   end
 
-  def title
-    @task.to_param[/(\d+-)(.*)/, 2]
+  it 'should include argument as admin' do
+    @task.admins.should eql([@admin])
+  end
+
+  it 'should destroy stakeholder when deleted' do
+    lambda { @task.destroy }.should change(Stakeholder, :count).to(0)
+  end
+
+end
+
+
+describe Task, 'to_param' do
+  include Specs::Tasks
+
+  it 'should return nil unless task saved' do
+    Task.new.to_param.should be_nil
   end
 
   it 'should resolve to task ID' do
-    @task.to_param.to_i.should eql(@task.id)
+    task = Task.create!(default_task)
+    task.to_param.to_i.should eql(task.id)
+    task.update_attributes! :title=>'whatever'
+    task.to_param.to_i.should eql(task.id)
   end
 
-  it 'should contain title' do
-    title.should eql(@task.title.gsub(' ', '-'))
+  it 'should only contain ID if title is empty' do
+    task = Task.reserve!(person('admin'))
+    task.to_param.should eql(task.id.to_s)
+  end
+
+  it 'should contain title if specified' do
+    task = Task.create(default_task.merge(:title=>'whatever'))
+    task.to_param.should eql("#{task.id}-whatever")
   end
 
   it 'should change all non-word characters to dashes' do
-    @task.title = 'foo*bar+baz faz_'
-    title.should eql('foo-bar-baz-faz_')
+    task = Task.create(default_task.merge(:title=>'foo*bar+baz faz_'))
+    task.to_param[/^\d+-(.*)/, 1].should eql('foo-bar-baz-faz_')
   end
 
   it 'should consolidate multiple dashes' do
-    @task.title = 'foo**bar--baz -faz'
-    title.should eql('foo-bar-baz-faz')
+    task = Task.create(default_task.merge(:title=>'foo**bar--baz -faz'))
+    task.to_param[/^\d+-(.*)/, 1].should eql('foo-bar-baz-faz')
   end
 
   it 'should remove dashes at end' do
-    @task.title = 'foo**'
-    title.should eql('foo')
+    task = Task.create(default_task.merge(:title=>'foo**'))
+    task.to_param[/^\d+-(.*)/, 1].should eql('foo')
   end
 
   it 'should leave UTF-8 text along' do
-    @task.title = 'josé'
-    CGI.escape(title).should eql('jos%C3%A9')
+    task = Task.create(default_task.merge(:title=>'josé'))
+    CGI.escape(task.to_param[/^\d+-(.*)/, 1]).should eql('jos%C3%A9')
   end
 
 end
@@ -47,34 +79,49 @@
   include Specs::Tasks
 
   before :each do
-    @task = Task.new
+    @task = Task.create!(default_task)
   end
 
   it 'should default to :active' do
     @task.status.should eql(:active)
   end
 
-  it 'should allow valid status code' do
-    Task::STATUSES.each do |status|
-      @task.status = status
-      @task.save
-      Task.find(@task.id).status.should eql(status)
-    end
+  it 'should be required to save' do
+    @task.status = nil
+    @task.should have(1).error_on(:status)
   end
 
-  it 'should reject unknown status code' do
-    @task.status = :unknown
-    lambda { @task.save! }.should raise_error(ActiveRecord::RecordInvalid)
+  it 'should not change to completed without owner' do
+    @task.status = :completed
+    @task.should have(1).error_on(:status)
   end
 
-  it 'should require status code' do
-    @task[:status] = nil
-    lambda { @task.save! }.should raise_error(ActiveRecord::RecordInvalid)
+  it 'should change to completed if owner specified' do
+    @task.owner = person('assaf')
+    @task.status = :completed
+    @task.should have(:no).errors_on(:status)
   end
 
-  it 'should be protected attribute' do
-    Task.new(:status=>:completed).status.should eql(:active)
-    lambda { @task.update_attributes! :status=>:completed }.should_not change { @task.status }
+  it 'should switch to cancelled if previoulsy active' do
+    lambda { @task.status = :cancelled ; @task.save! }.should change(@task, :status).to(:cancelled)
+  end
+
+  it 'should switch to suspended if previously active' do
+    lambda { @task.status = :suspended ; @task.save! }.should change(@task, :status).to(:suspended)
+  end
+
+  it 'should switch to active if previously suspended' do
+    @task.status = :suspended ; @task.save!
+    lambda { @task.status = :active ; @task.save! }.should change(@task, :status).to(:active)
+  end
+
+  it 'should be protected' do
+    lambda { @task.update_attributes! :status=>:suspended }.should_not change(@task, :status)
+  end
+
+  it 'should use suspended = to flip between active and suspended' do
+    lambda { @task.update_attributes! :suspended=>true }.should change(@task, :status).to(:suspended)
+    lambda { @task.update_attributes! :suspended=>false }.should change(@task, :status).to(:active)
   end
 
   it 'should resolve symbol to index value' do
@@ -83,6 +130,17 @@
     end
   end
 
+  it 'should not allow any other value from constructor' do
+    (Task::STATUSES - [:reserved, :active]).each do |status|
+      Task.new(:owner=>person('owner'), :status=>status).should be_active
+    end
+  end
+
+  it 'should change from reserved to active when doing mass assignment' do
+    task = Task.reserve!(person('admin'))
+    lambda { task.update_attributes(:title=>'Change to active') }.should change(task, :status).to(:active)
+  end
+
 end
 
 
@@ -90,35 +148,45 @@
   include Specs::Tasks
 
   before :each do
-    @task = Task.new
+    @task = Task.new(default_task)
   end
 
   it 'should default to 1' do
     @task.priority.should be(1)
   end
 
-  it 'should allow values from 1 to 5' do
-    priorities = Array.new(7) { |i| i }
-    priorities.map { |p| @task.update_attributes :priority=>p }.should eql([false] + [true] * 5 + [false])
+  it 'should allow values from 1 to 3' do
+    priorities = Array.new(5) { |i| i }
+    priorities.map { |p| @task.update_attributes :priority=>p }.should eql([false] + [true] * 3 + [false])
   end
 
   it 'should accept string value' do
-    lambda { @task.update_attributes! :priority=>'4' }.should change(@task, :priority).to(4)
+    lambda { @task.update_attributes! :priority=>'2' }.should change(@task, :priority).to(2)
   end
 
   it 'should accept nil and reset to default' do
-    @task.priority = 4
+    @task.priority = 2
     lambda { @task.update_attributes! :priority=>nil }.should change(@task, :priority).to(1)
   end
 
 end
 
 
+describe Task, 'title' do
+  include Specs::Tasks
+
+  it 'should be required' do
+    Task.new(default_task.except(:title)).should have(1).error_on(:title)
+  end
+
+end
+
+
 describe Task, 'due_on' do
   include Specs::Tasks
 
   before :each do
-    @task = Task.new
+    @task = Task.new(default_task)
   end
 
   it 'should default to nil' do
@@ -155,59 +223,46 @@
 
 describe Task, 'url', :shared=>true do
 
-  before :each do
-    @task = Task.new
-  end
-
-  it 'should be optional' do
-    lambda { @task.save! }.should_not raise_error
-  end
-
   it 'should be tested for validity' do
-    lambda { @task.update_attributes! @field=>'http://+++' }.should raise_error(ActiveRecord::RecordInvalid, /URL/)
+    Task.new(@field=>'http://+++').should have(1).error_on(@field)
   end
 
   it 'should allow HTTP URLS' do
-    lambda { @task.update_attributes! @field=>'http://test.host/do' }.should_not raise_error
+    Task.new(@field=>'http://test.host/do').should have(:no).errors_on(@field)
   end
 
   it 'should allow HTTPS URLS' do
-    lambda { @task.update_attributes! @field=>'https://test.host/do' }.should_not raise_error
+    Task.new(@field=>'https://test.host/do').should have(:no).errors_on(@field)
   end
 
   it 'should not allow other URL schemes' do
-    lambda { @task.update_attributes! @field=>'ftp://test.host/do' }.should raise_error(ActiveRecord::RecordInvalid, /URL/)
+    Task.new(@field=>'ftp://test.host/do').should have(1).error_on(@field)
   end
 
   it 'should store normalized URL' do
-    lambda { @task.update_attributes! @field=>'HTTP://Test.Host/Foo' }.should change(@task, @field).to('http://test.host/Foo')
-    lambda { @task.update_attributes! @field=>'http://test.host' }.should change(@task, @field).to('http://test.host/')
+    task = Task.new(@field=>'HTTP://Test.Host/Foo')
+    task.should have(:no).errors_on(@field)
+    task.send(@field).should eql('http://test.host/Foo')
   end
 
   it 'should be modifiable' do
-    lambda { @task.update_attributes! @field=>'http://test.host/' }.should change(@task, @field).from(nil).to('http://test.host/')
+    task = Task.new(@field=>'http://test.host/view')
+    lambda { task.update_attributes @field=>'http://test.host/' }.should change(task, @field).to('http://test.host/')
   end
 
 end
 
 
-describe Task, 'form_url' do
+describe Task, 'frame_url' do
   include Specs::Tasks
   it_should_behave_like 'Task url'
 
   before :all do
-    @field = :form_url
+    @field = :frame_url
   end
 
-end
-
-
-describe Task, 'view_url' do
-  include Specs::Tasks
-  it_should_behave_like 'Task url'
-
-  before :all do
-    @field = :view_url
+  it 'should be required for active task' do
+    Task.new.should have(1).errors_on(:frame_url)
   end
 
 end
@@ -221,6 +276,10 @@
     @field = :outcome_url
   end
 
+  it 'should be optional' do
+    Task.new.should have(:no).errors_on(:outcome_url)
+  end
+
 end
 
 
@@ -228,53 +287,52 @@
   include Specs::Tasks
 
   def outcome_values(mime_type)
-    { :outcome_url=>'http://test.host/outcome', :outcome_type=>mime_type }
+    default_task.merge(:outcome_url=>'http://test.host/outcome', :outcome_type=>mime_type)
   end
 
   it 'should be ignored unless outcome URL specified' do
-    task = Task.create!(:outcome_type=>Mime::XML)
+    task = Task.create!(outcome_values(Mime::XML).except(:outcome_url))
     Task.find(task.id).outcome_type.should be_nil
   end
 
   it 'should default to Mime::XML' do
     task = Task.create!(outcome_values(nil))
-    Task.find(task.id).outcome_type.should be(Mime::XML)
+    Task.find(task.id).outcome_type.should eql(Mime::XML.to_s)
   end
 
   it 'should accept Mime::XML' do
     task = Task.create!(outcome_values(Mime::XML))
-    Task.find(task.id).outcome_type.should be(Mime::XML)
+    Task.find(task.id).outcome_type.should eql(Mime::XML.to_s)
   end
 
   it 'should accept Mime::JSON' do
     task = Task.create!(outcome_values(Mime::JSON))
-    Task.find(task.id).outcome_type.should be(Mime::JSON)
+    Task.find(task.id).outcome_type.should eql(Mime::JSON.to_s)
   end
 
   it 'should accept all applicable MIME types' do
     Task::OUTCOME_MIME_TYPES.each do |mime_type|
       task = Task.create!(outcome_values(mime_type))
-      Task.find(task.id).outcome_type.should be(mime_type)
+      Task.find(task.id).outcome_type.should eql(mime_type.to_s)
     end
   end
 
   it 'should accept all applicable MIME types as content type' do
     Task::OUTCOME_MIME_TYPES.each do |mime_type|
       task = Task.create!(outcome_values(mime_type.to_s))
-      Task.find(task.id).outcome_type.should be(mime_type)
+      Task.find(task.id).outcome_type.should eql(mime_type.to_s)
     end
   end
 
   it 'should accept all applicable MIME types as extension name' do
     Task::OUTCOME_MIME_TYPES.each do |mime_type|
       task = Task.create!(outcome_values(mime_type.to_sym.to_s))
-      Task.find(task.id).outcome_type.should be(mime_type)
+      Task.find(task.id).outcome_type.should eql(mime_type.to_s)
     end
   end
 
   it 'should reject unsupported MIME types' do
-    lambda { Task.create!(outcome_values(Mime::ATOM)) }.
-      should raise_error(ActiveRecord::RecordInvalid)
+    Task.new(outcome_values(Mime::ATOM)).should have(1).error_on(:outcome_type)
   end
 
 end
@@ -284,7 +342,7 @@
   include Specs::Tasks
 
   before :each do
-    @task = Task.new
+    @task = Task.create!(default_task)
   end
 
   it 'should return hash' do
@@ -295,6 +353,11 @@
     @task.data = { }
   end
 
+  it 'should accept nil' do
+    @task.data = nil
+    @task.data.should == {}
+  end
+
   it 'should be hash with indifferent access' do
     @task.update_attributes! :data=>{ :foo=>1 }
     Task.find(@task.id).data[:foo].should be(1)
@@ -302,7 +365,6 @@
   end
 
   it 'should reject any other value' do
-    lambda { @task.data = nil }.should raise_error(ArgumentError)
     lambda { @task.data = [] }.should raise_error(ArgumentError)
     lambda { @task.data = 'string' }.should raise_error(ArgumentError)
   end
@@ -319,12 +381,12 @@
 
 
 describe Task, 'token' do
-  include Specs::Tasks, Specs::Authentication
+  include Specs::Tasks
 
   before :each do
     @creator = person('creator')
     @owner = person('owner')
-    @task = Task.new(:creator=>@creator, :owner=>@owner)
+    @task = Task.new(default_task.merge(:creator=>@creator, :owner=>@owner))
     @creator_token = @task.token_for(@creator)
     @owner_token = @task.token_for(@owner)
   end
@@ -359,151 +421,121 @@
 end
 
 
-describe Task, 'singular role' do
-  include Specs::Tasks, Specs::Authentication
+Task::SINGULAR_ROLES.each do |role|
+  describe Task, role do
+    include Specs::Tasks
 
-  before :all do
-    @person, @other = person('person'), person('alex')
-  end
+    before :all do
+      @person, @other = person('person'), person('alex')
+    end
 
-  it 'should start as nil' do
-    Task::SINGULAR_ROLES.each do |role|
+    it 'should start as nil' do
       Task.new.send(role).should be_nil
     end
-  end
 
-  it 'should have getter and setter methods' do
-    Task::SINGULAR_ROLES.each do |role|
-      task = Task.create!(role=>@person)
+    it 'should have getter and setter methods' do
+      task = Task.create!(default_task.merge(role=>@person))
       Task.find(task.id).send(role).should eql(@person)
     end
-  end
 
-  it 'should have checker methods' do
-    Task::SINGULAR_ROLES.each do |role|
-      task = Task.create!(role=>@person)
+    it 'should have checker methods' do
+      task = Task.create!(default_task.merge(role=>@person))
       Task.find(task.id).send("#{role}?", @person).should be_true
     end
-  end
 
-  it 'should be able to remove person' do
-    Task::SINGULAR_ROLES.each do |role|
-      task = Task.create!(role=>@person)
+    it 'should be able to remove person' do
+      task = Task.create!(default_task.merge(role=>@person))
       lambda { task.update_attributes! role=>nil }.should change(task, role).from(@person).to(nil)
     end
-  end
 
-  it 'should be able to change person' do
-    Task::SINGULAR_ROLES.each do |role|
-      task = Task.create!(role=>@person)
+    it 'should be able to change person' do
+      task = Task.create!(default_task.merge(role=>@person))
       lambda { task.update_attributes! role=>person(@other) }.should change(task, role).from(@person).to(person(@other))
     end
-  end
 
-  it 'should accept person at creation' do
-    Task::SINGULAR_ROLES.each do |role|
-      Task.create!(role=>@person).send(role).should eql(@person)
+    it 'should accept person at creation' do
+      Task.create!(default_task.merge(role=>@person)).send(role).should eql(@person)
     end
-  end
 
-  it 'should treat blank as nil' do
-    Task::SINGULAR_ROLES.each do |role|
-      task = Task.create!(role=>@person)
+    it 'should treat blank as nil' do
+      task = Task.create!(default_task.merge(role=>@person))
       lambda { task.update_attributes! role=>'' }.should change(task, role).from(@person).to(nil)
     end
-  end
 
-  it 'should accept unknown identities but fail to save' do
-    Task::SINGULAR_ROLES.each do |role|
-      task = Task.create!(role=>@person)
-      lambda { task.update_attributes! role=>'unknown' }.
-        should raise_error(ActiveRecord::RecordInvalid, /cannot find person/i)
+    it 'should accept unknown identities but fail to save' do
+      Task.new(default_task.merge(role=>'unknown')).should have(1).error_on(role)
     end
-  end
 
+  end
 end
 
 
-describe Task, 'plural role' do
-  include Specs::Tasks, Specs::Authentication
+Task::PLURAL_ROLES.each do |role|
+  describe Task, role do
+    include Specs::Tasks
 
-  before :each do
-    @people = Array.new(3) { |i| person("person#{i}") }
-    @task = Task.new
-  end
+    before :all do
+      @people = Array.new(3) { |i| person("person#{i}") }
+    end
 
-  def plural(role)
-    role.to_s.pluralize.to_sym
-  end
+    before :each do
+      @task = Task.new(default_task)
+    end
+
+    def plural(role)
+      role.to_s.pluralize.to_sym
+    end
 
-  it 'should start as empty array' do
-    Task::PLURAL_ROLES.each do |role|
+    it 'should start as empty array' do
       @task.send(plural(role)).should be_empty
     end
-  end
 
-  it 'should have getter and setter methods' do
-    Task::PLURAL_ROLES.each do |role|
+    it 'should have getter and setter methods' do
       lambda { @task.update_attributes! plural(role)=>@people }.should change(@task, plural(role)).to(@people)
     end
-  end
 
-  it 'should have checker methods' do
-    Task::PLURAL_ROLES.each do |role|
+    it 'should have checker methods' do
       lambda { @task.send "#{plural(role)}=", @people.first }.
         should change { @task.send("#{role}?", @people.first) }.to(true)
       @task.send("#{role}?", @people.last).should be_false
     end
-  end
 
-  it 'should be able to add person' do
-    Task::PLURAL_ROLES.each do |role|
+    it 'should be able to add person' do
       @task.update_attributes! plural(role)=>@people[0..-2]
       lambda { @task.update_attributes! plural(role)=>@people }.should change(@task, plural(role)).
         from(@people[0..-2]).to(@people)
     end
-  end
 
-  it 'should be able to remove person' do
-    Task::PLURAL_ROLES.each do |role|
+    it 'should be able to remove person' do
       @task.update_attributes! plural(role)=>@people
       lambda { @task.update_attributes! plural(role)=>@people[0..-2] }.should change(@task, plural(role)).
         from(@people).to(@people[0..-2])
     end
-  end
 
-  it 'should add each person only once' do
-    Task::PLURAL_ROLES.each do |role|
+    it "should add each person only once" do
       @task.update_attributes! plural(role)=>[@people.first, @people.first]
       @task.send(plural(role)).should eql([@people.first])
     end
-  end
 
-  it 'should accept person at creation' do
-    Task::PLURAL_ROLES.each do |role|
-      Task.create!(plural(role)=>@people).send(plural(role)).should eql(@people)
+    it "should accept person at creation" do
+      Task.create!(default_task.merge(plural(role)=>@people)).send(plural(role)).should eql(@people)
     end
-  end
 
-  it 'should treat blank as empty' do
-    Task::PLURAL_ROLES.each do |role|
+    it "should treat blank as empty" do
       @task.update_attributes! plural(role)=>@people
       lambda { @task.update_attributes! plural(role)=>'' }.should change(@task, plural(role)).from(@people).to([])
     end
-  end
 
-  it 'should accept unknown identities but fail to save' do
-    Task::PLURAL_ROLES.each do |role|
-      lambda { @task.update_attributes! plural(role)=>(@people << 'unknown') }.
-        should raise_error(ActiveRecord::RecordInvalid, /cannot find person/i)
+    it "should accept unknown identities for but fail to save" do
+      Task.new(default_task.merge(plural(role)=>(@people + ['unknown']))).should have(1).error_on(role)
     end
-  end
 
+  end
 end
 
 
 describe Task, 'creator' do
-  include Specs::Authentication, Specs::Tasks
+  include Specs::Tasks
 
   it 'should be singular role' do
     Task::SINGULAR_ROLES.should include(:creator)
@@ -526,19 +558,40 @@
   it 'should default to no one' do
     Task.new.owner.should be_nil
   end
+
+  it 'should never be excluded owner' do
+    Task.new(:owner=>person('owner'), :excluded_owners=>people('owner', 'foo')).should have(1).error_on(:owner)
+  end
   
 end
 
 
+describe Task, 'potential owners' do
+  include Specs::Tasks
+
+  it 'should never include excluded owners' do
+    task = Task.new(default_task.merge(:potential_owners=>people('foo', 'bar', 'baz'), :excluded_owners=>people('bar', 'qoo')))
+    task.should be_valid
+    task.potential_owners.should eql(people('foo', 'baz'))
+    task.excluded_owners.should eql(people('bar', 'qoo'))
+  end
+
+end
+
+
 describe Task, 'stakeholder?' do
-  include Specs::Tasks, Specs::Authentication
+  include Specs::Tasks
 
   before :all do
     @task = Task.new(@roles = all_roles)
+    @task.excluded_owners = [person('excluded'), @task.potential_owners[1]]
+    @task.save
   end
   
   it 'should return true if person associated with task' do
-    @roles.except(:excluded_owners).each { |role, person| @task.stakeholder?(person).should be_true }
+    allowed = @roles.map { |role, people| Array(people) }.flatten - @task.excluded_owners
+    allowed.size.should > 0
+    allowed.each { |person| @task.stakeholder?(person).should be_true }
   end
 
   it 'should return false if person not associated with task' do
@@ -546,12 +599,11 @@
   end
 
   it 'should return true for task admin' do
-    Task.admins << person(:admin)
-    @task.stakeholder?(person(:admin)).should be_true
+    @task.stakeholder?(su).should be_true
   end
 
   it 'should return false for excluded owner' do
-    @task.stakeholder?(@roles[:excluded_owners]).should be_false
+    @task.excluded_owners.each { |person| @task.stakeholder?(person).should be_false }
   end
 
 end
@@ -572,7 +624,7 @@
   include Specs::Tasks
 
   before :each do
-    @task = Task.create!
+    @task = Task.create!(default_task)
   end
 
   it 'should start at zero' do
@@ -592,7 +644,7 @@
   include Specs::Tasks
 
   before :each do
-    @task = Task.create!
+    @task = Task.create!(default_task)
   end
 
   it 'should return same value if task not udpated' do
@@ -606,7 +658,7 @@
   end
 
   it 'should be unique across tasks' do
-    @task.etag.should_not eql(Task.create!)
+    @task.etag.should_not eql(Task.create!(default_task))
   end
 
   it 'should be MD5 hash' do
@@ -620,14 +672,10 @@
 
 
 describe Task, 'cancellation' do
-  include Specs::Authentication, Specs::Tasks
-
-  before :all do
-    Task.admins = @task_admins = person('admins')
-  end
+  include Specs::Tasks
 
   before :each do
-    @task = Task.new(@roles = all_roles)
+    @task = Task.new(default_task.merge(@roles = all_roles))
   end
 
   it 'should default to :admin' do
@@ -639,32 +687,40 @@
   end
 
   it 'should allow admin to cancel the task for all values' do
-    @roles.select { |role, person| @task.can_cancel?(person) }.map(&:first).should eql([:admins])
-    @task.can_cancel?(@task_admins).should be_true
+    @roles.select { |role, people| Array(people).any? { |person| @task.can_cancel?(person) } }.
+      map(&:first).should eql([:admins])
+    @task.can_cancel?(su).should be_true
   end
 
   it 'should allow owner to cancel the task for the value :owner' do
     @task.cancellation = :owner
-    @roles.select { |role, person| @task.can_cancel?(person) }.map(&:first).sort_by(&:to_s).should eql([:admins, :owner])
-    @task.can_cancel?(@task_admins).should be_true
+    @roles.select { |role, people| Array(people).any? { |person| @task.can_cancel?(person) } }.
+      map(&:first).sort_by(&:to_s).should eql([:admins, :owner])
+    @task.can_cancel?(su).should be_true
   end
 
 end
 
 
 describe Task, 'completion' do
-  include Specs::Authentication, Specs::Tasks
+  include Specs::Tasks
 
   before :all do
-    Task.admins = @task_admins = person('admins')
+    @roles = all_roles
   end
 
   before :each do
-    @task = Task.new(@roles = all_roles)
+    @task = Task.create(default_task.merge(@roles))
   end
 
   it 'should allow owner to complete task' do
-    @roles.select { |role, person| @task.can_complete?(person) }.map(&:first).should eql([:owner])
+    @roles.select { |role, people| Array(people).any? { |person| @task.can_complete?(person) } }.
+      map(&:first).should eql([:owner])
+  end
+
+  it 'should not validate if completed without owner' do
+    @task.status = :completed
+    lambda { @task.owner = nil }.should change { @task.valid? }.to(false)
   end
 
 end

Modified: ode/sandbox/singleshot/spec/views/sessions/show_spec.rb
URL: http://svn.apache.org/viewvc/ode/sandbox/singleshot/spec/views/sessions/show_spec.rb?rev=603406&r1=603405&r2=603406&view=diff
==============================================================================
--- ode/sandbox/singleshot/spec/views/sessions/show_spec.rb (original)
+++ ode/sandbox/singleshot/spec/views/sessions/show_spec.rb Tue Dec 11 15:14:39 2007
@@ -4,12 +4,14 @@
 
   it 'should render login form' do
     render '/sessions/show'
-    response.should have_tag('div.login') do
+    response.should have_tag('form.login') do
       with_tag 'form[method=post][action=?]', session_url do
-        with_tag 'input[name=login][type=text]'
-        with_tag 'input[name=password][type=password]'
-        with_tag 'input[type=submit], button'
-        without_tag('p.error')
+        with_tag 'fieldset' do
+          with_tag 'input[name=login][type=text]'
+          with_tag 'input[name=password][type=password]'
+          with_tag 'button', 'Login'
+          without_tag('p.error')
+        end
       end
     end
   end
@@ -17,14 +19,14 @@
   it 'should render flash[:error] inside login box' do
     flash[:error] = 'Error message'
     render '/sessions/show'
-    response.should have_tag('div.login') do
+    response.should have_tag('form.login fieldset') do
       with_tag 'p.error', 'Error message'
     end
   end
 
   it 'should not render empty container without flash[:error]' do
     render '/sessions/show'
-    response.should have_tag('div.login') do
+    response.should have_tag('form.login fieldset') do
       without_tag('p.error')
     end
   end