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,5 @@
1
+ require "background_queue/worker/base"
2
+ require "background_queue/worker/environment"
3
+ require "background_queue/worker/worker_loader"
4
+ require "background_queue/worker/calling"
5
+ require "background_queue/worker/config"
@@ -0,0 +1,75 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'background_queue'
3
+
4
+ describe "Command" do
5
+
6
+ context "add_task" do
7
+ it "creates valid command" do
8
+ cmd = BackgroundQueue::ClientLib::Command.add_task_command(:worker, :owner_id, :job_id, :task_id, 1, {:a=>:b}, {:c=>:d} )
9
+ cmd.code.should eq(:add_task)
10
+ cmd.options[:c].should eq(:d)
11
+ cmd.args[:worker].should eq(:worker)
12
+ cmd.args[:owner_id].should eq(:owner_id)
13
+ cmd.args[:job_id].should eq(:job_id)
14
+ cmd.args[:task_id].should eq(:task_id)
15
+ cmd.args[:params][:a].should eq(:b)
16
+
17
+ end
18
+ end
19
+
20
+ context "add_tasks" do
21
+ it "creates valid command" do
22
+ cmd = BackgroundQueue::ClientLib::Command.add_tasks_command(:worker, :owner_id, :job_id, [[:task1_id, {:a=>:b}], [:task2_id, {:e=>:f}]], 1, {:shared=>:param}, {:c=>:d} )
23
+ cmd.code.should eq(:add_tasks)
24
+ cmd.options[:c].should eq(:d)
25
+ cmd.args[:worker].should eq(:worker)
26
+ cmd.args[:owner_id].should eq(:owner_id)
27
+ cmd.args[:job_id].should eq(:job_id)
28
+ cmd.args[:shared_parameters][:shared].should eq(:param)
29
+ cmd.args[:tasks].length.should eq(2)
30
+ cmd.args[:tasks].first.length.should eq(2)
31
+ cmd.args[:tasks].first[0].should eq(:task1_id)
32
+ cmd.args[:tasks].first[1][:a].should eq(:b)
33
+ cmd.args[:tasks].last.length.should eq(2)
34
+ cmd.args[:tasks].last[0].should eq(:task2_id)
35
+ cmd.args[:tasks].last[1][:e].should eq(:f)
36
+ end
37
+
38
+ it "fails if no tasks are defined" do
39
+ expect {
40
+ cmd = BackgroundQueue::ClientLib::Command.add_tasks_command(:worker, :owner_id, :job_id, [], 1, {:shared=>:param}, {:c=>:d} )
41
+ }.to raise_exception(BackgroundQueue::InvalidCommand, "No Tasks In List")
42
+ end
43
+ end
44
+
45
+
46
+ context "#get_status_command" do
47
+ it "creates valid command" do
48
+ cmd = BackgroundQueue::ClientLib::Command.get_status_command(:job_id, {:c=>:d} )
49
+ cmd.code.should eq(:get_status)
50
+ cmd.options[:c].should eq(:d)
51
+ cmd.args[:job_id].should eq(:job_id)
52
+ end
53
+ end
54
+
55
+
56
+ #i cant see why this would be needed.... will add back if needed
57
+ #context "remove_tasks" do
58
+ # it "creates valid command" do
59
+ # cmd = BackgroundQueue::ClientLib::Command.remove_tasks_command([:task1_id,:task2_id], {:c=>:d} )
60
+ # cmd.code.should eq(:remove_tasks)
61
+ # cmd.options[:c].should eq(:d)
62
+ # cmd.args[:tasks].length.should eq(2)
63
+ # cmd.args[:tasks][0].should eq(:task1_id)
64
+ # cmd.args[:tasks][1].should eq(:task2_id)
65
+ # end
66
+ #
67
+ # it "fails if no tasks are defined" do
68
+ # expect {
69
+ # cmd = BackgroundQueue::ClientLib::Command.remove_tasks_command([], {:c=>:d} )
70
+ # }.to raise_exception(BackgroundQueue::InvalidCommand, "No Tasks In List")
71
+ # end
72
+ #end
73
+
74
+
75
+ end
@@ -0,0 +1,156 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'background_queue'
3
+
4
+ unless defined? Rails
5
+ module Rails; end
6
+ end
7
+
8
+ describe "Client Config" do
9
+
10
+ context "using map" do
11
+ context "loading server entry" do
12
+ it "creates a server entry if all required string fields exist" do
13
+ entry = BackgroundQueue::ClientLib::Config::Server.new({
14
+ 'host'=>"127.0.0.1",
15
+ 'port'=>85
16
+ })
17
+ entry.host.should eq("127.0.0.1")
18
+ entry.port.should eq(85)
19
+ end
20
+
21
+ it "creates a server entry if all required symbol fields exist" do
22
+ entry = BackgroundQueue::ClientLib::Config::Server.new({
23
+ :host=>"127.0.0.1",
24
+ :port=>85
25
+ })
26
+ entry.host.should eq("127.0.0.1")
27
+ entry.port.should eq(85)
28
+ end
29
+
30
+ it "creates a server entry using default port" do
31
+ entry = BackgroundQueue::ClientLib::Config::Server.new({
32
+ :host=>"127.0.0.1"
33
+ })
34
+ entry.host.should eq("127.0.0.1")
35
+ entry.port.should eq(BackgroundQueue::ClientLib::Config::DEFAULT_PORT)
36
+ end
37
+
38
+ it "errors if missing or invalid hostname on server entry" do
39
+ expect {
40
+ BackgroundQueue::ClientLib::Config::Server.new({})
41
+ }.to raise_error(
42
+ BackgroundQueue::LoadError,
43
+ "Missing 'host' configuration entry"
44
+ )
45
+ end
46
+
47
+ it "errors if invalid type" do
48
+ expect {
49
+ BackgroundQueue::ClientLib::Config::Server.new([])
50
+ }.to raise_error(
51
+ BackgroundQueue::LoadError,
52
+ "Invalid data type (Array), expecting Hash"
53
+ )
54
+ end
55
+ end
56
+
57
+ context "loading primary server entry" do
58
+ before do
59
+ File.stub(:expand_path) { :expanded_path }
60
+ end
61
+
62
+ it "creates primary server entry" do
63
+ entry = BackgroundQueue::ClientLib::Config.__prv__build_primary_server_entry({ 'server'=> { :host=>"127.0.0.1" }}, :path_that_exists)
64
+ entry.host.should eq("127.0.0.1")
65
+ end
66
+
67
+ it "errors if missing" do
68
+ expect {
69
+ BackgroundQueue::ClientLib::Config.__prv__build_primary_server_entry({}, :path_that_exists)
70
+ }.to raise_error(
71
+ BackgroundQueue::LoadError,
72
+ "Missing 'server' entry in background queue configuration file expanded_path"
73
+ )
74
+ end
75
+
76
+ it "errors if invalid" do
77
+ expect {
78
+ BackgroundQueue::ClientLib::Config.__prv__build_primary_server_entry({:server=> {}}, :path_that_exists)
79
+ }.to raise_error(
80
+ BackgroundQueue::LoadError,
81
+ "Error loading 'server' entry from background queue configuration file expanded_path: Missing 'host' configuration entry"
82
+ )
83
+ end
84
+ end
85
+
86
+ context "loading failover server entries" do
87
+
88
+ it "creates failover server entries if defined" do
89
+ entries = BackgroundQueue::ClientLib::Config.__prv__build_failover_server_entries({ :failover=> [{ :host=>"127.0.0.1" }, { :host=>"127.0.0.2" }]}, :path_that_exists)
90
+ entries.length.should eq(2)
91
+ entries.first.host.should eq("127.0.0.1")
92
+ entries.last.host.should eq("127.0.0.2")
93
+ end
94
+
95
+ it "errors if failover entry is invalid" do
96
+ File.stub(:expand_path) { :expanded_path }
97
+ expect {
98
+ BackgroundQueue::ClientLib::Config.__prv__build_failover_server_entries({ 'failover'=> [{ :host=>"127.0.0.1" }, { }]}, :path_that_exists)
99
+ }.to raise_error(
100
+ BackgroundQueue::LoadError,
101
+ "Error loading 'failover' entry (2) from background queue configuration file expanded_path: Missing 'host' configuration entry"
102
+ )
103
+ end
104
+
105
+ end
106
+
107
+
108
+
109
+ context "creating Config entry" do
110
+ before do
111
+ File.stub(:expand_path) { :expanded_path }
112
+ end
113
+
114
+ it "should create Config instance" do
115
+ config = BackgroundQueue::ClientLib::Config.load_hash({
116
+ :server=>{:host=>"127.0.0.1"},
117
+ :failover=>[{:host=>"127.0.0.2"}, {:host=>"127.0.0.3"}],
118
+ :memcache=> "127.0.0.1:4000"
119
+ }, :path_that_exists)
120
+ config.server.host.should eq("127.0.0.1")
121
+ config.failover.length.should eq(2)
122
+ config.failover.first.host.should eq("127.0.0.2")
123
+ config.failover.last.host.should eq("127.0.0.3")
124
+ config.memcache.length.should eq(1)
125
+ config.memcache.first.should eq('127.0.0.1:4000')
126
+ end
127
+
128
+ it "should fail when missing server" do
129
+ expect {
130
+ config = BackgroundQueue::ClientLib::Config.load_hash({ }, :path_that_exists)
131
+ }.to raise_error(
132
+ BackgroundQueue::LoadError,
133
+ "Missing 'server' entry in background queue configuration file expanded_path"
134
+ )
135
+ end
136
+
137
+ it "should fail when missing memcache" do
138
+ expect {
139
+ config = BackgroundQueue::ClientLib::Config.load_hash({ :server=>{:host=>"127.0.0.1"} }, :path_that_exists)
140
+ }.to raise_error(
141
+ BackgroundQueue::LoadError,
142
+ "Missing 'memcache' entry in configuration file expanded_path"
143
+ )
144
+ end
145
+
146
+ it "should not fail when missing failover" do
147
+ config = BackgroundQueue::ClientLib::Config.load_hash({
148
+ :server=>{:host=>"127.0.0.1"},
149
+ :memcache=> "127.0.0.1:4000"
150
+ }, :path_that_exists)
151
+ config.failover.length.should eq(0)
152
+ end
153
+ end
154
+ end
155
+
156
+ end
@@ -0,0 +1,170 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'background_queue'
3
+
4
+ describe "Connection" do
5
+
6
+ let(:server) {
7
+ svr = double('Server')
8
+ svr.stub({:host=>:host, :port=>:port})
9
+ svr
10
+ }
11
+
12
+
13
+
14
+ context "connecting" do
15
+
16
+ subject { BackgroundQueue::ClientLib::Connection.new(:client, server) }
17
+
18
+ it "can successfully connect" do
19
+ TCPSocket.should_receive(:open).with(:host, :port) { :socket }
20
+ subject.__prv__connect.should eq(true)
21
+ end
22
+
23
+ it "fails when no server to connect to" do
24
+ TCPSocket.should_receive(:open).with(:host, :port) { raise "Unable to connect" }
25
+ expect { subject.__prv__connect }.to raise_error(BackgroundQueue::ClientLib::ConnectionError, "Error Connecting to host:port: Unable to connect")
26
+ end
27
+
28
+ it "fails if connection times out" do
29
+ Timeout.should_receive(:timeout).with(any_args) { raise Timeout::Error }
30
+ expect { subject.__prv__connect }.to raise_error(BackgroundQueue::ClientLib::ConnectionError, "Timeout Connecting to host:port")
31
+ end
32
+ end
33
+
34
+ context "connected" do
35
+
36
+ let(:socket) { stub() }
37
+
38
+ subject {
39
+ s = BackgroundQueue::ClientLib::Connection.new(:client, server)
40
+ TCPSocket.should_receive(:open).with(:host, :port) { socket }
41
+ s.__prv__connect
42
+ s
43
+ }
44
+
45
+ context "sending data" do
46
+
47
+ it "can send data successfully in one go" do
48
+ buf = "some data"
49
+ socket.should_receive(:write).with(buf) { buf.length }
50
+ subject.__prv__send_data(buf).should eq(true)
51
+ end
52
+
53
+ it "can send data successfully in 3 goes" do
54
+ buf = "12345678"
55
+ socket.should_receive(:write).with("12345678") { 2 }
56
+ socket.should_receive(:write).with("345678") { 3 }
57
+ socket.should_receive(:write).with("678") { 3 }
58
+ subject.__prv__send_data(buf).should eq(true)
59
+ end
60
+
61
+ it "fails when underlying network fails" do
62
+ buf = "12345678"
63
+ socket.should_receive(:write).with("12345678") { 2 }
64
+ socket.should_receive(:write).with("345678") { raise "Socket Disconnected" }
65
+
66
+ expect { subject.__prv__send_data(buf)}.to raise_error(BackgroundQueue::ClientLib::ConnectionError, "Error Sending to host:port: Socket Disconnected")
67
+ end
68
+
69
+ it "fails when command times out" do
70
+ init_subject = subject #need to init the subject before forcing timeout
71
+ Timeout.should_receive(:timeout).with(any_args) { raise Timeout::Error }
72
+ expect { init_subject.__prv__send_data("data")}.to raise_error(BackgroundQueue::ClientLib::ConnectionError, "Timeout Sending to host:port")
73
+ end
74
+ end
75
+
76
+ context "sending with header" do
77
+
78
+ let(:data) { "data"}
79
+ let(:packed_data) { [1,4,data].pack("SLZ4") }
80
+
81
+ it "can pack the header onto the data" do
82
+ BackgroundQueue::ClientLib::Connection.add_header(data).should eq(packed_data)
83
+ end
84
+
85
+ it "can send data with header" do
86
+ subject.should_receive(:send_data).with(packed_data) { true}
87
+ subject.__prv__send_with_header(data).should eq(true)
88
+ end
89
+
90
+ end
91
+
92
+ context "receiving data" do
93
+ it "can receive data successfully in one go" do
94
+ socket.should_receive(:recvfrom).with(4) { ["data", nil] }
95
+ subject.__prv__receive_data(4).should eq("data")
96
+ end
97
+
98
+ it "can receive data successfully in 3 goes" do
99
+ socket.should_receive(:recvfrom).with(10) { ["0123", nil] }
100
+ socket.should_receive(:recvfrom).with(6) { ["45", nil] }
101
+ socket.should_receive(:recvfrom).with(4) { ["6789", nil] }
102
+ subject.__prv__receive_data(10).should eq("0123456789")
103
+ end
104
+
105
+ it "fails when underlying network fails" do
106
+ socket.should_receive(:recvfrom).with(10) { ["0123", nil] }
107
+ socket.should_receive(:recvfrom).with(6) { raise "Socket Disconnected" }
108
+ expect { subject.__prv__receive_data(10)}.to raise_error(BackgroundQueue::ClientLib::ConnectionError, "Error Receiving 10 bytes from host:port: Socket Disconnected")
109
+ end
110
+
111
+ it "fails when response times out" do
112
+ init_subject = subject #need to init the subject before forcing timeout
113
+ Timeout.should_receive(:timeout).with(any_args) { raise Timeout::Error }
114
+ expect { init_subject.__prv__receive_data(10)}.to raise_error(BackgroundQueue::ClientLib::ConnectionError, "Timeout Receiving 10 bytes from host:port")
115
+ end
116
+ end
117
+
118
+ context "receiving with header" do
119
+
120
+ let(:data) { "data"}
121
+ let(:packed_data) { [1,4,data].pack("SLZ4") }
122
+
123
+
124
+ it "can receive data with header" do
125
+ subject.should_receive(:receive_data).with(6) { packed_data[0,6] }
126
+ subject.should_receive(:receive_data).with(4) { packed_data[6,4] }
127
+
128
+ subject.__prv__receive_with_header().should eq(data)
129
+ end
130
+
131
+ end
132
+ end
133
+
134
+
135
+ context "sending command" do
136
+
137
+ subject { BackgroundQueue::ClientLib::Connection.new(:client, server) }
138
+ let(:send_command) { stub({:to_buf=>:data}) }
139
+
140
+ it "can successfully send command" do
141
+
142
+ subject.stub(:check_connected) { true }
143
+ subject.should_receive(:send_with_header).with(:data) { true }
144
+ subject.should_receive(:receive_with_header).with(no_args) { :receive_response }
145
+ BackgroundQueue::Command.should_receive(:from_buf).with(:receive_response) { :command_response }
146
+
147
+ subject.send_command(send_command).should eq(:command_response)
148
+ end
149
+
150
+ it "fails if unable to connect" do
151
+ TCPSocket.should_receive(:open).with(:host, :port) { raise "Unable to connect" }
152
+ expect { subject.send_command(send_command) }.to raise_error(BackgroundQueue::ClientLib::ConnectionError, "Error Connecting to host:port: Unable to connect")
153
+ end
154
+
155
+ it "fails if unable to send data" do
156
+ subject.stub(:check_connected) { true }
157
+ subject.should_receive(:send_with_header).with(:data) { raise BackgroundQueue::ClientLib::ConnectionError, "Send Error" }
158
+ expect { subject.send_command(send_command) }.to raise_error(BackgroundQueue::ClientLib::ConnectionError, "Send Error")
159
+
160
+ end
161
+
162
+ it "fails if unable to recieve response" do
163
+ subject.stub(:check_connected) { true }
164
+ subject.should_receive(:send_with_header).with(:data) { true }
165
+ subject.should_receive(:receive_with_header).with(no_args) { raise BackgroundQueue::ClientLib::ConnectionError, "Receive Error" }
166
+ expect { subject.send_command(send_command) }.to raise_error(BackgroundQueue::ClientLib::ConnectionError, "Receive Error")
167
+ end
168
+ end
169
+
170
+ end
@@ -0,0 +1,95 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'background_queue'
3
+
4
+ describe "Client" do
5
+
6
+ context "initializing" do
7
+ it "loads from config path" do
8
+ BackgroundQueue::ClientLib::Config.stub(:load_file).with(:path_that_exists) { BackgroundQueue::ClientLib::Config.new(:a, :b, :c) }
9
+ bq_client = BackgroundQueue::Client.new(:path_that_exists)
10
+ bq_client.config.server.should eq(:a)
11
+ end
12
+ end
13
+
14
+ context "initialized" do
15
+ subject {
16
+ BackgroundQueue::ClientLib::Config.stub(:load_file).with(:path_that_exists) {
17
+ BackgroundQueue::ClientLib::Config.new(:primary_server, [:failover_1, :failover_2], :memcache_server)
18
+ }
19
+ BackgroundQueue::Client.new(:path_that_exists)
20
+ }
21
+
22
+ context "sending a command" do
23
+ it "can send a command to a server" do
24
+ BackgroundQueue::ClientLib::Connection.any_instance.should_receive(:send_command).with(:command) { true }
25
+ subject.__prv__send_command_to_server(:command, :primary_server).should eq([true, :primary_server])
26
+ end
27
+
28
+ it "can succeed first time" do
29
+ subject.should_receive(:send_command_to_server).with(:command, :primary_server) { true }
30
+ subject.__prv__send_command(:command).should eq(true)
31
+ end
32
+
33
+ it "can use failover server if main server fails" do
34
+ subject.should_receive(:send_command_to_server).with(:command, :primary_server) { raise BackgroundQueue::ClientLib::ConnectionError, "Primary" }
35
+ subject.should_receive(:send_command_to_server).with(:command, :failover_1) { true }
36
+ subject.__prv__send_command(:command).should eq(true)
37
+ end
38
+
39
+ it "can use second failover server if needed" do
40
+ subject.should_receive(:send_command_to_server).with(:command, :primary_server) { raise BackgroundQueue::ClientLib::ConnectionError, "Primary" }
41
+ subject.should_receive(:send_command_to_server).with(:command, :failover_1) { raise BackgroundQueue::ClientLib::ConnectionError, "Failure 1" }
42
+ subject.should_receive(:send_command_to_server).with(:command, :failover_2) { true }
43
+ subject.__prv__send_command(:command).should eq(true)
44
+ end
45
+
46
+ it "throws an exception if all connections fail" do
47
+ subject.should_receive(:send_command_to_server).with(:command, :primary_server) { raise BackgroundQueue::ClientLib::ConnectionError, "Primary" }
48
+ subject.should_receive(:send_command_to_server).with(:command, :failover_1) { raise BackgroundQueue::ClientLib::ConnectionError, "Failure 1" }
49
+ subject.should_receive(:send_command_to_server).with(:command, :failover_2) { raise BackgroundQueue::ClientLib::ConnectionError, "Failure 2" }
50
+ expect { subject.__prv__send_command(:command) }.to raise_error(BackgroundQueue::ClientException, "Primary, Attempt 2: Failure 1, Attempt 3: Failure 2")
51
+ end
52
+ end
53
+
54
+ context "single call commands" do
55
+ before do
56
+ subject.should_receive(:send_command).with(any_args) { [true, :server] }
57
+ end
58
+
59
+ context "#add_task" do
60
+ it "can build and send an add task command" do
61
+ job_handle = subject.add_task(:worker, :owner_id, :job_id, :task_id, 1, {}, {} )
62
+ job_handle.owner_id.should eq(:owner_id)
63
+ job_handle.job_id.should eq(:job_id)
64
+ job_handle.server.should eq(:server)
65
+ end
66
+
67
+ it "will dynamically generate a job id/task id if not passed" do
68
+ subject.should_receive(:generate_ids).and_return([:jjj, :ttt])
69
+ job_handle = subject.add_task(:worker, :owner_id, nil, nil, 1, {}, {} )
70
+ job_handle.job_id.should eq(:jjj)
71
+ end
72
+ end
73
+
74
+ it "can build and send an add tasks command" do
75
+ subject.add_tasks(:worker, :owner_id, :job_id, :tasks, 1, {}, {} ).should eq([true, :server])
76
+ end
77
+
78
+
79
+ #it "can build and send a remove task command" do
80
+ # subject.remove_tasks(:tasks, {}).should eq(true)
81
+ #end
82
+
83
+ end
84
+
85
+
86
+ context "#get_status" do
87
+ it "passes the requested server" do
88
+ job_handle = double("jh", :server=>:another_server, :job_id=>:job_id)
89
+ BackgroundQueue::ClientLib::Command.should_receive(:get_status_command).with(:job_id, {} ).and_return(:cmd)
90
+ subject.should_receive(:send_command).with(:cmd, :another_server) { [true, :another_server] }
91
+ subject.get_status(job_handle, {}).should eq(true)
92
+ end
93
+ end
94
+ end
95
+ end