gorgon 0.1.1 → 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.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gorgon (0.1.1)
4
+ gorgon (0.2.0)
5
5
  amqp (~> 0.9.7)
6
6
  awesome_print
7
7
  bunny (~> 0.8.0)
@@ -18,12 +18,12 @@ GEM
18
18
  amq-client (0.9.4)
19
19
  amq-protocol (>= 0.9.4)
20
20
  eventmachine
21
- amq-protocol (0.9.4)
21
+ amq-protocol (0.9.5)
22
22
  amqp (0.9.7)
23
23
  amq-client (~> 0.9.4)
24
24
  amq-protocol (>= 0.9.4)
25
25
  eventmachine
26
- awesome_print (1.0.2)
26
+ awesome_print (1.1.0)
27
27
  bunny (0.8.0)
28
28
  colorize (0.5.8)
29
29
  diff-lcs (1.1.3)
data/bin/gorgon CHANGED
@@ -2,6 +2,7 @@ require "rubygems"
2
2
  require 'gorgon/originator'
3
3
  require 'gorgon/listener'
4
4
  require 'gorgon/worker_manager'
5
+ require 'gorgon/ping_service'
5
6
  require 'gorgon/version'
6
7
 
7
8
  WELCOME_MSG = "Welcome to Gorgon #{Gorgon::VERSION}"
@@ -26,10 +27,15 @@ def manage_workers
26
27
  exit
27
28
  end
28
29
 
30
+ def ping_listeners
31
+ PingService.new.ping_listeners
32
+ end
33
+
29
34
  def usage
30
35
  #print instructions on how to use gorgon
31
36
  puts "\tstart - remotely runs all tests specified in gorgon.json"
32
37
  puts "\tlisten - starts a listener process using the settings in gorgon_listener.json"
38
+ puts "\tping - pings listeners and shows hosts and gorgon's version they are running"
33
39
  end
34
40
 
35
41
  puts WELCOME_MSG
@@ -43,6 +49,8 @@ when "listen"
43
49
  listen
44
50
  when "manage_workers"
45
51
  manage_workers
52
+ when "ping"
53
+ ping_listeners
46
54
  when "help"
47
55
  usage
48
56
  else
@@ -0,0 +1,4 @@
1
+ module Colors
2
+ FILENAME = :light_cyan
3
+ HOST = :light_blue
4
+ end
@@ -19,6 +19,6 @@ class JobDefinition
19
19
 
20
20
  #This can probably be done with introspection somehow, but this is way easier despite being very verbose
21
21
  def to_hash
22
- {:file_queue_name => @file_queue_name, :reply_exchange_name => @reply_exchange_name, :source_tree_path => @source_tree_path, :sync_exclude => @sync_exclude, :callbacks => @callbacks}
22
+ {:type => "job_definition", :file_queue_name => @file_queue_name, :reply_exchange_name => @reply_exchange_name, :source_tree_path => @source_tree_path, :sync_exclude => @sync_exclude, :callbacks => @callbacks}
23
23
  end
24
24
  end
@@ -21,7 +21,7 @@ class Listener
21
21
  @listener_config_filename = Dir.pwd + "/gorgon_listener.json"
22
22
  initialize_logger configuration[:log_file]
23
23
 
24
- log "Listener #{Gorgon::VERSION} initialized"
24
+ log "Listener #{Gorgon::VERSION} initializing"
25
25
  connect
26
26
  initialize_personal_job_queue
27
27
  end
@@ -48,16 +48,26 @@ class Listener
48
48
  def poll
49
49
  message = @job_queue.pop
50
50
  return false if message[:payload] == :queue_empty
51
+ log "Received: #{message[:payload]}"
51
52
 
52
- run_job(message[:payload])
53
+ handle_request message[:payload]
53
54
 
54
55
  log "Waiting for more jobs..."
55
56
  return true
56
57
  end
57
58
 
