background_queue 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/.rvmrc +48 -0
  4. data/Gemfile +19 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +69 -0
  7. data/Rakefile +42 -0
  8. data/TODO +2 -0
  9. data/VERSION +1 -0
  10. data/background_queue.gemspec +158 -0
  11. data/bin/bg_queue +26 -0
  12. data/lib/background_queue.rb +8 -0
  13. data/lib/background_queue/client.rb +96 -0
  14. data/lib/background_queue/client_lib/command.rb +36 -0
  15. data/lib/background_queue/client_lib/config.rb +109 -0
  16. data/lib/background_queue/client_lib/connection.rb +105 -0
  17. data/lib/background_queue/client_lib/job_handle.rb +19 -0
  18. data/lib/background_queue/command.rb +49 -0
  19. data/lib/background_queue/config.rb +118 -0
  20. data/lib/background_queue/server_lib/balanced_queue.rb +108 -0
  21. data/lib/background_queue/server_lib/config.rb +339 -0
  22. data/lib/background_queue/server_lib/event_connection.rb +133 -0
  23. data/lib/background_queue/server_lib/event_server.rb +35 -0
  24. data/lib/background_queue/server_lib/job.rb +252 -0
  25. data/lib/background_queue/server_lib/job_registry.rb +30 -0
  26. data/lib/background_queue/server_lib/lru.rb +193 -0
  27. data/lib/background_queue/server_lib/owner.rb +54 -0
  28. data/lib/background_queue/server_lib/priority_queue.rb +156 -0
  29. data/lib/background_queue/server_lib/queue_registry.rb +123 -0
  30. data/lib/background_queue/server_lib/server.rb +314 -0
  31. data/lib/background_queue/server_lib/sorted_workers.rb +52 -0
  32. data/lib/background_queue/server_lib/task.rb +79 -0
  33. data/lib/background_queue/server_lib/task_registry.rb +51 -0
  34. data/lib/background_queue/server_lib/thread_manager.rb +121 -0
  35. data/lib/background_queue/server_lib/worker.rb +18 -0
  36. data/lib/background_queue/server_lib/worker_balancer.rb +97 -0
  37. data/lib/background_queue/server_lib/worker_client.rb +94 -0
  38. data/lib/background_queue/server_lib/worker_thread.rb +70 -0
  39. data/lib/background_queue/utils.rb +40 -0
  40. data/lib/background_queue/worker/base.rb +46 -0
  41. data/lib/background_queue/worker/calling.rb +59 -0
  42. data/lib/background_queue/worker/config.rb +35 -0
  43. data/lib/background_queue/worker/environment.rb +70 -0
  44. data/lib/background_queue/worker/worker_loader.rb +94 -0
  45. data/lib/background_queue_server.rb +21 -0
  46. data/lib/background_queue_worker.rb +5 -0
  47. data/spec/background_queue/client_lib/command_spec.rb +75 -0
  48. data/spec/background_queue/client_lib/config_spec.rb +156 -0
  49. data/spec/background_queue/client_lib/connection_spec.rb +170 -0
  50. data/spec/background_queue/client_spec.rb +95 -0
  51. data/spec/background_queue/command_spec.rb +34 -0
  52. data/spec/background_queue/config_spec.rb +134 -0
  53. data/spec/background_queue/server_lib/balanced_queue_spec.rb +122 -0
  54. data/spec/background_queue/server_lib/config_spec.rb +443 -0
  55. data/spec/background_queue/server_lib/event_connection_spec.rb +190 -0
  56. data/spec/background_queue/server_lib/event_server_spec.rb +48 -0
  57. data/spec/background_queue/server_lib/integration/full_test_spec.rb +247 -0
  58. data/spec/background_queue/server_lib/integration/queue_integration_spec.rb +98 -0
  59. data/spec/background_queue/server_lib/integration/serialize_spec.rb +127 -0
  60. data/spec/background_queue/server_lib/job_registry_spec.rb +65 -0
  61. data/spec/background_queue/server_lib/job_spec.rb +525 -0
  62. data/spec/background_queue/server_lib/owner_spec.rb +33 -0
  63. data/spec/background_queue/server_lib/priority_queue_spec.rb +182 -0
  64. data/spec/background_queue/server_lib/server_spec.rb +353 -0
  65. data/spec/background_queue/server_lib/sorted_workers_spec.rb +122 -0
  66. data/spec/background_queue/server_lib/task_registry_spec.rb +69 -0
  67. data/spec/background_queue/server_lib/task_spec.rb +20 -0
  68. data/spec/background_queue/server_lib/thread_manager_spec.rb +106 -0
  69. data/spec/background_queue/server_lib/worker_balancer_spec.rb +127 -0
  70. data/spec/background_queue/server_lib/worker_client_spec.rb +196 -0
  71. data/spec/background_queue/server_lib/worker_thread_spec.rb +125 -0
  72. data/spec/background_queue/utils_spec.rb +27 -0
  73. data/spec/background_queue/worker/base_spec.rb +35 -0
  74. data/spec/background_queue/worker/calling_spec.rb +103 -0
  75. data/spec/background_queue/worker/environment_spec.rb +67 -0
  76. data/spec/background_queue/worker/worker_loader_spec.rb +103 -0
  77. data/spec/background_queue_spec.rb +7 -0
  78. data/spec/resources/config-client.yml +7 -0
  79. data/spec/resources/config-serialize.yml +12 -0
  80. data/spec/resources/config.yml +12 -0
  81. data/spec/resources/example_worker.rb +4 -0
  82. data/spec/resources/example_worker_with_error.rb +4 -0
  83. data/spec/resources/test_worker.rb +8 -0
  84. data/spec/shared/queue_registry_shared.rb +216 -0
  85. data/spec/spec_helper.rb +15 -0
  86. data/spec/support/default_task.rb +9 -0
  87. data/spec/support/private.rb +23 -0
  88. data/spec/support/simple_server.rb +28 -0
  89. data/spec/support/simple_task.rb +58 -0
  90. data/spec/support/test_worker_server.rb +205 -0
  91. metadata +254 -0
