droid 1.0.2pre → 1.0.2

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.
@@ -2,112 +2,112 @@ require 'socket'
2
2
  require 'digest/md5'
3
3
 
4
4
  class Droid
5
- DEFAULT_TTL = 300
5
+ DEFAULT_TTL = 300
6
6
 
7
- class BadPayload < RuntimeError; end
8
-
9
- module Utils
10
- def self.parse_message(raw)
11
- return { } unless raw
12
- JSON.parse(raw)
13
- end
14
-
15
- def self.parse_custom_headers(headers)
16
- return { } unless headers
17
-
18
- h = headers.dup
19
-
20
- h[:published_on] = h[:published_on].to_i
21
-
22
- h[:ttl] = h[:ttl].to_i rescue -1
23
- h[:ttl] = -1 if h[:ttl] == 0
24
-
25
- h
26
- end
27
-
28
- def self.create_event_hash
29
- s = Time.now.to_s + self.object_id.to_s + rand(100).to_s
30
- 'd' + Digest::MD5.hexdigest(s)
31
- end
32
-
33
- def self.extract_custom_headers(hash, opts={}, popts={})
34
- popts[:headers] ||= {}
35
- headers = popts[:headers]
36
-
37
- headers[:published_on] ||= hash.delete('published_on') || opts[:published_on] || Time.now.getgm.to_i
38
- headers[:ttl] ||= hash.delete('ttl') || (opts[:ttl] || Droid::DEFAULT_TTL).to_i
39
- headers[:reply_to] ||= opts[:reply_to] if opts[:reply_to]
40
-
41
- # this is the event hash that gets transferred through various publish/reply actions
42
- headers[:event_hash] ||= hash.delete('event_hash') || opts[:event_hash] || create_event_hash
43
-
44
- # this value should be unique for each published/received message pair
45
- headers[:message_id] ||= create_event_hash
46
-
47
- # some strange behavior with integers makes it better to
48
- # convert all amqp headers to strings to avoid any problems
49
- headers.each { |k,v| headers[k] = v.to_s }
50
-
51
- [hash, headers]
52
- end
53
-
54
- def self.format_publish(data, opts={}, popts={})
55
- raise Droid::BadPayload unless data.is_a?(Hash)
56
-
57
- hash, headers = extract_custom_headers(data, opts, popts)
58
-
59
- popts[:content_type] ||= 'application/json'
60
-
61
- [hash.to_json, popts]
62
- end
63
-
64
- def self.generate_queue(exchange_name, second_name=nil)
65
- second_name ||= $$
66
- "#{generate_name_for_instance(exchange_name)}.#{second_name}"
67
- end
68
-
69
- def self.generate_name_for_instance(name)
70
- "#{name}.#{Socket.gethostname}"
71
- end
72
-
73
- def self.generate_reply_to(name)
74
- "temp.reply.#{name}.#{self.generate_sym}"
75
- end
76
-
77
- def self.generate_sym
78
- values = [
79
- rand(0x0010000),
80
- rand(0x0010000),
81
- rand(0x0010000),
82
- rand(0x0010000),
83
- rand(0x0010000),
84
- rand(0x1000000),
85
- rand(0x1000000),
86
- ]
87
- "%04x%04x%04x%04x%04x%06x%06x" % values
88
- end
89
-
90
- def self.data_summary(json)
91
- return '-> (empty)' if json.empty?
92
- summary = json.map do |k,v|
93
- v = v.to_s
94
- v = v[0..37] + '...' if v.size > 40
95
- "#{k}=#{v}"
96
- end.join(', ')
97
- "-> #{summary}"
98
- end
99
-
100
- def self.format_data_summary(data, headers)
101
- "(data) " + Droid::Utils.data_summary(data) + " (headers) " + Droid::Utils.data_summary(headers)
102
- end
103
- end
104
-
105
- # Need this to be backwards compatible
106
- def self.gen_queue(droid, name)
107
- dn = droid
108
- dn = dn.name if dn.respond_to?(:name)
109
- dn ||= "d"
110
- dn = dn.gsub(" ", "")
111
- Droid::Utils.generate_queue(name, droid)
112
- end
7
+ class BadPayload < RuntimeError; end
8
+
9
+ module Utils
10
+ def self.parse_message(raw)
11
+ return { } unless raw
12
+ JSON.parse(raw)
13
+ end
14
+
15
+ def self.parse_custom_headers(headers)
16
+ return { } unless headers
17
+
18
+ h = headers.dup
19
+
20
+ h[:published_on] = h[:published_on].to_i
21
+
22
+ h[:ttl] = h[:ttl].to_i rescue -1
23
+ h[:ttl] = -1 if h[:ttl] == 0
24
+
25
+ h
26
+ end
27
+
28
+ def self.create_event_hash
29
+ s = Time.now.to_s + self.object_id.to_s + rand(100).to_s
30
+ 'd' + Digest::MD5.hexdigest(s)
31
+ end
32
+
33
+ def self.extract_custom_headers(hash, opts={}, popts={})
34
+ popts[:headers] ||= {}
35
+ headers = popts[:headers]
36
+
37
+ headers[:published_on] ||= hash.delete('published_on') || opts[:published_on] || Time.now.getgm.to_i
38
+ headers[:ttl] ||= hash.delete('ttl') || (opts[:ttl] || Droid::DEFAULT_TTL).to_i
39
+ headers[:reply_to] ||= opts[:reply_to] if opts[:reply_to]
40
+
41
+ # this is the event hash that gets transferred through various publish/reply actions
42
+ headers[:event_hash] ||= hash.delete('event_hash') || opts[:event_hash] || create_event_hash
43
+
44
+ # this value should be unique for each published/received message pair
45
+ headers[:message_id] ||= create_event_hash
46
+
47
+ # some strange behavior with integers makes it better to
48
+ # convert all amqp headers to strings to avoid any problems
49
+ headers.each { |k,v| headers[k] = v.to_s }
50
+
51
+ [hash, headers]
52
+ end
53
+
54
+ def self.format_publish(data, opts={}, popts={})
55
+ raise Droid::BadPayload unless data.is_a?(Hash)
56
+
57
+ hash, headers = extract_custom_headers(data, opts, popts)
58
+
59
+ popts[:content_type] ||= 'application/json'
60
+
61
+ [hash.to_json, popts]
62
+ end
63
+
64
+ def self.generate_queue(exchange_name, second_name=nil)
65
+ second_name ||= $$
66
+ "#{generate_name_for_instance(exchange_name)}.#{second_name}"
67
+ end
68
+
69
+ def self.generate_name_for_instance(name)
70
+ "#{name}.#{Socket.gethostname}"
71
+ end
72
+
73
+ def self.generate_reply_to(name)
74
+ "temp.reply.#{name}.#{self.generate_sym}"
75
+ end
76
+
77
+ def self.generate_sym
78
+ values = [
79
+ rand(0x0010000),
80
+ rand(0x0010000),
81
+ rand(0x0010000),
82
+ rand(0x0010000),
83
+ rand(0x0010000),
84
+ rand(0x1000000),
85
+ rand(0x1000000),
86
+ ]
87
+ "%04x%04x%04x%04x%04x%06x%06x" % values
88
+ end
89
+
90
+ def self.data_summary(json)
91
+ return '-> (empty)' if json.empty?
92
+ summary = json.map do |k,v|
93
+ v = v.to_s
94
+ v = v[0..37] + '...' if v.size > 40
95
+ "#{k}=#{v}"
96
+ end.join(', ')
97
+ "-> #{summary}"
98
+ end
99
+
100
+ def self.format_data_summary(data, headers)
101
+ "(data) " + Droid::Utils.data_summary(data) + " (headers) " + Droid::Utils.data_summary(headers)
102
+ end
103
+ end
104
+
105
+ # Need this to be backwards compatible
106
+ def self.gen_queue(droid, name)
107
+ dn = droid
108
+ dn = dn.name if dn.respond_to?(:name)
109
+ dn ||= "d"
110
+ dn = dn.gsub(" ", "")
111
+ Droid::Utils.generate_queue(name, droid)
112
+ end
113
113
  end