58
- def run_job(json_payload)
59
- log "Job received: #{json_payload}"
59
+ def handle_request json_payload
60
60
  payload = Yajl::Parser.new(:symbolize_keys => true).parse(json_payload)
61
+
62
+ case payload[:type]
63
+ when "job_definition"
64
+ run_job(payload)
65
+ when "ping"
66
+ respong_to_ping payload[:reply_exchange_name]
67
+ end
68
+ end
69
+
70
+ def run_job(payload)
61
71
  @job_definition = JobDefinition.new(payload)
62
72
  @reply_exchange = @bunny.exchange(@job_definition.reply_exchange_name)
63
73
 
@@ -140,6 +150,15 @@ class Listener
140
150
  end
141
151
  end
142
152
 
153
+ def respong_to_ping reply_exchange_name
154
+ reply = {:type => "ping_response", :hostname => Socket.gethostname,
155
+ :version => Gorgon::VERSION}
156
+ reply_exchange = @bunny.exchange(reply_exchange_name, :auto_delete => true)
157
+
158
+ log "Sending #{reply}"
159
+ reply_exchange.publish(Yajl::Encoder.encode(reply))
160
+ end
161
+
143
162
  def connection_information
144
163
  configuration[:connection]
145
164
  end
@@ -123,11 +123,24 @@ class Originator
123
123
  def job_definition
124
124
  job_config = configuration[:job]
125
125
  if !job_config.has_key?(:source_tree_path)
126
- job_config[:source_tree_path] = "#{Etc.getlogin}@#{Socket.gethostname}:#{Dir.pwd}"
126
+ job_config[:source_tree_path] = "#{Etc.getlogin}@#{local_ip_addr}:#{Dir.pwd}"
127
127
  end
128
128
  JobDefinition.new(configuration[:job])
129
129
  end
130
130
 
131
+ private
132
+
133
+ def local_ip_addr
134
+ orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily
135
+
136
+ UDPSocket.open do |s|
137
+ s.connect '64.59.144.16', 1
138
+ s.addr.last
139
+ end
140
+ ensure
141
+ Socket.do_not_reverse_lookup = orig
142
+ end
143
+
131
144
  def configuration
132
145
  @configuration ||= load_configuration_from_file("gorgon.json")
133
146
  end
@@ -16,6 +16,8 @@ class OriginatorProtocol
16
16
  end
17
17
 
18
18
  def publish_files files
19
+ @file_queue = @channel.queue(UUIDTools::UUID.timestamp_create.to_s)
20
+
19
21
  files.each do |file|
20
22
  @channel.default_exchange.publish(file, :routing_key => @file_queue.name)
21
23
  end
@@ -28,6 +30,12 @@ class OriginatorProtocol
28
30
  @channel.fanout("gorgon.jobs").publish(job_definition.to_json)
29
31
  end
30
32
 
33
+ def ping_listeners
34
+ # TODO: we probably want to use a different exchange for pinging when we add more services
35
+ message = {:type => "ping", :reply_exchange_name => @reply_exchange.name}
36
+ @channel.fanout("gorgon.jobs").publish(Yajl::Encoder.encode(message))
37
+ end
38
+
31
39
  def receive_payloads
32
40
  @reply_queue.subscribe do |payload|
33
41
  yield payload
@@ -35,7 +43,7 @@ class OriginatorProtocol
35
43
  end
36
44
 
37
45
  def cancel_job
38
- @file_queue.purge
46
+ @file_queue.purge if @file_queue
39
47
  @channel.fanout("gorgon.worker_managers").publish(cancel_message)
40
48
  @logger.log "Cancel Message sent"
41
49
  end
@@ -51,12 +59,11 @@ class OriginatorProtocol
51
59
  @reply_queue = @channel.queue(UUIDTools::UUID.timestamp_create.to_s)
52
60
  @reply_exchange = @channel.direct(UUIDTools::UUID.timestamp_create.to_s)
