agent_zmq 0.5.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c1810d095c41ef4752fbde11dfcdd2cc1b156c7a
4
+ data.tar.gz: b95f4154d6e47fabd960273cf02fb1f8e0997785
5
+ SHA512:
6
+ metadata.gz: 7f9b59119a7a03c1a998fb39545f33ffa6d36aa9ec9d4fd0f9ecbc38dea42f58dc3491516e7066d3cd46fab0b988130efb924f087134f3a16f50e219c104abcb
7
+ data.tar.gz: 7922703be2d5ac0b9267dbdffe5ae62581263745aa2fc1b866f0796677e0510235f03fa90ed94412e2fac5471969a1cf071d5b5364d63df6ad024c2450b6c823
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,6 @@
1
+ before_install: sudo apt-get install libzmq3-dev
2
+ language: ruby
3
+ rvm:
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - 2.0.0
@@ -0,0 +1,22 @@
1
+ If you come across any issues, please [tell us](https://github.com/connamara/agent_zmq/issues).
2
+ Pull requests (with tests) are appreciated. No pull request is too small. Please help with:
3
+
4
+ * Reporting bugs
5
+ * Suggesting features
6
+ * Writing or improving documentation
7
+ * Fixing typos
8
+ * Cleaning whitespace
9
+ * Refactoring code
10
+ * Adding tests
11
+ * Closing [issues](https://github.com/connamara/agent_zmq/issues)
12
+
13
+ Contributing to agent_zmq:
14
+
15
+ 1. Fork the [official repository](https://github.com/connamara/agent_zmq/tree/master).
16
+ 2. Make your changes in a topic branch.
17
+ 3. Send a pull request.
18
+
19
+ Notes:
20
+ * If you report a bug and don't include a fix, please include a failing test.
21
+ * Contributions without tests won't be accepted.
22
+ * Please don't update the Gem version
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'ffi-rzmq', "~> 0.9.3"
4
+ gem "rspec", "~> 2.14"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "jeweler", "~> 1.8"
10
+ gem "cucumber", "~> 1.3"
11
+ gem "rake", "~> 10.1"
12
+ end
@@ -0,0 +1,76 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ addressable (2.3.5)
5
+ builder (3.2.2)
6
+ cucumber (1.3.6)
7
+ builder (>= 2.1.2)
8
+ diff-lcs (>= 1.1.3)
9
+ gherkin (~> 2.12.0)
10
+ multi_json (~> 1.7.5)
11
+ multi_test (>= 0.0.2)
12
+ diff-lcs (1.2.4)
13
+ faraday (0.8.8)
14
+ multipart-post (~> 1.2.0)
15
+ ffi (1.9.0)
16
+ ffi-rzmq (0.9.7)
17
+ ffi
18
+ gherkin (2.12.1)
19
+ multi_json (~> 1.3)
20
+ git (1.2.6)
21
+ github_api (0.10.1)
22
+ addressable
23
+ faraday (~> 0.8.1)
24
+ hashie (>= 1.2)
25
+ multi_json (~> 1.4)
26
+ nokogiri (~> 1.5.2)
27
+ oauth2
28
+ hashie (2.0.5)
29
+ highline (1.6.19)
30
+ httpauth (0.2.0)
31
+ jeweler (1.8.7)
32
+ builder
33
+ bundler (~> 1.0)
34
+ git (>= 1.2.5)
35
+ github_api (= 0.10.1)
36
+ highline (>= 1.6.15)
37
+ nokogiri (= 1.5.10)
38
+ rake
39
+ rdoc
40
+ json (1.8.0)
41
+ jwt (0.1.8)
42
+ multi_json (>= 1.5)
43
+ multi_json (1.7.9)
44
+ multi_test (0.0.2)
45
+ multi_xml (0.5.5)
46
+ multipart-post (1.2.0)
47
+ nokogiri (1.5.10)
48
+ oauth2 (0.9.2)
49
+ faraday (~> 0.8)
50
+ httpauth (~> 0.2)
51
+ jwt (~> 0.1.4)
52
+ multi_json (~> 1.0)
53
+ multi_xml (~> 0.5)
54
+ rack (~> 1.2)
55
+ rack (1.5.2)
56
+ rake (10.1.0)
57
+ rdoc (4.0.1)
58
+ json (~> 1.4)
59
+ rspec (2.14.1)
60
+ rspec-core (~> 2.14.0)
61
+ rspec-expectations (~> 2.14.0)
62
+ rspec-mocks (~> 2.14.0)
63
+ rspec-core (2.14.5)
64
+ rspec-expectations (2.14.2)
65
+ diff-lcs (>= 1.1.3, < 2.0)
66
+ rspec-mocks (2.14.3)
67
+
68
+ PLATFORMS
69
+ ruby
70
+
71
+ DEPENDENCIES
72
+ cucumber (~> 1.3)
73
+ ffi-rzmq (~> 0.9.3)
74
+ jeweler (~> 1.8)
75
+ rake (~> 10.1)
76
+ rspec (~> 2.14)
@@ -0,0 +1,14 @@
1
+ Copyright (C) 2013 Connamara Systems, llc
2
+
3
+ This program is free software: you can redistribute it and/or modify
4
+ it under the terms of the GNU General Public License as published by
5
+ the Free Software Foundation, either version 3 of the License, or
6
+ (at your option) any later version.
7
+
8
+ This program is distributed in the hope that it will be useful,
9
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ GNU General Public License for more details.
12
+
13
+ You should have received a copy of the GNU General Public License
14
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -0,0 +1,182 @@
1
+ agent\_zmq [![Build Status](https://travis-ci.org/connamara/agent_zmq.png?branch=master)](https://travis-ci.org/connamara/agent_zmq)
2
+ ============
3
+
4
+ Agent framework designed for testing [ZeroMQ](http://zeromq.org/) Applications
5
+
6
+ Usage
7
+ -----
8
+
9
+
10
+ ### Agent Types
11
+
12
+ The agent types correspond to underlying ZMQ Socket type under test
13
+
14
+ #### ZMQ\_SUB
15
+
16
+ * Connects or Binds to local address
17
+ * Includes message caching for inspection
18
+
19
+ #### ZMQ\_PUB
20
+
21
+ * Connects or Binds to local address
22
+ * Publishes
23
+
24
+ #### ZMQ\_REQ
25
+
26
+ * Connects or Binds to local address
27
+ * Publishes request, returns response
28
+
29
+ #### ZMQ\_REP
30
+
31
+ * Connects or Binds to local address
32
+ * Listens for request, sends response
33
+
34
+
35
+ ### Configuration
36
+
37
+ Inside of your project, declare your agents inside of ```config/zmq_agents.rb``` like this:
38
+
39
+ ```ruby
40
+ require 'agent_zmq'
41
+
42
+ AgentZMQ.define_ZMQ_SUB :my_sub_agent do |a|
43
+ a.socket_opts << {ZMQ::SUBSCRIBE=>'com.connamara.BODPosition'}
44
+ a.end_point_type=:bind
45
+ a.end_point='tcp://*:5556'
46
+ end
47
+
48
+ AgentZMQ.define_ZMQ_PUB :my_pub_agent do |a|
49
+ a.end_point_type=:connect
50
+ a.end_point='tcp://127.0.0.1:5558'
51
+ end
52
+
53
+ AgentZMQ.define_ZMQ_REQ :my_req_agent do |a|
54
+ a.end_point_type=:connect
55
+ a.end_point='tcp://127.0.0.1:5552'
56
+ end
57
+
58
+ AgentZMQ.define_ZMQ_REP :my_rep_agent do |a|
59
+ a.reply = Proc.new {|msg| "ok"}
60
+ a.end_point_type=:bind
61
+ a.end_point='tcp://*:5552'
62
+ end
63
+ ```
64
+
65
+ ### Starting, Stopping and Resetting
66
+
67
+ ```ruby
68
+ require 'agent_zmq'
69
+ AgentZMQ.start
70
+ at_exit { AgentZMQ.stop }
71
+ ```
72
+
73
+ You may want to reset the agent states between tests without stopping and starting. This may be done with ```AgentZMQ.reset```
74
+
75
+ ### Getting your agent
76
+
77
+ Grab the agent by the name given in the config file
78
+
79
+ ```ruby
80
+ my_agent = AgentZMQ.agents_hash[:my_sub_agent]
81
+ ```
82
+
83
+ ### Agent Interfaces
84
+
85
+
86
+ #### ZMQ\_SUB
87
+
88
+ This agent provides a message cache
89
+
90
+ ```ruby
91
+ all_messages_received = my_sub_agent.messages_received
92
+
93
+ # returns and removes the last message received from the cache
94
+ last_message_received = my_sub_agent.pop
95
+ ```
96
+
97
+ On `reset`, the sub agent cache is cleared
98
+
99
+ #### ZMQ\_PUB
100
+
101
+ The ```publish``` method takes a single message of one or more parts
102
+
103
+ ```ruby
104
+ my_pub_agent.publish "single part message"
105
+ my_pub_agent.publish ["part 1", "part 2"]
106
+ ```
107
+
108
+ #### ZMQ\_REQ
109
+
110
+ The ```publish``` method takes a single message of one or more parts. The agent blocks until a response is received and returned as an array of message parts
111
+
112
+ ```ruby
113
+ response = my_req_agent.publish "single part message"
114
+ response = my_pub_agent.publish ["part 1", "part 2"]
115
+ ```
116
+
117
+ #### ZMQ\_REP
118
+
119
+ Like the ZMQ_SUB agent, ZMQ_REP provides a message cache
120
+
121
+ ```ruby
122
+ all_messages_received = my_rep_agent.messages_received
123
+
124
+ # returns and removes the last message received from the cache
125
+ last_message_received = my_rep_agent.pop
126
+ ```
127
+
128
+ When receiving requests, the agent will reply with the output of the ```reply``` Proc. The return value of this proc may be in the form of a multi-part message.
129
+
130
+ ### Cucumber
131
+
132
+ There is some support for cucumber. See [features](https://github.com/connamara/agent_zmq/blob/master/features) for example usage.
133
+
134
+ ### More
135
+
136
+ Check out [specs](https://github.com/connamara/agent_zmq/blob/master/spec) and [features](https://github.com/connamara/agent_zmq/blob/master/features) to see all the ways you can use agent_zmq.
137
+
138
+ Install
139
+ -------
140
+
141
+ ```shell
142
+ gem install agent_zmq
143
+ ```
144
+
145
+ or add the following to Gemfile:
146
+ ```ruby
147
+ gem 'agent_zmq'
148
+ ```
149
+ and run `bundle install` from your shell.
150
+
151
+ More Information
152
+ ----------------
153
+
154
+ * [Rubygems](https://rubygems.org/gems/agent_zmq)
155
+ * [Issues](https://github.com/connamara/agent_zmq/issues)
156
+ * [Connamara Systems](http://connamara.com)
157
+
158
+ Contributing
159
+ ------------
160
+
161
+ Please see the [contribution guidelines](https://github.com/connamara/agent_zmq/blob/master/CONTRIBUTION_GUIDELINES.md).
162
+
163
+ Credits
164
+ -------
165
+
166
+ Contributers:
167
+
168
+ * Chris Busbey
169
+ * Brad Haan
170
+
171
+ ![Connamara Systems](http://www.connamara.com/images/home-connamara-logo-lg.png)
172
+
173
+ agent_zmq is maintained and funded by [Connamara Systems, llc](http://connamara.com).
174
+
175
+ The names and logos for Connamara Systems are trademarks of Connamara Systems, llc.
176
+
177
+ Licensing
178
+ ---------
179
+
180
+ agent_zmq is Copyright © 2013 Connamara Systems, llc.
181
+
182
+ This software is available under the GPL and a commercial license. Please see the [LICENSE](https://github.com/connamara/agent_zmq/blob/master/LICENSE.txt) file for the terms specified by the GPL license. The commercial license offers more flexible licensing terms compared to the GPL, and includes support services. [Contact us](mailto:info@connamara.com) for more information on the Connamara commercial license, what it enables, and how you can start developing with it.
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+
13
+ require 'rspec/core/rake_task'
14
+ require 'cucumber/rake/task'
15
+
16
+ RSpec::Core::RakeTask.new(:spec)
17
+ Cucumber::Rake::Task.new(:cucumber)
18
+
19
+ task :test => [:spec, :cucumber]
20
+ task :default => :test
21
+
22
+
23
+ require 'jeweler'
24
+ Jeweler::Tasks.new do |gem|
25
+ gem.name = "agent_zmq"
26
+ gem.homepage = "https://github.com/connamara/agent_zmq"
27
+ gem.license = "GPL"
28
+ gem.summary = %Q{Acceptance test framework for ZeroMQ applications}
29
+ gem.description = %Q{Acceptance test framework for ZeroMQ applications. Includes some cucumber helpers.}
30
+ gem.email = "info@connamara.com"
31
+ gem.authors = ["Chris Busbey"]
32
+ # dependencies defined in Gemfile
33
+ end
34
+
35
+ Jeweler::RubygemsDotOrgTasks.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.0
@@ -0,0 +1,78 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "agent_zmq"
8
+ s.version = "0.5.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Chris Busbey"]
12
+ s.date = "2013-08-29"
13
+ s.description = "Acceptance test framework for ZeroMQ applications. Includes some cucumber helpers."
14
+ s.email = "info@connamara.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ ".travis.yml",
23
+ "CONTRIBUTION_GUIDELINES.md",
24
+ "Gemfile",
25
+ "Gemfile.lock",
26
+ "LICENSE.txt",
27
+ "README.md",
28
+ "Rakefile",
29
+ "VERSION",
30
+ "agent_zmq.gemspec",
31
+ "config/zmq_agents.rb",
32
+ "features/MessageInspection.feature",
33
+ "features/step_definitions/steps.rb",
34
+ "features/support/env.rb",
35
+ "lib/agent_zmq.rb",
36
+ "lib/agent_zmq/agent.rb",
37
+ "lib/agent_zmq/agents/base_agent.rb",
38
+ "lib/agent_zmq/agents/pub_agent.rb",
39
+ "lib/agent_zmq/agents/rep_agent.rb",
40
+ "lib/agent_zmq/agents/req_agent.rb",
41
+ "lib/agent_zmq/agents/sub_agent.rb",
42
+ "lib/agent_zmq/cucumber.rb",
43
+ "lib/agent_zmq/helpers.rb",
44
+ "lib/agent_zmq/message_cache.rb",
45
+ "spec/agent_zmq/message_cache_spec.rb",
46
+ "spec/spec_helper.rb"
47
+ ]
48
+ s.homepage = "https://github.com/connamara/agent_zmq"
49
+ s.licenses = ["GPL"]
50
+ s.require_paths = ["lib"]
51
+ s.rubygems_version = "2.0.7"
52
+ s.summary = "Acceptance test framework for ZeroMQ applications"
53
+
54
+ if s.respond_to? :specification_version then
55
+ s.specification_version = 4
56
+
57
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
58
+ s.add_runtime_dependency(%q<ffi-rzmq>, ["~> 0.9.3"])
59
+ s.add_runtime_dependency(%q<rspec>, ["~> 2.14"])
60
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8"])
61
+ s.add_development_dependency(%q<cucumber>, ["~> 1.3"])
62
+ s.add_development_dependency(%q<rake>, ["~> 10.1"])
63
+ else
64
+ s.add_dependency(%q<ffi-rzmq>, ["~> 0.9.3"])
65
+ s.add_dependency(%q<rspec>, ["~> 2.14"])
66
+ s.add_dependency(%q<jeweler>, ["~> 1.8"])
67
+ s.add_dependency(%q<cucumber>, ["~> 1.3"])
68
+ s.add_dependency(%q<rake>, ["~> 10.1"])
69
+ end
70
+ else
71
+ s.add_dependency(%q<ffi-rzmq>, ["~> 0.9.3"])
72
+ s.add_dependency(%q<rspec>, ["~> 2.14"])
73
+ s.add_dependency(%q<jeweler>, ["~> 1.8"])
74
+ s.add_dependency(%q<cucumber>, ["~> 1.3"])
75
+ s.add_dependency(%q<rake>, ["~> 10.1"])
76
+ end
77
+ end
78
+
@@ -0,0 +1,14 @@
1
+ AgentZMQ.define_ZMQ_SUB :my_subscriber do |a|
2
+ a.socket_opts << {ZMQ::SUBSCRIBE=>""}
3
+
4
+ a.end_point_type=:connect
5
+ a.end_point='tcp://127.0.0.1:5560'
6
+ end
7
+
8
+ AgentZMQ.define_ZMQ_PUB :my_publisher do |a|
9
+ a.end_point_type=:bind
10
+ a.end_point='tcp://*:5560'
11
+ end
12
+
13
+
14
+
@@ -0,0 +1,13 @@
1
+ Feature: The Cucumber interface allows message inspection
2
+
3
+ Scenario: A message is received
4
+
5
+ Given publisher "my_publisher" sends the following:
6
+ |hello|world|
7
+
8
+ And I sleep 2 seconds
9
+
10
+ Then I should receive a message on ZeroMQ with agent "my_subscriber"
11
+ And the ZeroMQ message should have 2 parts
12
+ And part 1 of the ZeroMQ message should be "hello"
13
+ And part 2 of the ZeroMQ message should be "world"
@@ -0,0 +1,7 @@
1
+ Given /^publisher "([^"]*)" sends the following:$/ do |publisher, message|
2
+ AgentZMQ.agents_hash[publisher.to_sym].publish message.raw.first
3
+ end
4
+
5
+ Given /^I sleep (\d+) seconds$/ do |seconds|
6
+ sleep(seconds.to_i)
7
+ end
@@ -0,0 +1,8 @@
1
+ $: << File.expand_path("../../../lib", __FILE__)
2
+
3
+ require 'agent_zmq/cucumber'
4
+
5
+ AgentZMQ.start
6
+ at_exit {
7
+ AgentZMQ.stop
8
+ }
@@ -0,0 +1,71 @@
1
+ module AgentZMQ
2
+ extend self
3
+
4
+ def agent_path
5
+ "./config/zmq_agents.rb"
6
+ end
7
+
8
+ def agents
9
+ return @agents if @agents
10
+
11
+ (@agents=[]).tap do
12
+ load_agents if agent_files_loaded.empty?
13
+ end
14
+ end
15
+
16
+ def agent_files_loaded
17
+ @agent_files_loaded ||=[]
18
+ end
19
+
20
+ def load_agents path=nil
21
+ path = File.expand_path(path || agent_path, Dir.pwd)
22
+ return if agent_files_loaded.include? path
23
+ agent_files_loaded << path
24
+ load path
25
+ end
26
+
27
+ def define_agent(agent, &blk)
28
+ yield agent
29
+ agents << agent
30
+ end
31
+
32
+ def define_ZMQ_SUB(name, &blk)
33
+ define_agent(AgentZMQ::SubAgent.new(name), &blk)
34
+ end
35
+
36
+ def define_ZMQ_PUB(name, &blk)
37
+ define_agent(AgentZMQ::PubAgent.new(name), &blk)
38
+ end
39
+
40
+ def define_ZMQ_REQ(name, &blk)
41
+ define_agent(AgentZMQ::ReqAgent.new(name), &blk)
42
+ end
43
+
44
+ def define_ZMQ_REP(name, &blk)
45
+ define_agent(AgentZMQ::RepAgent.new(name), &blk)
46
+ end
47
+
48
+ #starts all configured agents
49
+ def start
50
+ raise RuntimeError, "No ZMQ Agents Defined" if agents.empty?
51
+
52
+ agents.each do |a|
53
+ a.start
54
+ end
55
+ end
56
+
57
+ def stop
58
+ agents.each {|a| a.stop}
59
+ end
60
+
61
+ def reset
62
+ agents.each {|a| a.reset}
63
+ end
64
+
65
+ def agents_hash
66
+ Hash[agents.map { |a| [a.name.to_sym, a]}]
67
+ end
68
+ end
69
+
70
+ require 'agent_zmq/helpers'
71
+ require 'agent_zmq/agent'
@@ -0,0 +1,4 @@
1
+ require 'agent_zmq/agents/sub_agent.rb'
2
+ require 'agent_zmq/agents/pub_agent.rb'
3
+ require 'agent_zmq/agents/req_agent.rb'
4
+ require 'agent_zmq/agents/rep_agent.rb'
@@ -0,0 +1,31 @@
1
+ module AgentZMQ::BaseAgent
2
+ attr_reader :name
3
+
4
+ attr_accessor :end_point_type, :end_point, :socket_opts
5
+
6
+ def zmq_context
7
+ @ctx ||= ZMQ::Context.new 1
8
+ end
9
+
10
+ def zmq_socket
11
+ return @sub_socket unless @sub_socket.nil?
12
+
13
+ (@sub_socket = sock_type).tap do
14
+
15
+ case @end_point_type
16
+ when :connect
17
+ @sub_socket.connect(@end_point)
18
+ else
19
+ @sub_socket.bind(@end_point)
20
+ end
21
+
22
+ if @socket_opts.is_a? Array
23
+ @socket_opts.each do |opts|
24
+ opts.each_pair do |opt_name, opt_val|
25
+ @sub_socket.setsockopt(opt_name,opt_val)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ require 'agent_zmq/agents/base_agent'
2
+
3
+ class AgentZMQ::PubAgent
4
+ include AgentZMQ::BaseAgent
5
+
6
+ def initialize name
7
+ @name=name
8
+ @socket_opts=[]
9
+ end
10
+
11
+ def sock_type
12
+ zmq_context.socket(ZMQ::PUB)
13
+ end
14
+
15
+ def start
16
+ zmq_socket
17
+ sleep 0.8 # slow joiner
18
+ end
19
+
20
+ def stop
21
+ zmq_socket.close
22
+ end
23
+
24
+ def publish msg
25
+ AgentZMQ::Helpers.publish zmq_socket, msg
26
+ end
27
+
28
+ def reset
29
+
30
+ end
31
+ end
@@ -0,0 +1,65 @@
1
+ require 'agent_zmq/agents/base_agent'
2
+ require 'thread'
3
+
4
+ class AgentZMQ::RepAgent
5
+ include AgentZMQ::BaseAgent
6
+ include AgentZMQ::MessageCache
7
+
8
+ attr_accessor :reply
9
+
10
+ def initialize name
11
+ @name=name
12
+ @socket_opts=[]
13
+
14
+ @read_thread=nil
15
+ @mutex = Mutex.new
16
+ @do_run_read_thread = true
17
+ end
18
+
19
+ def do_read
20
+ while true
21
+ @mutex.synchronize do
22
+ return unless @do_run_read_thread
23
+ end
24
+ @zmq_poller.poll(1000)
25
+
26
+ @zmq_poller.readables.each do |sock|
27
+ request=AgentZMQ::Helpers.read_msg sock
28
+ add_msg request
29
+
30
+ unless @reply.nil?
31
+ AgentZMQ::Helpers.publish(sock, @reply.call(request))
32
+ end
33
+ end
34
+ end
35
+
36
+ zmq_socket.close
37
+ end
38
+
39
+ def sock_type
40
+ zmq_context.socket(ZMQ::REP)
41
+ end
42
+
43
+ def start_read_thread
44
+ @zmq_poller = ZMQ::Poller.new
45
+ @zmq_poller.register(zmq_socket, ZMQ::POLLIN)
46
+
47
+ @read_thread = Thread.new {do_read}
48
+ end
49
+
50
+ def start
51
+ start_read_thread
52
+ end
53
+
54
+ def stop
55
+ @mutex.synchronize do
56
+ @do_run_read_thread=false
57
+ end
58
+ @read_thread.join
59
+ zmq_socket.close
60
+ end
61
+
62
+ def reset
63
+ clear
64
+ end
65
+ end
@@ -0,0 +1,32 @@
1
+ require 'agent_zmq/agents/base_agent'
2
+
3
+ class AgentZMQ::ReqAgent
4
+ include AgentZMQ::BaseAgent
5
+
6
+ def initialize name
7
+ @name=name
8
+ @socket_opts=[]
9
+ end
10
+
11
+ def sock_type
12
+ zmq_context.socket(ZMQ::REQ)
13
+ end
14
+
15
+ def start
16
+ zmq_socket
17
+ sleep 0.8 # slow joiner
18
+ end
19
+
20
+ def stop
21
+ zmq_socket.close
22
+ end
23
+
24
+ def publish msg
25
+ AgentZMQ::Helpers.publish(zmq_socket, msg)
26
+ AgentZMQ::Helpers.read_msg zmq_socket
27
+ end
28
+
29
+ def reset
30
+ #no-op
31
+ end
32
+ end
@@ -0,0 +1,66 @@
1
+ require 'ffi-rzmq'
2
+ require 'thread'
3
+
4
+ require 'agent_zmq/message_cache'
5
+ require 'agent_zmq/agents/base_agent'
6
+
7
+ class AgentZMQ::SubAgent
8
+ include AgentZMQ::MessageCache
9
+ include AgentZMQ::BaseAgent
10
+
11
+ attr_reader :name
12
+
13
+ def initialize name
14
+ @name=name
15
+ @socket_opts=[]
16
+
17
+ @mutex=Mutex.new
18
+ @read_thread=nil
19
+ @do_run_read_thread = true
20
+ end
21
+
22
+ def do_read
23
+ while true
24
+ @mutex.synchronize do
25
+ return unless @do_run_read_thread
26
+ end
27
+
28
+ @zmq_poller.poll(1000)
29
+
30
+ @zmq_poller.readables.each do |sock|
31
+ add_msg AgentZMQ::Helpers.read_msg sock
32
+ end
33
+ end
34
+
35
+ zmq_socket.close
36
+ end
37
+
38
+ def sock_type
39
+ zmq_context.socket(ZMQ::SUB)
40
+ end
41
+
42
+
43
+ def start_read_thread
44
+ @zmq_poller = ZMQ::Poller.new
45
+ @zmq_poller.register(zmq_socket, ZMQ::POLLIN)
46
+
47
+ @read_thread = Thread.new {do_read}
48
+ end
49
+
50
+ def start
51
+ start_read_thread
52
+ end
53
+
54
+ def stop
55
+ @mutex.synchronize do
56
+ @do_run_read_thread = false
57
+ end
58
+ @read_thread.join
59
+ zmq_socket.close
60
+ end
61
+
62
+ def reset
63
+ clear
64
+ end
65
+
66
+ end
@@ -0,0 +1,32 @@
1
+ require File.expand_path("../../agent_zmq", __FILE__)
2
+
3
+ require 'rspec'
4
+
5
+ module ZMQMessageCache
6
+ def last_zmq_message
7
+ @message
8
+ end
9
+ end
10
+
11
+ World(ZMQMessageCache)
12
+
13
+ Then /^I should receive a (?:request|response|message) on ZeroMQ with agent "([^"]*)"$/ do |subscriber|
14
+ throw "Unknown agent #{subscriber}" unless AgentZMQ.agents_hash.has_key?(subscriber.to_sym)
15
+ throw "#{subscriber} is not an agent type that receives messages" unless AgentZMQ.agents_hash[subscriber.to_sym].respond_to?(:pop)
16
+
17
+ @message=AgentZMQ.agents_hash[subscriber.to_sym].pop
18
+ @message.should_not be_nil
19
+ end
20
+
21
+ Then /^the ZeroMQ (?:request|response|message) should have (\d+) parts$/ do |length|
22
+ throw "last_zmq_message is nil" if last_zmq_message.nil?
23
+
24
+ last_zmq_message.length == length.to_i
25
+ end
26
+
27
+ Then /^part (\d+) of the ZeroMQ (?:request|response|message) should be "([^"]*)"$/ do |index, value|
28
+ throw "last_zmq_message is nil" if last_zmq_message.nil?
29
+
30
+ last_zmq_message.length.should >= index.to_i
31
+ last_zmq_message[(index.to_i - 1)].should == value
32
+ end
@@ -0,0 +1,32 @@
1
+ module AgentZMQ
2
+ module Helpers
3
+ extend self
4
+
5
+ def read_msg socket
6
+ msg_parts = []
7
+
8
+ begin
9
+ part=""
10
+ socket.recv_string part
11
+ msg_parts << part
12
+ end while socket.more_parts?
13
+
14
+ msg_parts
15
+ end
16
+
17
+ def publish socket, msg
18
+ msg = [msg] unless msg.is_a? Array
19
+
20
+ while true do
21
+ msg_part=msg.shift
22
+
23
+ if msg.empty?
24
+ socket.send_string msg_part
25
+ break
26
+ else
27
+ socket.send_string msg_part, ZMQ::SNDMORE
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,36 @@
1
+ require 'thread'
2
+ module AgentZMQ::MessageCache
3
+ def messages_received
4
+ lock.synchronize do
5
+ return messages.dup
6
+ end
7
+ end
8
+
9
+ def pop
10
+ lock.synchronize do
11
+ return messages.pop
12
+ end
13
+ end
14
+
15
+ def add_msg msg
16
+ lock.synchronize do
17
+ messages << msg
18
+ end
19
+ end
20
+
21
+ def clear
22
+ lock.synchronize do
23
+ messages.clear
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def messages
30
+ @messages||=[]
31
+ end
32
+
33
+ def lock
34
+ @lock||=Mutex.new
35
+ end
36
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ class DummyClass
4
+ end
5
+
6
+ describe AgentZMQ::MessageCache do
7
+ before(:each) do
8
+ @cache = DummyClass.new
9
+ @cache.extend(AgentZMQ::MessageCache)
10
+ end
11
+
12
+ describe "pop" do
13
+ it "returns nil if empty" do
14
+ @cache.pop.should be_nil
15
+ end
16
+
17
+ it "returns pops messages in lifo" do
18
+ @cache.add_msg "hello"
19
+ @cache.add_msg "world"
20
+
21
+ @cache.pop.should ==("world")
22
+ @cache.pop.should ==("hello")
23
+ @cache.pop.should be_nil
24
+ end
25
+ end
26
+
27
+ describe "clear" do
28
+ it "removes all cached messages" do
29
+ @cache.add_msg "hello"
30
+ @cache.add_msg "world"
31
+
32
+ @cache.clear
33
+ @cache.pop.should be_nil
34
+ end
35
+ end
36
+
37
+ describe "messages_received" do
38
+ it "duplicates the internal message cache" do
39
+ @cache.add_msg "hello"
40
+ @cache.add_msg "world"
41
+
42
+ msgs_received = @cache.messages_received
43
+ @cache.clear
44
+ msgs_received.should ==["hello", "world"]
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'agent_zmq'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+
12
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: agent_zmq
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Chris Busbey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2013-08-29 00:00:00 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ffi-rzmq
16
+ requirement: &id001 !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ~>
19
+ - !ruby/object:Gem::Version
20
+ version: 0.9.3
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: *id001
24
+ - !ruby/object:Gem::Dependency
25
+ name: rspec
26
+ requirement: &id002 !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: "2.14"
31
+ type: :runtime
32
+ prerelease: false
33
+ version_requirements: *id002
34
+ - !ruby/object:Gem::Dependency
35
+ name: jeweler
36
+ requirement: &id003 !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: "1.8"
41
+ type: :development
42
+ prerelease: false
43
+ version_requirements: *id003
44
+ - !ruby/object:Gem::Dependency
45
+ name: cucumber
46
+ requirement: &id004 !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ~>
49
+ - !ruby/object:Gem::Version
50
+ version: "1.3"
51
+ type: :development
52
+ prerelease: false
53
+ version_requirements: *id004
54
+ - !ruby/object:Gem::Dependency
55
+ name: rake
56
+ requirement: &id005 !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ version: "10.1"
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: *id005
64
+ description: Acceptance test framework for ZeroMQ applications. Includes some cucumber helpers.
65
+ email: info@connamara.com
66
+ executables: []
67
+
68
+ extensions: []
69
+
70
+ extra_rdoc_files:
71
+ - LICENSE.txt
72
+ - README.md
73
+ files:
74
+ - .document
75
+ - .rspec
76
+ - .travis.yml
77
+ - CONTRIBUTION_GUIDELINES.md
78
+ - Gemfile
79
+ - Gemfile.lock
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - VERSION
84
+ - agent_zmq.gemspec
85
+ - config/zmq_agents.rb
86
+ - features/MessageInspection.feature
87
+ - features/step_definitions/steps.rb
88
+ - features/support/env.rb
89
+ - lib/agent_zmq.rb
90
+ - lib/agent_zmq/agent.rb
91
+ - lib/agent_zmq/agents/base_agent.rb
92
+ - lib/agent_zmq/agents/pub_agent.rb
93
+ - lib/agent_zmq/agents/rep_agent.rb
94
+ - lib/agent_zmq/agents/req_agent.rb
95
+ - lib/agent_zmq/agents/sub_agent.rb
96
+ - lib/agent_zmq/cucumber.rb
97
+ - lib/agent_zmq/helpers.rb
98
+ - lib/agent_zmq/message_cache.rb
99
+ - spec/agent_zmq/message_cache_spec.rb
100
+ - spec/spec_helper.rb
101
+ homepage: https://github.com/connamara/agent_zmq
102
+ licenses:
103
+ - GPL
104
+ metadata: {}
105
+
106
+ post_install_message:
107
+ rdoc_options: []
108
+
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - &id006
114
+ - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: "0"
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - *id006
120
+ requirements: []
121
+
122
+ rubyforge_project:
123
+ rubygems_version: 2.0.7
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: Acceptance test framework for ZeroMQ applications
127
+ test_files: []
128
+