@@ -0,0 +1,98 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+ require 'background_queue_server'
3
+
4
+
5
+ describe "Queue Integration" do
6
+
7
+ let(:server) {
8
+ ss = SimpleServer.new(:jobs=>BackgroundQueue::ServerLib::JobRegistry.new)
9
+ ss.thread_manager=BackgroundQueue::ServerLib::ThreadManager.new(ss, 5)
10
+ ss
11
+ }
12
+
13
+ subject { BackgroundQueue::ServerLib::BalancedQueue.new(server) }
14
+
15
+ context "Adding And Removing Tasks" do
16
+
17
+ it "single task" do
18
+ task = SimpleTask.new(:owner_id, :job_id, :task_id, 2)
19
+ subject.add_task(task)
20
+ subject.peek.priority.should eq(2)
21
+ end
22
+
23
+ it "2 tasks against same owner" do
24
+ subject.add_task(SimpleTask.new(:owner_id, :job_id, :task_id, 2))
25
+ subject.add_task(SimpleTask.new(:owner_id, :job2_id, :task2_id, 2))
26
+ subject.peek.priority.should eq(2)
27
+ subject.number_of_priorities.should eq(1)
28
+ subject.number_if_items_at_priority(2).should eq(1)
29
+
30
+ subject.peek.number_of_priorities.should eq(1)
31
+ subject.peek.number_if_items_at_priority(2).should eq(2)
32
+
33
+ subject.next_task.id.should eq(:task_id)
34
+ subject.peek.number_if_items_at_priority(2).should eq(1)
35
+ subject.next_task.id.should eq(:task2_id)
36
+ end
37
+
38
+ it "Adds 3 task against same owner with different priority" do
39
+ subject.add_task(SimpleTask.new(:owner_id, :job_id, :task_id, 3))
40
+ subject.add_task(SimpleTask.new(:owner_id, :job2_id, :task2_id, 2))
41
+ subject.add_task(SimpleTask.new(:owner_id, :job2_id, :task3_id, 4))
42
+
43
+ subject.next_task.id.should eq(:task2_id)
44
+ subject.next_task.id.should eq(:task_id)
45
+ subject.next_task.id.should eq(:task3_id)
46
+ end
47
+
48
+ it "Adds multiple tasks" do
49
+ subject.add_task(SimpleTask.new(:owner_id, :job_id, :task_id, 3))
50
+ subject.add_task(SimpleTask.new(:owner_id, :job2_id, :task2_id, 2))
51
+ subject.add_task(SimpleTask.new(:owner_id, :job2_id, :task3_id, 4))
52
+ subject.add_task(SimpleTask.new(:owner2_id, :job2_id, :task4_id, 1))
53
+ subject.add_task(SimpleTask.new(:owner2_id, :job2_id, :task5_id, 1))
54
+ subject.add_task(SimpleTask.new(:owner3_id, :job3_id, :task6_id, 1))
55
+ subject.add_task(SimpleTask.new(:owner_id, :job4_id, :task7_id, 1))
56
+
57
+ subject.next_task.id.should eq(:task4_id)
58
+ subject.next_task.id.should eq(:task6_id)
59
+ subject.next_task.id.should eq(:task7_id)
60
+ subject.next_task.id.should eq(:task5_id)
61
+ subject.next_task.id.should eq(:task2_id)
62
+ subject.next_task.id.should eq(:task_id)
63
+ subject.next_task.id.should eq(:task3_id)
64
+ end
65
+
66
+ end
67
+
68
+ context "stalled tasks" do
69
+ it "will not return a task from a synchronous job already running" do
70
+ subject.add_task(SimpleTask.new(:owner_id, :job_id, :task_id, 3, {:synchronous=>true}))
71
+ subject.add_task(SimpleTask.new(:owner_id, :job_id, :task_id2, 3, {:synchronous=>false}))
72
+
73
+ task = subject.next_item
74
+ task.id.should be(:task_id)
75
+ subject.next_item.should be_nil
76
+ subject.finish_item(task)
77
+ subject.next_item.id.should eq(:task_id2)
78
+
79
+ end
80
+
81
+ it "will add tasks to empty queues that have not finished" do
82
+ subject.add_task(SimpleTask.new(:owner_id, :job_id, :task_id, 3))
83
+ task = subject.next_item
84
+ task2 = SimpleTask.new(:owner_id, :job_id, :task_id2, 3)
85
+ subject.add_task(task2)
86
+
87
+ task2.get_job.should be(task.get_job)
88
+
89
+ task2.get_job.total_tasks.should eq(2)
90
+
91
+ subject.next_item.should be_nil
92
+ subject.finish_item(task)
93
+ subject.next_item.id.should eq(:task_id2)
94
+
95
+ end
96
+ end
97
+
98
+ end
@@ -0,0 +1,127 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+ require 'background_queue_server'
3
+ require 'background_queue'
4
+ require 'background_queue_worker'
5
+ require 'net/http'
6
+
7
+ require 'rubygems'
8
+ gem "rufus-scheduler"
9
+
10
+ #unless defined? Rails
11
+ module Rails;
12
+ def self.env
13
+ "development"
14
+ end
15
+ end
16
+ #end
17
+
18
+ describe "Serialize Test" do
19
+
20
+ context "saving running tasks" do
21
+
22
+ it "will save running tasks" do
23
+
24
+ File.delete("/tmp/bq_tasks") if File.exist?("/tmp/bq_tasks")
25
+
26
+ config_path = File.expand_path(File.dirname(__FILE__) + '/../../../resources/config-serialize.yml')
27
+
28
+ server = BackgroundQueue::ServerLib::Server.new
29
+
30
+ thread = Thread.new {
31
+ server.start(:config=>config_path, :skip_pid=>true, :command=>:run, :log_file=>"/tmp/bq.log", :log_level=>'debug')
32
+ }
33
+ while server.event_server.nil? || !server.event_server.running
34
+ sleep(0.1)
35
+ end
36
+
37
+ stopped = false
38
+ ss = nil
39
+ begin
40
+
41
+
42
+ mutex = Mutex.new
43
+ condvar = ConditionVariable.new
44
+ called = false
45
+
46
+ meth_name = nil
47
+ ss = TestWorkerServer.new(8001)
48
+ ss.start(Proc.new { |controller|
49
+ meth_name = controller.request.request_method
50
+
51
+ mutex.synchronize {
52
+ called = true
53
+ condvar.signal
54
+ }
55
+ sleep(10)
56
+ controller.render :text => {:percent=>100, :caption=>"Not Done"}.to_json, :type=>"text/text"
57
+ })
58
+
59
+
60
+ client_config_path = File.expand_path(File.dirname(__FILE__) + '/../../../resources/config-client.yml')
61
+
62
+ client = BackgroundQueue::Client.new(client_config_path)
63
+
64
+
65
+ job_handle = client.add_task(:some_worker, :owner_id, :job_id, :task_id, 2, {:something=>:else}, {:domain=>"www.example.com"} )
66
+
67
+ mutex.synchronize {
68
+ unless called
69
+ condvar.wait(mutex, 5)
70
+ end
71
+ }
72
+
73
+ called.should be_true
74
+
75
+ #the job is now running
76
+ server.stop(0.1)
77
+ thread.join
78
+ ss.stop
79
+
80
+ #lets make sure it can load back up and finish properly this time
81
+
82
+ ss = TestWorkerServer.new(8001)
83
+ ss.start(Proc.new { |controller|
84
+ meth_name = controller.request.request_method
85
+
86
+ mutex.synchronize {
87
+ called = true
88
+ condvar.signal
89
+ }
90
+ controller.render :text => {:percent=>100, :caption=>"Done"}.to_json, :type=>"text/text"
91
+ })
92
+
93
+
94
+ server = BackgroundQueue::ServerLib::Server.new
95
+
96
+ thread = Thread.new {
97
+ server.start(:config=>config_path, :skip_pid=>true, :command=>:run, :log_file=>"/tmp/bq.log", :log_level=>'debug')
98
+ }
99
+
100
+ while server.event_server.nil? || !server.event_server.running
101
+ sleep(0.1)
102
+ end
103
+
104
+ stopped = false
105
+
106
+
107
+ ss.wait_to_be_called.should be_true
108
+
109
+ result = client.get_status(job_handle)
110
+
111
+ result.code.should eq(:status)
112
+ result.args[:percent].should eq(100)
113
+ result.args[:caption].should eq('Done')
114
+
115
+ ss.stop
116
+ ensure
117
+ unless stopped
118
+ server.stop
119
+ thread.join
120
+ end
121
+ ss.stop unless ss.nil?
122
+ end
123
+ end
124
+
125
+ end
126
+
127
+ end
@@ -0,0 +1,65 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'background_queue_server'
3
+
4
+
5
+ describe BackgroundQueue::ServerLib::JobRegistry do
6
+
7
+
8
+ context "#register" do
9
+
10
+ subject { BackgroundQueue::ServerLib::JobRegistry.new(3) }
11
+
12
+ it "adds a job to the registry" do
13
+ job = double("job1", :id=>"job1")
14
+ subject.register(job)
15
+ subject.__prv__lru.size.should eq(1)
16
+ end
17
+
18
+ it "updates existing job" do
19
+ job = double("job1", :id=>"job1")
20
+ job2 = double("job1", :id=>"job1")
21
+ subject.register(job)
22
+ subject.__prv__lru.size.should eq(1)
23
+ subject.register(job2)
24
+ subject.__prv__lru.size.should eq(1)
25
+ subject.__prv__lru.get("job1").should be(job2)
26
+ end
27
+
28
+ it "expires jobs" do
29
+ job = double("job1", :id=>"job1")
30
+ job2 = double("job2", :id=>"job2")
31
+ job3 = double("job3", :id=>"job3")
32
+ job4 = double("job4", :id=>"job4")
33
+ subject.register(job)
34
+ subject.register(job2)
35
+ subject.register(job3)
36
+ subject.__prv__lru.size.should eq(3)
37
+ subject.register(job4)
38
+ subject.__prv__lru.size.should eq(3)
39
+ end
40
+ end
41
+
42
+ context "#get_job" do
43
+
44
+ subject { BackgroundQueue::ServerLib::JobRegistry.new(3) }
45
+
46
+ it "moves job to start or lru" do
47
+ job = double("job1", :id=>"job1")
48
+ job2 = double("job2", :id=>"job2")
49
+ job3 = double("job3", :id=>"job3")
50
+ job4 = double("job4", :id=>"job4")
51
+
52
+ subject.register(job)
53
+ subject.register(job2)
54
+ subject.register(job3)
55
+ subject.__prv__lru.size.should eq(3)
56
+
57
+ subject.get_job("job1").should be(job)
58
+ subject.register(job4)
59
+ subject.__prv__lru.size.should eq(3)
60
+ subject.get_job("job1").should be(job)
61
+ subject.get_job("job2").should be_nil
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,525 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'background_queue_server'
3
+
4
+
5
+ describe BackgroundQueue::ServerLib::Job do
6
+
7
+ subject { BackgroundQueue::ServerLib::Job.new(1, :parent) }
8
+ let(:task) { SimpleTask.new(:owner_id, :job_id, :id, :priority, {}) }
9
+
10
+ it "#add_item uses normal priority queue" do
11
+ task.should_receive(:set_job).with(subject)
12
+ task.should_receive(:synchronous?).and_return(false)
13
+ BackgroundQueue::ServerLib::Job.any_instance.should_receive(:push).with(task).and_return(nil)
14
+ subject.add_item(task)
15
+ end
16
+
17
+ it "#next_item uses normal priority queue" do
18
+ BackgroundQueue::ServerLib::Job.any_instance.should_receive(:pop).and_return(:task)
19
+ subject.next_item.should eq(:task)
20
+ end
21
+
22
+ context "#add_item" do
23
+ it "will initialise the status caption if requested" do
24
+ task_with_status = SimpleTask.new(:owner_id, :job_id, :id, :priority, {:initial_progress_caption=>"test"})
25
+ subject.add_item(task_with_status)
26
+ subject.get_current_progress[:caption].should eq("test")
27
+ end
28
+ end
29
+
30
+ context "#set_worker_status" do
31
+ it "will update_finished_status if finished" do
32
+ status = {:percent=>100.0}
33
+
34
+ subject.should_receive(:update_finished_status).with(status)
35
+ subject.set_worker_status(status)
36
+ end
37
+
38
+ it "will get running status and update it if not finished" do
39
+ status = {:percent=>99.0}
40
+ subject.should_receive(:get_running_status).with(status).and_return(:rstatus)
41
+ subject.should_receive(:update_running_status).with(:rstatus, status)
42
+ subject.set_worker_status(status)
43
+ end
44
+
45
+ it "will update meta data if :meta is passed in" do
46
+ status = {:meta=>:meta}
47
+ subject.should_receive(:update_status_meta).with(:meta)
48
+ subject.set_worker_status(status)
49
+ end
50
+ end
51
+
52
+ context "#update_status_meta" do
53
+ it "will add notices to notices meta list" do
54
+ subject.update_status_meta({:notice=>"hello"})
55
+ subject.get_current_progress[:notice].should eq(["hello"])
56
+ subject.update_status_meta({:notice=>"world"})
57
+ subject.get_current_progress[:notice].should eq(["hello", "world"])
58
+ end
59
+ it "will add warnings to warnings meta list" do
60
+ subject.update_status_meta({:warning=>"hello"})
61
+ subject.get_current_progress[:warning].should eq(["hello"])
62
+ subject.update_status_meta({:warning=>"world"})
63
+ subject.get_current_progress[:warning].should eq(["hello", "world"])
64
+ end
65
+ it "will add errors to errors meta list" do
66
+ subject.update_status_meta({:error=>"hello"})
67
+ subject.get_current_progress[:error].should eq(["hello"])
68
+ subject.update_status_meta({:error=>"world"})
69
+ subject.get_current_progress[:error].should eq(["hello", "world"])
70
+ end
71
+ it "will add meta data to meta entry" do
72
+ subject.update_status_meta({:meta=>{:a=>"b"}})
73
+ subject.get_current_progress[:meta].should eq({:a=>"b"})
74
+ subject.update_status_meta({:meta=>{:c=>"d"}})
75
+ subject.get_current_progress[:meta].should eq({:a=>"b", :c=>"d"})
76
+ subject.update_status_meta({:meta=>{:c=>"e"}})
77
+ subject.get_current_progress[:meta].should eq({:a=>"b", :c=>"e"})
78
+ end
79
+ end
80
+
81
+ context "#get_running_status" do
82
+ it "will register a new task if new" do
83
+ status = {:task_id=>:tid}
84
+ subject.should_receive(:register_running_status).with(status).and_return(:new_status)
85
+ subject.get_running_status(status).should eq(:new_status)
86
+ end
87
+
88
+ it "will return an existing registered task" do
89
+ status = {:task_id=>:tid}
90
+ subject.get_running_status(status)[:task_id].should eq(:tid)
91
+ subject.should_not_receive(:register_running_status)
92
+ subject.get_running_status(status)[:task_id].should eq(:tid)
93
+ end
94
+ end
95
+
96
+ context "#register_running_status" do
97
+ it "will add a status to map and ordered array" do
98
+ status = {:task_id=>:some_status}
99
+ subject.register_running_status(status)[:task_id].should eq(:some_status)
100
+ subject.running_status[:some_status][:task_id].should eq(:some_status)
101
+ subject.running_ordered_status.should have(1).item
102
+ subject.running_ordered_status[0][:task_id].should eq(:some_status)
103
+ end
104
+
105
+ #it "will not add to ordered array if excluded from count" do
106
+ # status = {:task_id=>:some_status, :exclude=>true}
107
+ # subject.register_running_status(status)[:task_id].should eq(:some_status)
108
+ # subject.running_status[:some_status][:task_id].should eq(:some_status)
109
+ # subject.running_ordered_status.should have(0).items
110
+ #end
111
+ end
112
+
113
+ context "#deregister_running_status" do
114
+ it "will remove the status from the map and the ordered array" do
115
+ status = {:task_id=>:tid}
116
+ status2 = {:task_id=>:tid2}
117
+ subject.running_status[:tid] = status
118
+ subject.running_ordered_status << status
119
+ subject.running_status[:tid2] = status2
120
+ subject.running_ordered_status << status2
121
+ subject.deregister_running_status(:tid)
122
+ subject.running_status[:tid].should be_nil
123
+ subject.running_ordered_status.should have(1).item
124
+ subject.running_ordered_status.first.should be(status2)
125
+
126
+ subject.deregister_running_status(:tid2)
127
+ subject.running_ordered_status.should have(0).items
128
+
129
+ end
130
+ end
131
+
132
+ context "#update_finished_status" do
133
+ it "will remove the task as running and increment the finished count" do
134
+ status = {:task_id=>:tid, :percent=>100.0}
135
+ subject.should_receive(:deregister_running_status).with(:tid).and_return({:exclude=>false})
136
+ subject.update_finished_status(status)
137
+ subject.completed_tasks.should eq(1)
138
+ subject.completed_counted_tasks.should eq(1)
139
+ end
140
+
141
+ it "will remove the task as running and increment the finished count but not counted" do
142
+ status = {:task_id=>:tid, :percent=>100.0, :exclude=>true}
143
+ subject.should_receive(:deregister_running_status).with(:tid).and_return({:exclude=>true})
144
+ subject.update_finished_status(status)
145
+ subject.completed_tasks.should eq(1)
146
+ subject.completed_counted_tasks.should eq(0)
147
+ end
148
+
149
+ it "will do nothing if the task has not been registered as running" do
150
+ status = {:task_id=>:tid, :percent=>100.0}
151
+ subject.update_finished_status(status)
152
+ subject.completed_tasks.should eq(0)
153
+ end
154
+
155
+ it "will increment the completed weighted tasks" do
156
+ status = {:task_id=>:tid, :percent=>100.0, :exclude=>true, :weight=>5.0}
157
+ subject.should_receive(:deregister_running_status).with(:tid).and_return({:exclude=>true, :weight=>5.0})
158
+ subject.update_finished_status(status)
159
+ subject.completed_tasks.should eq(1)
160
+ subject.completed_counted_tasks.should eq(0)
161
+ subject.completed_weighted_percent.should eq(5.0)
162
+ subject.completed_weighted_tasks.should eq(1)
163
+ end
164
+ end
165
+
166
+
167
+
168
+ context "#update_running_status" do
169
+ it "will update the comment and percent of the task" do
170
+ status = {:task_id=>:tid, :percent=>55.0, :caption=>"hello"}
171
+ rstatus = {:task_id=>:tid, :percent=>40.0, :caption=>"bye"}
172
+ subject.should_receive(:update_running_percent)
173
+ subject.update_running_status(rstatus, status)
174
+ rstatus[:percent].should eq(55.0)
175
+ rstatus[:caption].should eq("hello")
176
+
177
+ end
178
+ end
179
+
180
+ context "#update_running_percent" do
181
+ it "will get the total percent through of the running tasks and set_current_status" do
182
+ status = {:task_id=>:tid, :percent=>90.0}
183
+ status2 = {:task_id=>:tid2, :percent=>22.0}
184
+ subject.running_ordered_status << status
185
+ subject.running_ordered_status << status2
186
+ subject.should_receive(:set_running_percent).with(1.12, 1.12, 1.12, 0.0)
187
+ subject.update_running_percent
188
+ end
189
+
190
+ it "will get the running percent of weighted tasks" do
191
+ status = {:task_id=>:tid, :percent=>90.0}
192
+ status2 = {:task_id=>:tid2, :percent=>22.0}
193
+ status3 = {:task_id=>:tid2, :percent=>20.0, :weight=>5.0}
194
+ status4 = {:task_id=>:tid2, :percent=>50.0, :weight=>10.0}
195
+ subject.running_ordered_status << status
196
+ subject.running_ordered_status << status2
197
+ subject.running_ordered_status << status3
198
+ subject.running_ordered_status << status4
199
+ subject.should_receive(:set_running_percent).with(1.12, 1.12, 1.82, 0.06)
200
+ subject.update_running_percent
201
+ end
202
+
203
+
204
+
205
+ end
206
+
207
+ context "#set_running_percent" do
208
+ context "without excluded" do
209
+ before do
210
+ @status = {:task_id=>:tid, :percent=>90.0}
211
+ @status2 = {:task_id=>:tid2, :percent=>22.0}
212
+ @status3 = {:task_id=>:tid3, :percent=>22.0}
213
+ subject.running_ordered_status << @status
214
+ subject.running_ordered_status << @status2
215
+ subject.running_ordered_status << @status3
216
+ end
217
+
218
+ it "will set status to the first status if the running percent is 0" do
219
+ subject.set_running_percent(0.0, 0.0, 0.0, 0.0)
220
+ subject.current_running_status.should be(@status)
221
+ end
222
+
223
+ it "will set status to the first status if the running percent is < 1" do
224
+ subject.set_running_percent(0.9, 0.9, 0.9, 0.0)
225
+ subject.current_running_status.should be(@status)
226
+ end
227
+
228
+ it "will set status to the second status if the running percent is < 2 > 1 " do
229
+ subject.set_running_percent(1.2, 1.2, 1.2, 0.0)
230
+ subject.current_running_status.should be(@status2)
231
+ end
232
+
233
+ it "will set status to the second status if the running percent is < 3 > 2 " do
234
+ subject.set_running_percent(2.99, 2.99, 2.99, 0.0)
235
+ subject.current_running_status.should be(@status3)
236
+ end
237
+
238
+ end
239
+
240
+ context "with excluded" do
241
+ it "will use the current_running_excluded_status if there are no running_ordered_status" do
242
+ status = {:task_id=>:tid, :percent=>55.0, :caption=>"hello", :exclude=>true}
243
+ subject.set_worker_status(status)
244
+ subject.set_running_percent(0, 0.55, 0.55, 0.0)
245
+ subject.current_running_status[:task_id].should eq(:tid)
246
+ end
247
+
248
+ it "will not use the current_running_excluded_status if there are running_ordered_status" do
249
+ subject.set_worker_status({:task_id=>:tid, :percent=>55.0, :caption=>"hello", :exclude=>true})
250
+ subject.set_worker_status({:task_id=>:tid2, :percent=>55.0, :caption=>"hello2", :exclude=>false})
251
+ subject.set_running_percent(0.55, 1.1, 1.1, 0.0)
252
+ subject.current_running_status[:task_id].should eq(:tid2)
253
+ end
254
+
255
+ it "will not use the current_running_excluded_status if there are running_ordered_status even if at 0" do
256
+ subject.set_worker_status({:task_id=>:tid, :percent=>55.0, :caption=>"hello", :exclude=>true})
257
+ subject.set_worker_status({:task_id=>:tid2, :percent=>55.0, :caption=>"hello2", :exclude=>false})
258
+ subject.set_running_percent(0.0, 1.1, 1.1, 0.0)
259
+ subject.current_running_status[:task_id].should eq(:tid2)
260
+ end
261
+ end
262
+ end
263
+
264
+ context "#get_current_progress_percent" do
265
+ it "will start at 0%" do
266
+ subject.get_current_progress_percent.should eq(0)
267
+ end
268
+
269
+ it "will use single task percent" do
270
+ subject.stub(:total_tasks=>1, :completed_tasks=>0, :running_percent=>0.5)
271
+ subject.get_current_progress_percent.should eq(50.0)
272
+ end
273
+
274
+ it "will track multiple tasks" do
275
+ subject.stub(:total_tasks=>4, :completed_tasks=>2, :running_percent=>0.10)
276
+ #50% + 10/4%
277
+ subject.get_current_progress_percent.should eq(52.5)
278
+ end
279
+
280
+ it "will track weighted tasks" do
281
+ subject.stub(:total_tasks=>4, :completed_tasks=>2, :running_percent=>0.10, :total_weighted_percent=>40.0, :completed_weighted_percent=>20.0, :running_percent_weighted=>0.1)
282
+ #weighted_percent = 40%
283
+ #unweighted_percent = 60%
284
+ #completed percent = 2/4 = 50% of unweighted_percent = 30%
285
+ #running percent = 10% of 1 task (25% of 60%) = 1.5%
286
+ #completed_weighted_percent = 20%
287
+ #running weighted_percent = 10%
288
+ #total = 61.5%
289
+ subject.get_current_progress_percent.should eq(61.5)
290
+
291
+ end
292
+
293
+ end
294
+
295
+ context "#get_current_progress_caption" do
296
+ it "will start blank" do
297
+ subject.get_current_progress_caption.should eq("")
298
+ end
299
+
300
+ it "will use the caption from the designated running task" do
301
+ subject.stub(:current_running_status=>{:caption=>:cappy})
302
+ subject.get_current_progress_caption.should eq(:cappy)
303
+ end
304
+
305
+ it "will add a counter if the current task is counted, and the total counted tasks > 1" do
306
+ subject.stub(:current_running_status=>{:caption=>'cappy'}, :total_counted_tasks=>2, :completed_counted_tasks=>0)
307
+ subject.get_current_progress_caption.should eq('cappy (1/2)')
308
+ end
309
+
310
+ it "will not add a counter if the current task is not counted" do
311
+ status = {:caption=>'cappy', :exclude=>true}
312
+ subject.stub(:current_running_status=>status, :total_counted_tasks=>2, :completed_counted_tasks=>0)
313
+ subject.get_current_progress_caption.should eq('cappy')
314
+ end
315
+
316
+ it "will not add a counter if the total counted tasks is 1" do
317
+ status = {:caption=>'cappy'}
318
+ subject.stub(:current_running_status=>status, :total_counted_tasks=>1, :completed_counted_tasks=>0)
319
+ subject.get_current_progress_caption.should eq('cappy')
320
+ end
321
+ end
322
+
323
+ context "integration" do
324
+ it "will track progress" do
325
+ task0 = BackgroundQueue::ServerLib::Task.new(:owner_id, :job_id, :id0, 1, :worker, {}, {:exclude=>true})
326
+ subject.add_item(task0)
327
+ task1 = BackgroundQueue::ServerLib::Task.new(:owner_id, :job_id, :id1, 1, :worker, {}, {})
328
+ subject.add_item(task1)
329
+ task2 = BackgroundQueue::ServerLib::Task.new(:owner_id, :job_id, :id2, 1, :worker, {}, {})
330
+ subject.add_item(task2)
331
+ task3 = BackgroundQueue::ServerLib::Task.new(:owner_id, :job_id, :id3, 1, :worker, {}, {})
332
+ subject.add_item(task3)
333
+
334
+ subject.total_tasks.should eq(4)
335
+ subject.total_counted_tasks.should eq(3)
336
+
337
+ subject.get_current_progress[:percent].should eq(0.0)
338
+
339
+ task = subject.next_item
340
+ subject.get_current_progress[:percent].should eq(0.0)
341
+
342
+ task.set_worker_status(:percent=>10.0, :caption=>"loading")
343
+ subject.current_running_status[:task_id].should eq(:id0)
344
+ subject.running_percent.should eq(0.1)
345
+
346
+ subject.get_current_progress[:percent].should eq(2.5)
347
+ subject.get_current_progress[:caption].should eq("loading")
348
+
349
+ task.set_worker_status(:percent=>50.0, :caption=>"loading")
350
+
351
+ subject.get_current_progress[:percent].should eq(12.5)
352
+
353
+ task.set_worker_status(:percent=>100.0, :caption=>"loading")
354
+
355
+ subject.get_current_progress[:percent].should eq(25.0)
356
+
357
+ task1 = subject.next_item
358
+ task2 = subject.next_item
359
+
360
+ task1.set_worker_status(:percent=>10.0, :caption=>"task1")
361
+ task2.set_worker_status(:percent=>10.0, :caption=>"task2")
362
+
363
+ #25% + 20%/4 = 30%
364
+ subject.get_current_progress[:percent].should eq(30.0)
365
+ subject.get_current_progress[:caption].should eq("task1 (1/3)")
366
+
367
+ task1.set_worker_status(:percent=>50.0, :caption=>"task1")
368
+ #25% + 60%/4 = 30%
369
+ subject.get_current_progress[:percent].should eq(40.0)
370
+ subject.get_current_progress[:caption].should eq("task1 (1/3)")
371
+
372
+ task1.set_worker_status(:percent=>70.0, :caption=>"task1")
373
+ task2.set_worker_status(:percent=>30.0, :caption=>"task2")
374
+
375
+ #25% + 100%/4 = 50%
376
+ subject.get_current_progress[:percent].should eq(50.0)
377
+ subject.get_current_progress[:caption].should eq("task2 (2/3)")
378
+
379
+ task1.set_worker_status(:percent=>100.0, :caption=>"task1")
380
+
381
+
382
+ #25% + 130%/4 = 57.5%
383
+ subject.get_current_progress[:percent].should eq(57.5)
384
+ subject.get_current_progress[:caption].should eq("task2 (2/3)")
385
+
386
+ task3 = subject.next_item
387
+
388
+ #50% + 50%/4 = 62.5
389
+ task2.set_worker_status(:percent=>50.0, :caption=>"task2")
390
+ subject.get_current_progress[:percent].should eq(62.5)
391
+ subject.get_current_progress[:caption].should eq("task2 (2/3)")
392
+
393
+ #50% + 100%/4 = 75%
394
+ task3.set_worker_status(:percent=>50.0, :caption=>"task3")
395
+ subject.get_current_progress[:percent].should eq(75.0)
396
+ subject.get_current_progress[:caption].should eq("task3 (3/3)")
397
+
398
+ #75% + 50%/4 = 87.5%
399
+ task2.set_worker_status(:percent=>100.0, :caption=>"task2")
400
+ subject.get_current_progress[:percent].should eq(87.5)
401
+ subject.get_current_progress[:caption].should eq("task3 (3/3)")
402
+
403
+ #75% + 50%/4 = 87.5%
404
+ task3.set_worker_status(:percent=>100.0, :caption=>"task3")
405
+ subject.get_current_progress[:percent].should eq(100.0)
406
+ subject.get_current_progress[:caption].should eq("task3 (3/3)")
407
+
408
+ end
409
+
410
+ it "will track weighted tasks" do
411
+ task0 = BackgroundQueue::ServerLib::Task.new(:owner_id, :job_id, :id0, 1, :worker, {}, {:exclude=>true, :weight=>20.0})
412
+ subject.add_item(task0)
413
+
414
+ subject.total_weighted_percent.should eq(20.0)
415
+ subject.total_weighted_tasks.should eq(1)
416
+
417
+ subject.get_current_progress[:percent].should eq(0.0)
418
+
419
+ task = subject.next_item
420
+ subject.get_current_progress[:percent].should eq(0.0)
421
+
422
+ task.set_worker_status(:percent=>10.0, :caption=>"loading")
423
+ subject.current_running_status[:task_id].should eq(:id0)
424
+ subject.running_percent_weighted.should eq(0.02)
425
+ subject.running_percent.should eq(0.0)
426
+ subject.total_weighted_tasks.should eq(1)
427
+ subject.total_tasks.should eq(1)
428
+ subject.completed_weighted_tasks.should eq(0.0)
429
+ subject.completed_tasks.should eq(0.0)
430
+
431
+ subject.get_current_progress[:percent].should eq(2.0)
432
+ subject.get_current_progress[:caption].should eq("loading")
433
+
434
+ task1 = BackgroundQueue::ServerLib::Task.new(:owner_id, :job_id, :id1, 1, :worker, {}, {})
435
+ subject.add_item(task1)
436
+ task2 = BackgroundQueue::ServerLib::Task.new(:owner_id, :job_id, :id2, 1, :worker, {}, {})
437
+ subject.add_item(task2)
438
+ task3 = BackgroundQueue::ServerLib::Task.new(:owner_id, :job_id, :id3, 1, :worker, {}, {})
439
+ subject.add_item(task3)
440
+
441
+ task5 = BackgroundQueue::ServerLib::Task.new(:owner_id, :job_id, :id4, 1, :worker, {}, {:exclude=>true, :weight=>20.0})
442
+ subject.add_item(task5)
443
+
444
+ subject.get_current_progress[:percent].should eq(2.0)
445
+ subject.get_current_progress[:caption].should eq("loading")
446
+
447
+ task.set_worker_status(:percent=>50.0, :caption=>"loading")
448
+
449
+ subject.get_current_progress[:percent].should eq(10.0)
450
+ subject.get_current_progress[:caption].should eq("loading")
451
+
452
+ task1 = subject.next_item
453
+ task2 = subject.next_item
454
+
455
+ task1.set_worker_status(:percent=>10.0, :caption=>"task1")
456
+ task2.set_worker_status(:percent=>10.0, :caption=>"task2")
457
+
458
+ #10% + 10% of 20% + 10% of 20% = 14%
459
+
460
+
461
+ subject.current_running_status[:task_id].should eq(:id0)
462
+ subject.running_percent_weighted.should eq(0.1)
463
+ subject.running_percent.should eq(0.2)
464
+ subject.total_weighted_tasks.should eq(2)
465
+ subject.total_tasks.should eq(5)
466
+ subject.completed_weighted_tasks.should eq(0.0)
467
+ subject.completed_tasks.should eq(0.0)
468
+
469
+ subject.get_current_progress[:percent].should eq(14.0)
470
+ subject.get_current_progress[:caption].should eq("loading")
471
+
472
+ task1.set_worker_status(:percent=>80.0, :caption=>"task1")
473
+ #the task will now switch over to the next running task...
474
+ subject.current_running_status[:task_id].should eq(:id1)
475
+ subject.get_current_progress[:caption].should eq("task1 (1/3)")
476
+
477
+ #10% + 10% of 20% + 80% of 20% = 28%
478
+ subject.get_current_progress[:percent].should eq(28.0)
479
+
480
+ #finish first weighted task
481
+ task.set_worker_status(:percent=>100.0, :caption=>"loaded")
482
+ subject.running_percent_weighted.should eq(0.0)
483
+ subject.running_percent.should eq(0.9)
484
+ subject.total_weighted_tasks.should eq(2)
485
+ subject.total_tasks.should eq(5)
486
+ subject.completed_weighted_tasks.should eq(1)
487
+ subject.completed_tasks.should eq(1)
488
+ subject.completed_counted_tasks.should eq(0)
489
+ subject.completed_weighted_percent.should eq(20.0)
490
+
491
+ #20% + 10% of 20% + 80% of 20% = 38%
492
+ subject.get_current_progress[:caption].should eq("task1 (1/3)")
493
+ subject.get_current_progress[:percent].should eq(38.0)
494
+
495
+ task2.set_worker_status(:percent=>30.0, :caption=>"task2")
496
+ #the task will now switch over to the next running task...
497
+ subject.current_running_status[:task_id].should eq(:id2)
498
+ subject.get_current_progress[:caption].should eq("task2 (2/3)")
499
+
500
+ task1.set_worker_status(:percent=>100.0, :caption=>"task1")
501
+ subject.get_current_progress[:caption].should eq("task2 (2/3)")
502
+
503
+ task2.set_worker_status(:percent=>100.0, :caption=>"task2")
504
+ subject.get_current_progress[:caption].should eq("task2 (3/3)")
505
+
506
+ #20% + 100% of 20% + 100% of 20% = 60%
507
+ #subject.get_current_progress[:percent].should eq(60.0)
508
+
509
+ task3 = subject.next_item
510
+ task3.set_worker_status(:percent=>100.0, :caption=>"task3")
511
+ subject.get_current_progress[:caption].should eq("task3 (3/3)")
512
+ subject.get_current_progress[:percent].should eq(80.0)
513
+
514
+ task4 = subject.next_item
515
+ task4.set_worker_status(:percent=>50.0, :caption=>"task4")
516
+ subject.get_current_progress[:caption].should eq("task4")
517
+ subject.get_current_progress[:percent].should eq(90.0)
518
+
519
+ task4.set_worker_status(:percent=>100.0, :caption=>"task4")
520
+ subject.get_current_progress[:caption].should eq("task4")
521
+ subject.get_current_progress[:percent].should eq(100.0)
522
+ end
523
+
524
+ end
525
+ end