53
61
  @reply_queue.bind(@reply_exchange)
54
- @file_queue = @channel.queue(UUIDTools::UUID.timestamp_create.to_s)
55
62
  end
56
63
 
57
64
  def cleanup_queues
58
- @reply_queue.delete
59
- @file_queue.delete
65
+ @reply_queue.delete if @reply_queue
66
+ @file_queue.delete if @file_queue
60
67
  end
61
68
 
62
69
  def cancel_message
@@ -0,0 +1,66 @@
1
+ require 'gorgon/originator_protocol'
2
+ require 'gorgon/configuration'
3
+ require 'gorgon/originator_logger'
4
+ require 'gorgon/colors'
5
+
6
+ require 'colorize'
7
+
8
+ class PingService
9
+ include Configuration
10
+
11
+ TIMEOUT=4
12
+
13
+ def initialize
14
+ @configuration = load_configuration_from_file("gorgon.json")
15
+ @logger = OriginatorLogger.new @configuration[:originator_log_file]
16
+ @protocol = OriginatorProtocol.new @logger
17
+ @listeners = []
18
+ end
19
+
20
+ def ping_listeners
21
+ Signal.trap("INT") { disconnect }
22
+ Signal.trap("TERM") { disconnect }
23
+
24
+ EventMachine.run do
25
+ @logger.log "Connecting..."
26
+ @protocol.connect @configuration[:connection], :on_closed => proc {EM.stop}
27
+
28
+ @logger.log "Pinging Listeners..."
29
+ @protocol.ping_listeners
30
+
31
+ EM.add_timer(TIMEOUT) { disconnect }
32
+
33
+ @protocol.receive_payloads do |payload|
34
+ @logger.log "Received #{payload}"
35
+
36
+ handle_reply(Yajl::Parser.new(:symbolize_keys => true).parse(payload))
37
+ end
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def disconnect
44
+ @protocol.disconnect
45
+ print_summary
46
+ end
47
+
48
+ def handle_reply payload
49
+ if payload[:type] != "ping_response"
50
+ puts "Unexpected message received: #{payload}"
51
+ return
52
+ end
53
+
54
+ @listeners << payload
55
+ hostname = payload[:hostname].colorize(Colors::HOST)
56
+ puts "#{hostname} is running Listener version #{payload[:version]}"
57
+ end
58
+
59
+ def print_summary
60
+ puts "\n#{@listeners.size} host(s) responded."
61
+ end
62
+
63
+ def on_disconnect
64
+ EventMachine.stop
65
+ end
66
+ end
@@ -1,3 +1,5 @@
1
+ require 'gorgon/colors'
2
+
1
3
  require 'ruby-progressbar'
2
4
  require 'colorize'
3
5
 
@@ -6,9 +8,6 @@ LOADING_MSG = "Loading environment and workers..."
6
8
  RUNNING_MSG = "Running files:"
7
9
  LEGEND_MSG = "Legend:\nF - failure files count\nH - number of hosts that have run files\nW - number of workers running files"
8
10
 
9
- FILENAME_COLOR = :light_cyan
10
- HOST_COLOR = :light_blue
11
-
12
11
  class ProgressBarView
13
12
  def initialize job_state
14
13
  @job_state = job_state
@@ -28,7 +27,7 @@ class ProgressBarView
28
27
 
29
28
  failed_files_count = @job_state.failed_files_count
30
29
 
31
- @progress_bar.title="F: #{failed_files_count} H: #{@job_state.total_running_hosts} W: #{@job_state.total_running_workers}"
30
+ @progress_bar.title=" F: #{failed_files_count} H: #{@job_state.total_running_hosts} W: #{@job_state.total_running_workers}"
32
31
  if failed_files_count > 0
33
32
  @progress_bar.format(format(bar: :red, title: :default))
34
33
  end
