Commit 38f0137d authored by Felix Hamann's avatar Felix Hamann

removed old ruby client implementation

parent 8b75e2f7
--color
--require spec_helper
# A sample Gemfile
source "https://rubygems.org"
gem "rspec"
gem "rbczmq"
GEM
remote: https://rubygems.org/
specs:
diff-lcs (1.2.5)
rbczmq (1.7.8)
rspec (3.2.0)
rspec-core (~> 3.2.0)
rspec-expectations (~> 3.2.0)
rspec-mocks (~> 3.2.0)
rspec-core (3.2.0)
rspec-support (~> 3.2.0)
rspec-expectations (3.2.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.2.0)
rspec-mocks (3.2.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.2.0)
rspec-support (3.2.1)
PLATFORMS
ruby
DEPENDENCIES
rbczmq
rspec
The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# Samwise Ruby Gem #
This is a ruby implementation of the samwise protocol 1.0 to communicate with samwise instances.
## Examples ##
```ruby
Samwise::Connection.connect "ipc://path/to/samwise"
Samwise::RabbitMQ.publish_roundrobin "amq.direct", "", "hi!"
Samwise::RabbitMQ.publish_redundant 2, "amq.direct", "", "hi!"
Samwise::RabbitMQ.exchange_declare "test-x"
Samwise::RabbitMQ.exchange_delete "test-x"
Samwise::Connection.close!
```
require 'rbczmq'
module Samwise
# protocol version
VERSION = 1 * 100 + 0
# abstract superclass
class Error < StandardError; end
# if no connection to samwise could be established
class ConnectionFailure < StandardError; end
# if a message request can not be sent because of errors
class RequestMalformed < StandardError; end
# if an answer can not be parsed
class ResponseMalformed < StandardError; end
# if samwise answered with an error code
class ResponseError < StandardError; end
# if either send or recv run into a timeout
class Timeout < StandardError; end
end
require 'samwise/connection'
require 'samwise/message'
require 'samwise/rabbitmq'
module Samwise::Connection
extend self # singleton
# Create a new connection to a samwise endpoint. This creates a new
# ZeroMQ Context and establishes a connection to this endpoint. If
# this method gets called multiple times it destroys the former
# context and closes any existing connection and connects to the new
# endpoint.
#
# @param endpoint [String] a valid ZeroMQ endpoint specifier
# @return [Connection] freshly instantiated connection instance
#
def connect endpoint
if connected?
close!
end
@ctx ||= ZMQ::Context.new
@req = @ctx.socket(:REQ)
raise Samwise::ConnectionFailure, "create socket" unless @req
begin
rc = @req.connect(endpoint)
raise "connection failed" unless rc
rescue StandardError => e
raise Samwise::ConnectionFailure, e.inspect
end
connected?
end
# Destroy a ZeroMQ context explicitly
#
def close!
@ctx.destroy if @ctx
@ctx = nil
end
def send msg
raise Samwise::ConnectionFailure, "socket not connected" unless connected?
@req.send_message msg
raise Samwise::ConnectionFailure, "message was not sent" unless msg.gone?
rcode = @req.recv_frame().data.to_i
if rcode == -1
raise Samwise::ResponseError, @req.recv_frame().data
end
raise Samwise::ResponseMalformed unless rcode == 0
true
end
# Test if the context is still alive and the connection to the
# endpoint still exists.
#
# @return [Boolean] true if connected
#
def connected?
begin
return true if @ctx and @req and @req.state & ZMQ::Socket::CONNECTED
rescue ZMQ::Error => e
raise Samwise::ConnectionFailure, e.inspect
end
false
end
end
require 'forwardable'
module Samwise
class Message
extend Forwardable
def initialize
@frames = []
end
def_delegators :@frames, :size, :empty?
# Add a variable number of frames to the message.
#
# @param frames Variadic number of frames
#
def add *frames
frames.each do |m|
@frames.insert 0, m
end
end
# Send the message to samwise.
#
def send
if @frames.empty?
raise Samwise::RequestMalformed, "At least one frame required"
end
@frames << Samwise::VERSION.inspect
zmsg = ZMQ::Message.new
# puts "message: #{@frames.reverse.to_s}"
@frames.map { |m| ZMQ::Frame(m.to_s) }.each do |f|
zmsg.push f
end
Samwise::Connection.send zmsg
end
end
end
module Samwise::RabbitMQ
PUBLISHING_ARGS = [
:echange,
:routing_key,
:mandatory,
:immediate
]
PUBLISHING_OPTS = [
:content_type,
:content_encoding,
:delivery_mode, # beetle // either :persistent or not
:priority,
:correlation_id,
:reply_to,
:expiration, # beetle // as :expires_at
:message_id,
:type,
:user_id,
:app_id,
:cluster_id
]
def self.publish_roundrobin args, opts, payload
msg = Samwise::Message.new
msg.add "publish", "round robin"
self.publish msg, args, opts, payload
end
def self.publish_redundant n, args, opts, payload
msg = Samwise::Message.new
msg.add "publish", "redundant", n.inspect
self.publish msg, args, opts, payload
end
def self.exchange_declare name, type
msg = Samwise::Message.new
msg.add "rpc", "", "exchange.declare", name, type
msg.send
end
def self.exchange_delete name
msg = Samwise::Message.new
msg.add "rpc", "", "exchange.delete", name
msg.send
end
private
def self.publish msg, args, opts, payload
# add arguments
msg.add *(args.values_at :exchange, :routing_key, :mandatory, :immediate)
# add opts (retain order)
msg.add PUBLISHING_OPTS.size
PUBLISHING_OPTS.each do |key|
msg.add opts[key]
end
# add headers
if opts[:headers]
flat_headers = opts[:headers].collect { |k, v| [k, v] }.flatten
msg.add flat_headers.size, *flat_headers
else
msg.add 0
end
# add payload
msg.add payload
msg.send
end
end
#!/usr/bin/env ruby
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/lib')
require 'ostruct'
require 'optparse'
require 'samwise'
endpoint = "ipc://../../sam_ipc"
Samwise::Connection.connect endpoint
def publish (opts)
puts "publishing #{opts.n} messages (#{opts.t})" unless opts.quiet
time_start = Time.now
opts.n.times do |i|
puts "publishing message #{i}" if opts.verbose
amqp_args = { :exchange => "amq.direct" }
amqp_opts = { :headers => { :header_key => "header_val" }}
msg = "#{opts.t} publishing request no #{i}"
if opts.t == "redundant"
Samwise::RabbitMQ.publish_redundant opts.d, amqp_args, amqp_opts, msg
end
if opts.t == "round robin"
Samwise::RabbitMQ.publish_roundrobin amqp_args, amqp_opts, msg
end
end
time_end = Time.now
puts "done in #{time_end - time_start}, exiting" unless opts.quiet
end
#
# parse command line options
#
class OptionParser
def self.parse (args)
options = OpenStruct.new
options.n = 1
options.quiet = false
options.verbose = false
opt_parser = OptionParser.new do |opts|
opts.banner = "Usage: publish.rb [options]"
opts.separator ""
opts.separator "Specific options:"
# mandatory
opts.on("-n NUMBER", Integer, "Number of messages to publish") do |n|
options.n = n
end
opts.on("-t TYPE", String, "Distribution type [redundant, round robin]") do |t|
options.t = t
end
# optional
opts.separator ""
opts.separator "Common options:"
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit
end
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
options.verbose = v
end
opts.on("-q", "--quiet", "Completely suppress output") do |q|
options.quiet = q
options.verbose = false
end
opts.on("-d count", Integer, "For -t redundant") do |d|
if not options.t == "redundant"
raise "You must provide '-t redundant' to use -d"
end
options.d = d
end
end
rc = opt_parser.parse!(args)
raise OptionParser::MissingArgument, "-t" if options.t.nil?
if options.t == "redundant"
raise OptionParser::MissingArgument, "-d" if options.d.nil?
end
options
end
end
options = OptionParser.parse(ARGV)
publish(options)
Samwise::Connection.close!
Gem::Specification.new do |s|
s.name = "samwise"
# the first two parts of the version number
# are equal to the supported sam protocol
# specification, the last number gets iterated
# for new versions of the gem
s.version = "0.1.0"
s.date = "2015-02-21"
s.summary = "Samwise client"
s.description = "A client implementation to communicate with samd"
s.authors = ["Felix Hamann"]
s.email = "nvri@dreadworks.de"
s.files = [
"lib/samwise.rb",
'lib/samwise/connection.rb',
"lib/samwise/message.rb",
"lib/samwise/rabbitmq.rb"
]
s.homepage = "https://github.com/dreadworks/samwise"
s.license = "MIT"
end
require 'samwise'
RSpec.describe Samwise::Connection do
it "fails without explicit connect" do
expect(Samwise::Connection.connected?)
.to be false
Samwise::Connection.close!
end
it "fails for unknown endpoints" do
expect { Samwise::Connection.connect "endpoint" }
.to raise_error (Samwise::ConnectionFailure)
end
it "connects to a known endpoint" do
# TODO negotiate endpoint via config
expect(Samwise::Connection.connect("ipc://../../sam_ipc"))
.to be true
expect(Samwise::Connection.connected?)
.to be true
Samwise::Connection.close!
expect(Samwise::Connection.connected?)
.to be false
end
# TODO test send()
end
endpoint = "ipc://../../sam_ipc"
RSpec.describe Samwise::Message do
before(:all) do
Samwise::Connection.connect endpoint
end
after(:all) do
Samwise::Connection.close!
end
before(:each) do
@msg = Samwise::Message.new
end
it "creates a proper message" do
expect(@msg).to be_an_instance_of(Samwise::Message)
expect(@msg.empty?).to be true
expect(@msg.size).to eq 0
expect { @msg.send }.to raise_error Samwise::RequestMalformed
end
it "accepts frames" do
@msg.add "foo", "bar"
expect(@msg.empty?).to be false
expect(@msg.size).to eq 2
end
it "handles malformed requests" do
@msg.add "foo", "bar"
expect { @msg.send }.to raise_error Samwise::ResponseError
end
it "handles correct requests" do
@msg.add "ping"
expect(@msg.send).to eq true
end
end
endpoint = "ipc://../../sam_ipc"
RSpec.describe Samwise::RabbitMQ do
before(:all) do
Samwise::Connection.connect endpoint
end
after(:all) do
Samwise::Connection.close!
end
it "handles round robin" do
Samwise::RabbitMQ.publish_roundrobin "amq.direct", "", "hi!"
end
it "handles redundant" do
Samwise::RabbitMQ.publish_redundant 2, "amq.direct", "", "hi!"
end
it "handles exchange.declare" do
Samwise::RabbitMQ.exchange_declare "test-x", "direct"
end
it "handles exchange.delete" do
Samwise::RabbitMQ.exchange_delete "test-x"
end
end
# This file was generated by the `rspec --init` command. Conventionally, all
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
# The generated `.rspec` file contains `--require spec_helper` which will cause
# this file to always be loaded, without a need to explicitly require it in any
# files.
#
# Given that it is always loaded, you are encouraged to keep this file as
# light-weight as possible. Requiring heavyweight dependencies from this file
# will add to the boot time of your test suite on EVERY test run, even for an
# individual file that may not need all of that loaded. Instead, consider making
# a separate helper file that requires the additional dependencies and performs
# the additional setup, and require it from the spec files that actually need
# it.
#
# The `.rspec` file also contains a few flags that are not defaults but that
# users commonly want.
#
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config|
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.expect_with :rspec do |expectations|
# This option will default to `true` in RSpec 4. It makes the `description`
# and `failure_message` of custom matchers include text for helper methods
# defined using `chain`, e.g.:
# be_bigger_than(2).and_smaller_than(4).description
# # => "be bigger than 2 and smaller than 4"
# ...rather than:
# # => "be bigger than 2"
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
# rspec-mocks config goes here. You can use an alternate test double
# library (such as bogus or mocha) by changing the `mock_with` option here.
config.mock_with :rspec do |mocks|
# Prevents you from mocking or stubbing a method that does not exist on
# a real object. This is generally recommended, and will default to
# `true` in RSpec 4.
mocks.verify_partial_doubles = true
end
# The settings below are suggested to provide a good initial experience
# with RSpec, but feel free to customize to your heart's content.
=begin
# These two settings work together to allow you to limit a spec run
# to individual examples or groups you care about by tagging them with
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
# get run.
config.filter_run :focus
config.run_all_when_everything_filtered = true
# Limits the available syntax to the non-monkey patched syntax that is
# recommended. For more details, see:
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
# - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
config.disable_monkey_patching!
# This setting enables warnings. It's recommended, but in some cases may
# be too noisy due to issues in dependencies.
config.warnings = true
# Many RSpec users commonly either run the entire suite or an individual
# file, and it's useful to allow more verbose output when running an
# individual spec file.
if config.files_to_run.one?
# Use the documentation formatter for detailed output,
# unless a formatter has already been configured
# (e.g. via a command-line flag).
config.default_formatter = 'doc'
end
# Print the 10 slowest examples and example groups at the
# end of the spec run, to help surface which specs are running
# particularly slow.
config.profile_examples = 10
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = :random
# Seed global randomization in this process using the `--seed` CLI option.
# Setting this allows you to use `--seed` to deterministically reproduce
# test failures related to randomization by passing the same `--seed` value
# as the one that triggered the failure.
Kernel.srand config.seed
=end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment