Commit b6eabacb30256369e13b122362ac584a3a45ab21
1 parent
83f48698
Exists in
master
and in
29 other branches
ActionItem96: implementing task system
git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@611 3f533792-8f58-4932-b0fe-aaf55b0a4547
Showing
3 changed files
with
134 additions
and
2 deletions
Show diff stats
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__) + '/../test_helper' |
| 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 < 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 < 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 | ... | ... |