@@ -57,7 +56,7 @@ private
57
56
  end
58
57
 
59
58
  def output_gorgon_crash_message payload
60
- $stderr.puts "\nA #{'crash'.red} occured at '#{payload[:hostname].colorize HOST_COLOR}':"
59
+ $stderr.puts "\nA #{'crash'.red} occured at '#{payload[:hostname].colorize Colors::HOST}':"
61
60
  $stderr.puts payload[:stdout].yellow unless payload[:stdout].to_s.strip.length == 0
62
61
  $stderr.puts payload[:stderr].yellow unless payload[:stderr].to_s.strip.length == 0
63
62
  if @progress_bar.nil?
@@ -71,7 +70,7 @@ private
71
70
  bar = "%w>%i".colorize(colors[:bar])
72
71
  title = "%t".colorize(colors[:title])
73
72
 
74
- "%e [#{bar}] %c/%C | #{title}"
73
+ "#{title} | [#{bar}] %c/%C %e"
75
74
  end
76
75
 
77
76
  def terminal_size
@@ -87,8 +86,8 @@ private
87
86
  def print_failed_tests
88
87
  @job_state.each_failed_test do |test|
89
88
  puts "\n" + ('*' * 80).magenta #light_red
90
- puts("File '#{test[:filename].colorize(FILENAME_COLOR)}' failed/crashed at " \
91
- + "'#{test[:hostname].colorize(HOST_COLOR)}'\n")
89
+ puts("File '#{test[:filename].colorize(Colors::FILENAME)}' failed/crashed at " \
90
+ + "'#{test[:hostname].colorize(Colors::HOST)}'\n")
92
91
  msg = build_fail_message test[:failures]
93
92
  puts "#{msg}\n"
94
93
  end
@@ -112,8 +111,8 @@ private
112
111
  puts "\n#{title} - The following files were still running:" if @job_state.total_running_workers > 0
113
112
 
114
113
  @job_state.each_running_file do |hostname, filename|
115
- filename_str = filename.dup.colorize(FILENAME_COLOR)
116
- hostname_str = hostname.dup.colorize(HOST_COLOR)
114
+ filename_str = filename.dup.colorize(Colors::FILENAME)
115
+ hostname_str = hostname.dup.colorize(Colors::HOST)
117
116
  puts "\t#{filename_str} at '#{hostname_str}'"
118
117
  end
119
118
  end
@@ -14,6 +14,8 @@ class SourceTreeSyncer
14
14
  end
15
15
 
16
16
  def sync
17
+ return if blank_source_tree_path?
18
+
17
19
  @tempdir = Dir.mktmpdir("gorgon")
18
20
  Dir.chdir(@tempdir)
19
21
 
@@ -34,11 +36,26 @@ class SourceTreeSyncer
34
36
  end
35
37
 
36
38
  def remove_temp_dir
37
- FileUtils::remove_entry_secure(@tempdir)
39
+ FileUtils::remove_entry_secure(@tempdir) if @tempdir
38
40
  end
39
41
 
40
42
  private
41
43
 
44
+ def blank_source_tree_path?
45
+ if @source_tree_path.nil?
46
+ @errors = "Source tree path cannot be nil. Check your gorgon.json file."
47
+ elsif @source_tree_path.strip.empty?
48
+ @errors = "Source tree path cannot be empty. Check your gorgon.json file."
49
+ end
50
+
51
+ if @errors
52
+ @exitstatus = 1
53
+ return true
54
+ else
55
+ return false
56
+ end
57
+ end
58
+
42
59
  def build_exclude_opt
43
60
  return "" if @exclude.nil? or @exclude.empty?
44
61
 
@@ -1,3 +1,3 @@
1
1
  module Gorgon
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/gorgon/worker.rb CHANGED
@@ -32,8 +32,6 @@ class Worker
32
32
  include GLogger
33
33
 
34
34
  def self.build(config)
