Commit b6eabacb30256369e13b122362ac584a3a45ab21

Authored by AntonioTerceiro
1 parent 83f48698

ActionItem96: implementing task system



git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@611 3f533792-8f58-4932-b0fe-aaf55b0a4547
app/models/task.rb
  1 +# Task is the base class of ... tasks! Its instances represents tasks that must
  2 +# be confirmed by someone (like an environment administrator) or by noosfero
  3 +# itself.
  4 +#
  5 +# The specific types of tasks <em>must</em> override the #perform method, so
  6 +# the actual action associated to the type of task can be performed. See the
  7 +# documentation of the #perform method for details.
  8 +#
  9 +# This class has a +status+ field of type <tt>text</tt>, where you can store
  10 +# any type of data (as serialized Ruby objects) you need for your subclass .
1 11 class Task < ActiveRecord::Base
  12 +
  13 + module Status
  14 + # the status of tasks just created
  15 + ACTIVE = 1
  16 +
  17 + # the status of a task that was cancelled.
  18 + CANCELLED = 2
  19 +
  20 + # the status os a task that was successfully finished
  21 + FINISHED = 3
  22 + end
  23 +
2 24 belongs_to :requestor, :class_name => 'Profile', :foreign_key => :requestor_id
3 25 belongs_to :target, :class_name => 'Profile', :foreign_key => :target_id
  26 +
  27 + def initialize(*args)
  28 + super
  29 + self.status ||= Task::Status::ACTIVE
  30 + end
  31 +
  32 + # this method finished the task. It calls #perform, which must be overriden
  33 + # by subclasses. At the end a message (as returned by #finish_message) is
  34 + # sent to the requestor with #notify_requestor.
  35 + def finish
  36 + transaction do
  37 + self.status = Task::Status::FINISHED
  38 + self.end_date = Time.now
  39 + self.save!
  40 + self.perform
  41 + self.notify_requestor(self.finish_message)
  42 + end
  43 + end
  44 +
  45 + # this method cancels the task. At the end a message (as returned by
  46 + # #cancel_message) is sent to the requestor with #notify_requestor.
  47 + def cancel
  48 + transaction do
  49 + self.status = Task::Status::CANCELLED
  50 + self.end_date = Time.now
  51 + self.save!
  52 + self.notify_requestor(self.cancel_message)
  53 + end
  54 + end
  55 +
  56 + protected
  57 +
  58 + # This method must be overrided in subclasses, and its implementation must do
  59 + # the job the task is intended to. This method will be called when the finish
  60 + # method is called.
  61 + #
  62 + # To cancel the finish of the task, you can throw an exception in perform.
  63 + #
  64 + # The implementation on Task class just does nothing.
  65 + def perform
  66 + end
  67 +
  68 + # sends a message to the requestor
  69 + def notify_requestor(msg)
  70 + # TODO: implement message sending
  71 + end
  72 +
  73 + # The message that will be sent to the requestor of the task when its
  74 + # finished.
  75 + def finish_message
  76 + _("The task was finished at %s") % (self.end_date.to_s)
  77 + end
  78 +
  79 + # The message that will be sent to the requestor of the task when its
  80 + # cancelled.
  81 + def cancel_message
  82 + _("The task was cancelled at %s") % (self.end_date.to_s)
  83 + end
  84 +
4 85 end
... ...
db/migrate/017_create_tasks.rb
1 1 class CreateTasks < ActiveRecord::Migration
2 2 def self.up
3 3 create_table :tasks do |t|
  4 + t.column :description, :string
4 5  
5 6 t.column :data, :text
6 7 t.column :status, :integer
  8 + t.column :end_date, :date
7 9  
8 10 t.column :requestor_id, :integer
9 11 t.column :target_id, :integer
... ...
test/unit/task_test.rb
... ... @@ -3,7 +3,7 @@ require File.dirname(__FILE__) + &#39;/../test_helper&#39;
3 3 class TaskTest < Test::Unit::TestCase
4 4  
5 5 def test_relationship_with_requestor
6   - t = Task.new
  6 + t = Task.create
7 7 assert_raise ActiveRecord::AssociationTypeMismatch do
8 8 t.requestor = 1
9 9 end
... ... @@ -13,7 +13,7 @@ class TaskTest &lt; Test::Unit::TestCase
13 13 end
14 14  
15 15 def test_relationship_with_target
16   - t = Task.new
  16 + t = Task.create
17 17 assert_raise ActiveRecord::AssociationTypeMismatch do
18 18 t.target = 1
19 19 end
... ... @@ -21,4 +21,53 @@ class TaskTest &lt; Test::Unit::TestCase
21 21 t.target = Profile.new
22 22 end
23 23 end
  24 +
  25 + def test_should_call_perform_in_finish
  26 + t = Task.create
  27 + t.expects(:perform)
  28 + t.finish
  29 + assert_equal Task::Status::FINISHED, t.status
  30 + end
  31 +
  32 + def test_should_have_cancelled_status_after_cancel
  33 + t = Task.create
  34 + t.cancel
  35 + assert_equal Task::Status::CANCELLED, t.status
  36 + end
  37 +
  38 + def test_should_start_with_active_status
  39 + t = Task.create
  40 + assert_equal Task::Status::ACTIVE, t.status
  41 + end
  42 +
  43 + def test_should_notify_finish
  44 + t = Task.create
  45 + t.expects(:notify_requestor)
  46 + t.expects(:finish_message)
  47 + t.finish
  48 + end
  49 +
  50 + def test_should_notify_cancel
  51 + t = Task.create
  52 + t.expects(:notify_requestor)
  53 + t.expects(:cancel_message)
  54 + t.cancel
  55 + end
  56 +
  57 + def test_should_not_notify_when_perform_fails
  58 + count = Task.count
  59 +
  60 + t = Task.create
  61 + class << t
  62 + def perform
  63 + raise RuntimeError
  64 + end
  65 + end
  66 +
  67 + t.expects(:notify_requestor).never
  68 + assert_raise RuntimeError do
  69 + t.finish
  70 + end
  71 + end
  72 +
24 73 end
... ...