droid 1.0.2pre → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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