35
- Signal.trap("INT") { interrupted }
36
-
37
35
  payload = Yajl::Parser.new(:symbolize_keys => true).parse($stdin.read)
38
36
  job_definition = JobDefinition.new(payload)
39
37
 
@@ -77,6 +75,7 @@ class Worker
77
75
  @amqp.start_worker @file_queue_name, @reply_exchange_name do |queue, exchange|
78
76
  while filename = queue.pop
79
77
  exchange.publish make_start_message(filename)
78
+ log "Running '#{filename}'"
80
79
  test_results = run_file(filename)
81
80
  exchange.publish make_finish_message(filename, test_results)
82
81
  end
@@ -103,8 +102,4 @@ class Worker
103
102
  def make_finish_message(filename, results)
104
103
  {:action => :finish, :hostname => Socket.gethostname, :worker_id => @worker_id, :filename => filename}.merge(results)
105
104
  end
106
-
107
- def self.interrupted
108
- exit # to avoid raising "INT" exception
109
- end
110
105
  end
@@ -19,6 +19,8 @@ class WorkerManager
19
19
 
20
20
  def initialize config
21
21
  initialize_logger config[:log_file]
22
+ log "Worker Manager #{Gorgon::VERSION} initializing"
23
+
22
24
  @worker_pids = []
23
25
 
24
26
  @config = config
@@ -115,10 +117,15 @@ class WorkerManager
115
117
  def on_current_job_complete
116
118
  log "Job '#{@job_definition.inspect}' completed"
117
119
 
120
+ stop
121
+ end
122
+
123
+ def stop
118
124
  EventMachine.stop_event_loop
119
125
  @bunny.stop
120
126
  end
121
127
 
128
+ CANCEL_TIMEOUT = 15
122
129
  def subscribe_to_originator_queue
123
130
 
124
131
  originator_watcher = proc do
@@ -138,6 +145,8 @@ class WorkerManager
138
145
  log "Sending 'INT' signal to #{@worker_pids}"
139
146
  Process.kill("INT", *@worker_pids)
140
147
  log "Signal sent"
148
+
149
+ EM.add_timer(CANCEL_TIMEOUT) { stop }
141
150
  else
142
151
  EventMachine.defer(originator_watcher, handle_message)
143
152
  end
@@ -8,8 +8,7 @@ describe JobDefinition do
8
8
 
9
9
  describe "#to_json" do
10
10
  it "should serialize itself to json" do
11
- expected_hash = {:file_queue_name => "string 1", :reply_exchange_name => "string 2",
12
- :source_tree_path => "string 3", :sync_exclude => "string 4", :callbacks => {}}
11
+ expected_hash = {:type => "job_definition", :file_queue_name => "string 1", :reply_exchange_name => "string 2", :source_tree_path => "string 3", :sync_exclude => "string 4", :callbacks => {}}
13
12
 
14
13
  jd = JobDefinition.new(expected_hash)
15
14
 
@@ -43,7 +43,7 @@ describe Listener do
43
43
  end
44
44
 
45
45
  it "should log to 'log_file'" do
46
- logger.should_receive(:info).with("Listener initialized")
46
+ logger.should_receive(:info).with(/Listener.*initializing/)
47
47
 
48
48
  Listener.new
49
49
  end
@@ -98,7 +98,7 @@ describe Listener do
98
98
  describe "#poll" do
99
99
 
100
100
  let(:empty_queue) { {:payload => :queue_empty} }
101
- let(:job_payload) { {:payload => "Job"} }
101
+ let(:job_payload) { {:payload => Yajl::Encoder.encode({:type => "job_definition"}) } }
102
102
  before do
103
103
  listener.stub(:run_job)
104
104
  end
@@ -125,7 +125,7 @@ describe Listener do
125
125
 
126
126
  it "starts a new job when there is a job payload" do
127
127
  queue.should_receive(:pop).and_return(job_payload)