@@ -1,27 +1,27 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'AMQP Publish' do
4
- before do
5
- @json, @publish_opts = Droid::Utils.format_publish({:x => 1, :y => 2}, {}, {})
6
- Droid::Utils.stubs(:format_publish).with({:x => 1, :y => 2}, {}, {}).returns([@json, @publish_opts])
7
- end
4
+ before do
5
+ @json, @publish_opts = Droid::Utils.format_publish({:x => 1, :y => 2}, {}, {})
6
+ Droid::Utils.stubs(:format_publish).with({:x => 1, :y => 2}, {}, {}).returns([@json, @publish_opts])
7
+ end
8
8
 
9
- it "publishes a message to a queue" do
10
- @q = mock('queue')
11
- ::MQ.expects(:queue).with('topic').returns(@q)
12
- @q.expects(:publish).with(@json, @publish_opts)
13
- Droid.publish_to_q('topic', :x => 1, :y => 2)
14
- end
9
+ it "publishes a message to a queue" do
10
+ @q = mock('queue')
11
+ ::MQ.expects(:queue).with('topic').returns(@q)
12
+ @q.expects(:publish).with(@json, @publish_opts)
13
+ Droid.publish_to_q('topic', :x => 1, :y => 2)
14
+ end
15
15
 
16
- it "publishes a message to an exchange" do
17
- @ex = mock('exchange')
18
- ::MQ.expects(:direct).with('topic').returns(@ex)
19
- @ex.expects(:publish).with(@json, @publish_opts)
20
- Droid.publish_to_ex('topic', :x => 1, :y => 2)
21
- end
16
+ it "publishes a message to an exchange" do
17
+ @ex = mock('exchange')
18
+ ::MQ.expects(:direct).with('topic').returns(@ex)
19
+ @ex.expects(:publish).with(@json, @publish_opts)
20
+ Droid.publish_to_ex('topic', :x => 1, :y => 2)
21
+ end
22
22
 
23
- it "by default publishes to an exchange" do
24
- Droid.expects(:publish_to_ex).with('topic', {:x => 1, :y => 2}, {}, {})
25
- Droid.publish('topic', :x => 1, :y => 2)
26
- end
23
+ it "by default publishes to an exchange" do
24
+ Droid.expects(:publish_to_ex).with('topic', {:x => 1, :y => 2}, {}, {})
25
+ Droid.publish('topic', :x => 1, :y => 2)
26
+ end
27
27
  end
@@ -1,47 +1,47 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'Request' do
4
- before do
5
- @mq = mock("MQ")
6
- @exchange = mock("MQ Exchange")
7
- @queue = mock("MQ Queue")
8
-
9
- @qobj = mock("Droid::BasicQueue Instance")
10
- @qobj.stubs(:q).returns(@queue)
11
- @qobj.stubs(:mq).returns(@mq)
12
- @qobj.stubs(:ex).returns(@exchange)
13
-
14
- @header = mock("amqp header", :headers => {})
15
-
16
- @raw_message = '{"x":123,"y":"abc"}'
17
-
18
- @res = Droid::Request.new(@qobj, @header, @raw_message)
19
- end
20
-
21
- it "allows access to response via symbols or strings in array access" do
22
- @res['x'].should == 123
23
- @res[:x].should == 123
24
- @res['y'].should == 'abc'
25
- @res[:y].should == 'abc'
26
- end
27
-
28
- it "calls ack on the header" do
29
- @header.expects(:ack)
30
- @res.ack
31
- end
32
-
33
- it "calls q on the qobj" do
34
- @qobj.expects(:q)
35
- @res.q
36
- end
37
-
38
- it "calls ex on the qobj" do
39
- @qobj.expects(:ex)
40
- @res.ex
41
- end
42
-
43
- it "calls mq on the qobj" do
44
- @qobj.expects(:mq)
45
- @res.mq
46
- end
4
+ before do
5
+ @mq = mock("MQ")
6
+ @exchange = mock("MQ Exchange")
7
+ @queue = mock("MQ Queue")
8
+
9
+ @qobj = mock("Droid::BasicQueue Instance")
10
+ @qobj.stubs(:q).returns(@queue)
11
+ @qobj.stubs(:mq).returns(@mq)
12
+ @qobj.stubs(:ex).returns(@exchange)
13
+
14
+ @header = mock("amqp header", :headers => {})
15
+
16
+ @raw_message = '{"x":123,"y":"abc"}'
17
+
18
+ @res = Droid::Request.new(@qobj, @header, @raw_message)
19
+ end
20
+
21
+ it "allows access to response via symbols or strings in array access" do
22
+ @res['x'].should == 123
23
+ @res[:x].should == 123
24
+ @res['y'].should == 'abc'
25
+ @res[:y].should == 'abc'
26
+ end
27
+
28
+ it "calls ack on the header" do
29
+ @header.expects(:ack)
30
+ @res.ack
31
+ end
32
+
33
+ it "calls q on the qobj" do
34
+ @qobj.expects(:q)
35
+ @res.q
36
+ end
37
+
38
+ it "calls ex on the qobj" do
39
+ @qobj.expects(:ex)
40
+ @res.ex
41
+ end
42
+
43
+ it "calls mq on the qobj" do
44
+ @qobj.expects(:mq)
45
+ @res.mq
46
+ end
47
47
  end