128
- listener.should_receive(:run_job).with(job_payload[:payload])
128
+ listener.should_receive(:run_job).with({:type => "job_definition"})
129
129
  listener.poll
130
130
  end
131
131
 
@@ -133,6 +133,24 @@ describe Listener do
133
133
  listener.poll.should be_true
134
134
  end
135
135
  end
136
+
137
+ context "ping message pending on queue" do
138
+ let(:ping_payload) {{
139
+ :payload => Yajl::Encoder.encode({:type => "ping", :reply_exchange_name => "name"}) }}
140
+
141
+ before do
142
+ queue.stub!(:pop => ping_payload)
143
+ end
144
+
145
+ it "publishes ping_response message with Gorgon's version" do
146
+ listener.should_not_receive(:run_job)
147
+ bunny.should_receive(:exchange).with("name", anything).and_return(exchange)
148
+ response = {:type => "ping_response", :hostname => Socket.gethostname,
149
+ :version => Gorgon::VERSION}
150
+ exchange.should_receive(:publish).with(Yajl::Encoder.encode(response))
151
+ listener.poll
152
+ end
153
+ end
136
154
  end
137
155
 
138
156
  describe "#run_job" do
@@ -153,7 +171,6 @@ describe Listener do
153
171
  before do
154
172
  stub_classes
155
173
  @listener = Listener.new
156
- @json_payload = Yajl::Encoder.encode(payload)
157
174
  end
158
175
 
159
176
  it "copy source tree" do
@@ -161,7 +178,7 @@ describe Listener do
161
178
  syncer.should_receive(:exclude=).with(["log"])
162
179
  syncer.should_receive(:sync)
163
180
  syncer.should_receive(:success?).and_return(true)
164
- @listener.run_job(@json_payload)
181
+ @listener.run_job(payload)
165
182
  end
166
183
 
167
184
  context "syncer#sync fails" do
@@ -173,13 +190,13 @@ describe Listener do
173
190
 
174
191
  it "aborts current job" do
175
192
  callback_handler.should_not_receive(:after_sync)
176
- @listener.run_job(@json_payload)
193
+ @listener.run_job(payload)
177
194
  end
178
195
 
179
196
  it "sends message to originator with output and errors from syncer" do
180
197
  reply = {:type => :crash, :hostname => "hostname", :stdout => "some output", :stderr => "some errors"}
181
198
  exchange.should_receive(:publish).with(Yajl::Encoder.encode(reply))
182
- @listener.run_job(@json_payload)
199
+ @listener.run_job(reply)
183
200
  end
184
201
  end
185
202
 
@@ -193,28 +210,28 @@ describe Listener do
193
210
  stderr.should_receive(:read).and_return "some errors"
194
211
  reply = {:type => :crash, :hostname => "hostname", :stdout => "some output", :stderr => "some errors"}
195
212
  exchange.should_receive(:publish).with(Yajl::Encoder.encode(reply))
196
- @listener.run_job(@json_payload)
213
+ @listener.run_job(reply)
197
214
  end
198
215
  end
199
216
 
200
217
  it "remove temp source directory when complete" do
201
218
  syncer.should_receive(:remove_temp_dir)
202
- @listener.run_job(@json_payload)
219
+ @listener.run_job(payload)
203
220
  end
204
221
 
205
222
  it "creates a CallbackHandler object using callbacks passed in payload" do
206
223
  CallbackHandler.should_receive(:new).once.with({:a_callback => "path/to/callback"}).and_return(callback_handler)
207
- @listener.run_job(@json_payload)
224
+ @listener.run_job(payload)
208
225
  end
209
226
 
210
227
  it "calls after_sync callback" do
211
228
  callback_handler.should_receive(:after_sync).once
212
- @listener.run_job(@json_payload)
229
+ @listener.run_job(payload)
213
230
  end
214
231
 
215
232
  it "uses Bundler#with_clean_env so the workers load new gems that could have been installed in after_sync" do
216
233
  Bundler.should_receive(:with_clean_env).and_yield
217
- @listener.run_job(@json_payload)
234
+ @listener.run_job(payload)
218
235
  end
219
236
  end
220
237
 
@@ -39,7 +39,7 @@ describe OriginatorProtocol do
39
39
 
40
40
  it "opens a reply and exchange queue" do
41
41
  UUIDTools::UUID.stub!(:timestamp_create).and_return 1
42
- channel.should_receive(:queue).twice.with("1")
42
+ channel.should_receive(:queue).once.with("1")
43
43
  @originator_p.connect @conn_information
44
44
  end
45
45
 
@@ -68,6 +68,7 @@ describe OriginatorProtocol do
68
68
  describe "#publish_job" do
69
69
  before do
70
70
  @originator_p.connect @conn_information
71
+ @originator_p.publish_files []
71
72
  end
72
73
 
73
74
  it "add queue's names to job_definition and fanout using 'gorgon.jobs' exchange" do
@@ -81,6 +82,19 @@ describe OriginatorProtocol do
81
82
  end
82
83
  end
83
84
 
85
+ describe "#ping_listeners" do
86
+ before do
87
+ @originator_p.connect @conn_information
88
+ end
89
+
90
+ it "adds reply_exchange_name to ping_messages and fanouts it using 'gorgon.jobs' exchange" do
91
+ expected_msg = {:type => "ping", :reply_exchange_name => "exchange"}
92
+ channel.should_receive(:fanout).once.ordered.with("gorgon.jobs")
93
+ exchange.should_receive(:publish).once.ordered.with(Yajl::Encoder.encode(expected_msg))
94
+ @originator_p.ping_listeners
95
+ end
96
+ end
97
+
84
98
  describe "#receive_payloads" do
85
99
  before do
86
100
  @originator_p.connect @conn_information
@@ -104,6 +118,7 @@ describe OriginatorProtocol do
104
118
  end
105
119
 
106
120
  it "purges file_queue" do
121
+ @originator_p.publish_files ['file1']
107
122
  queue.should_receive(:purge)
108
123
  @originator_p.cancel_job
109
124
  end
@@ -122,6 +137,7 @@ describe OriginatorProtocol do
122
137
  end
123
138
 
124
139
  it "deletes reply and file queue" do
140
+ @originator_p.publish_files []
125
141
  queue.should_receive(:delete).twice
126
142
  @originator_p.disconnect
127
143
  end
@@ -118,7 +118,8 @@ describe Originator do
118
118
 
119
119
  it "builds source_tree_path if it was not specified in the configuration" do
120
120
  @originator.stub!(:configuration).and_return({:job => {}})
121
- @originator.job_definition.source_tree_path.should == "#{Etc.getlogin}@#{Socket.gethostname}:#{Dir.pwd}"
121
+ UDPSocket.any_instance.stub(:addr).and_return(["1.1.1.1"])
122
+ @originator.job_definition.source_tree_path.should == "#{Etc.getlogin}@1.1.1.1:#{Dir.pwd}"
122
123
  end
123
124
 
124
125
  it "returns source_tree_path specified in configuration if it is present" do