@@ -1,43 +1,43 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'Utils' do
4
- before do
5
- end
6
-
7
- it "parses a json message" do
8
- Droid::Utils.parse_message('{"x":1,"y":2}').should == {'x' => 1, 'y' => 2}
9
- end
10
-
11
- it "parses custom headers and force integers on a few values" do
12
- headers = {
13
- :x => '1',
14
- :y => '2',
15
- :reply_to => 'q.random.reply',
16
- :published_on => '12345',
17
- :event_hash => 'x123'
18
- }
19
-
20
- h = Droid::Utils.parse_custom_headers(headers)
21
-
22
- h.size.should == 6
23
- h[:ttl].should == -1
24
- h[:reply_to].should == 'q.random.reply'
25
- h[:published_on].should == 12345
26
- h[:event_hash].should == 'x123'
27
- end
28
-
29
- it "raises an exception if the data to format for publish is not a hash" do
30
- lambda { Droid::Utils.format_publish('bad payload') }.should.raise Droid::BadPayload
31
- end
32
-
33
- it "generates a name for the instance" do
34
- Socket.stubs(:gethostname).returns('deepblue.123')
35
- Droid::Utils.generate_name_for_instance('woo').should == 'woo.deepblue.123'
36
- end
37
-
38
- it "generates queue name, really more like a generic identifier" do
39
- Socket.stubs(:gethostname).returns('deepblue.123')
40
- Droid::Utils.generate_queue('topic').should == "topic.deepblue.123.#{$$}"
41
- Droid::Utils.generate_queue('topic', 'local').should == "topic.deepblue.123.local"
42
- end
4
+ before do
5
+ end
6
+
7
+ it "parses a json message" do
8
+ Droid::Utils.parse_message('{"x":1,"y":2}').should == {'x' => 1, 'y' => 2}
9
+ end
10
+
11
+ it "parses custom headers and force integers on a few values" do
12
+ headers = {
13
+ :x => '1',
14
+ :y => '2',
15
+ :reply_to => 'q.random.reply',
16
+ :published_on => '12345',
17
+ :event_hash => 'x123'
18
+ }
19
+
20
+ h = Droid::Utils.parse_custom_headers(headers)
21
+
22
+ h.size.should == 6
23
+ h[:ttl].should == -1
24
+ h[:reply_to].should == 'q.random.reply'
25
+ h[:published_on].should == 12345
26
+ h[:event_hash].should == 'x123'
27
+ end
28
+
29
+ it "raises an exception if the data to format for publish is not a hash" do
30
+ lambda { Droid::Utils.format_publish('bad payload') }.should.raise Droid::BadPayload
31
+ end
32
+
33
+ it "generates a name for the instance" do
34
+ Socket.stubs(:gethostname).returns('deepblue.123')
35
+ Droid::Utils.generate_name_for_instance('woo').should == 'woo.deepblue.123'
36
+ end
37
+
38
+ it "generates queue name, really more like a generic identifier" do
39
+ Socket.stubs(:gethostname).returns('deepblue.123')
40
+ Droid::Utils.generate_queue('topic').should == "topic.deepblue.123.#{$$}"
41
+ Droid::Utils.generate_queue('topic', 'local').should == "topic.deepblue.123.local"
42
+ end
43
43
  end
@@ -1,16 +1,16 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  Thread.new do
4
- sleep 2
5
- TCPServer.new('localhost', 20_001).accept.close
4
+ sleep 2
5
+ TCPServer.new('localhost', 20_001).accept.close
6
6
  end
7
7
 
8
8
  describe 'Connectivity' do
9
- it "waits for the rabbitmq server to come up before opening the amqp connection" do
10
- start = Time.now
11
- Droid.wait_for_tcp_port('localhost', 20_001)
12
- finish = Time.now
13
- (finish - start).should > 1
14
- (finish - start).should < 3
15
- end
9
+ it "waits for the rabbitmq server to come up before opening the amqp connection" do
10
+ start = Time.now
11
+ Droid.wait_for_tcp_port('localhost', 20_001)
12
+ finish = Time.now
13
+ (finish - start).should > 1
14
+ (finish - start).should < 3
15
+ end
16
16
  end