@@ -0,0 +1,44 @@
1
+ require 'gorgon/ping_service'
2
+
3
+ describe "PingService" do
4
+ describe "#ping_listeners" do
5
+ let(:configuration){ {:connection => {:host => "host"}, :originator_log_file => "file.log"}}
6
+ let(:protocol) { stub("OriginatorProtocol", :connect => nil, :ping => nil,
7
+ :receive_payloads => nil, :disconnect => nil,
8
+ :ping_listeners => nil)}
9
+ let(:logger){ stub("Originator Logger", :log => nil, :log_message => nil)}
10
+
11
+ before do
12
+ $stdout.stub!(:write)
13
+ PingService.any_instance.stub(:load_configuration_from_file).and_return configuration
14
+ EventMachine.stub!(:run).and_yield
15
+ EM.stub!(:add_timer).and_yield
16
+ OriginatorLogger.stub!(:new).and_return logger
17
+ end
18
+
19
+ it "connnects and calls OriginatorProtocol#ping_listeners" do
20
+ OriginatorProtocol.should_receive(:new).once.ordered.and_return(protocol)
21
+ protocol.should_receive(:connect).once.ordered.with({:host => "host"}, anything)
22
+ protocol.should_receive(:ping_listeners).once.ordered
23
+ PingService.new.ping_listeners
24
+ end
25
+
26
+ context "after sending ping messages" do
27
+ before do
28
+ OriginatorProtocol.stub!(:new).and_return(protocol)
29
+ @service = PingService.new
30
+ end
31
+
32
+ it "adds an Event machine timer" do
33
+ EM.should_receive(:add_timer).and_yield
34
+ @service.ping_listeners
35
+ end
36
+
37
+ it "receives a ping_response message" do
38
+ payload = {:type => "ping_response", :hostname => "host", :version => "1.1.1"}
39
+ protocol.should_receive(:receive_payloads).and_yield Yajl::Encoder.encode(payload)
40
+ @service.ping_listeners
41
+ end
42
+ end
43
+ end
44
+ end
@@ -26,6 +26,24 @@ describe SourceTreeSyncer.new("") do
26
26
  @syncer.sync
27
27
  end
28
28
 
29
+ context "invalid source_tree_path" do
30
+ it "gives error if source_tree_path is empty string" do
31
+ syncer = SourceTreeSyncer.new " "
32
+ Dir.should_not_receive(:mktmpdir)
33
+ syncer.sync
34
+ syncer.success?.should be_false
35
+ syncer.errors.should == "Source tree path cannot be empty. Check your gorgon.json file."
36
+ end
37
+
38
+ it "gives error if source_tree_path is nil" do
39
+ syncer = SourceTreeSyncer.new nil
40
+ Dir.should_not_receive(:mktmpdir)
41
+ syncer.sync
42
+ syncer.success?.should be_false
43
+ syncer.errors.should == "Source tree path cannot be nil. Check your gorgon.json file."
44
+ end
45
+ end
46
+
29
47
  context "options" do
30
48
  it "runs rsync system command with appropriate options" do
31
49
  cmd = /rsync.*-azr .*path\/to\/source\/\ \./
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gorgon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2012-09-24 00:00:00.000000000 Z
16
+ date: 2012-09-26 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: rspec
@@ -211,6 +211,7 @@ files:
211
211
  - lib/gorgon.rb
212
212
  - lib/gorgon/amqp_service.rb
213
213
  - lib/gorgon/callback_handler.rb
214
+ - lib/gorgon/colors.rb
214
215
  - lib/gorgon/configuration.rb
215
216
  - lib/gorgon/failures_printer.rb
216
217
  - lib/gorgon/g_logger.rb
@@ -222,6 +223,7 @@ files:
222
223
  - lib/gorgon/originator.rb
223
224
  - lib/gorgon/originator_logger.rb
224
225
  - lib/gorgon/originator_protocol.rb
226
+ - lib/gorgon/ping_service.rb
225
227
  - lib/gorgon/pipe_manager.rb
226
228
  - lib/gorgon/progress_bar_view.rb
227
229
  - lib/gorgon/source_tree_syncer.rb
@@ -239,6 +241,7 @@ files:
239
241
  - spec/originator_logger_spec.rb
240
242
  - spec/originator_protocol_spec.rb
241
243
  - spec/originator_spec.rb
244
+ - spec/ping_service_spec.rb
242
245
  - spec/progress_bar_view_spec.rb
243
246
  - spec/source_tree_syncer_spec.rb
244
247
  - spec/worker_manager_spec.rb