sync_service 0.0.8
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/.autotest +5 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/Gemfile +13 -0
- data/Guardfile +5 -0
- data/README.md +66 -0
- data/Rakefile +29 -0
- data/examples/application.rb +17 -0
- data/examples/client.rb +29 -0
- data/examples/config.ru +7 -0
- data/examples/php/client.php +17 -0
- data/examples/php/jsonRPCClient.php +165 -0
- data/examples/python/README +5 -0
- data/examples/python/client.py +16 -0
- data/examples/server.rb +4 -0
- data/lib/mobme/infrastructure/rpc/adaptor.rb +31 -0
- data/lib/mobme/infrastructure/rpc/base.rb +15 -0
- data/lib/mobme/infrastructure/rpc/error.rb +3 -0
- data/lib/mobme/infrastructure/rpc/runner.rb +21 -0
- data/lib/mobme/infrastructure/rpc/version.rb +14 -0
- data/lib/rpc/.gitignore +2 -0
- data/lib/rpc/CHANGELOG +10 -0
- data/lib/rpc/Gemfile +19 -0
- data/lib/rpc/LICENSE +20 -0
- data/lib/rpc/README.textile +7 -0
- data/lib/rpc/examples/em-http-request-json/client.rb +39 -0
- data/lib/rpc/examples/helpers.rb +15 -0
- data/lib/rpc/examples/net-http-json/client.rb +34 -0
- data/lib/rpc/examples/net-http-json/console.rb +13 -0
- data/lib/rpc/examples/server.ru +42 -0
- data/lib/rpc/examples/socket-json/client.rb +36 -0
- data/lib/rpc/examples/socket-json/server.rb +41 -0
- data/lib/rpc/lib/rpc.rb +166 -0
- data/lib/rpc/lib/rpc/clients/amqp/coolio.rb +0 -0
- data/lib/rpc/lib/rpc/clients/amqp/eventmachine.rb +0 -0
- data/lib/rpc/lib/rpc/clients/amqp/socket.rb +0 -0
- data/lib/rpc/lib/rpc/clients/em-http-request.rb +58 -0
- data/lib/rpc/lib/rpc/clients/net-http.rb +55 -0
- data/lib/rpc/lib/rpc/clients/redis.rb +0 -0
- data/lib/rpc/lib/rpc/clients/socket.rb +50 -0
- data/lib/rpc/lib/rpc/encoders/json.rb +142 -0
- data/lib/rpc/lib/rpc/encoders/xml.rb +0 -0
- data/lib/rpc/rpc.gemspec +34 -0
- data/lib/sync_service.rb +20 -0
- data/spec/adaptor_spec.rb +104 -0
- data/spec/base_spec.rb +61 -0
- data/spec/error_spec.rb +14 -0
- data/spec/runner_spec.rb +31 -0
- data/spec/spec_helper.rb +9 -0
- data/sync_service.gemspec +32 -0
- metadata +218 -0
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# https://github.com/eventmachine/em-http-request
|
|
4
|
+
|
|
5
|
+
require "eventmachine"
|
|
6
|
+
require "em-http-request"
|
|
7
|
+
|
|
8
|
+
# Note that we support only HTTP POST. JSON-RPC can be done
|
|
9
|
+
# via HTTP GET as well, but since HTTP POST is the preferred
|
|
10
|
+
# method, I decided to implement only it. More info can is here:
|
|
11
|
+
# http://groups.google.com/group/json-rpc/web/json-rpc-over-http
|
|
12
|
+
|
|
13
|
+
module RPC
|
|
14
|
+
module Clients
|
|
15
|
+
class EmHttpRequest
|
|
16
|
+
HEADERS ||= {"Accept" => "application/json-rpc"}
|
|
17
|
+
|
|
18
|
+
def initialize(uri)
|
|
19
|
+
@client = EventMachine::HttpRequest.new(uri)
|
|
20
|
+
@in_progress = 0
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def connect
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def disconnect
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def run(&block)
|
|
30
|
+
EM.run do
|
|
31
|
+
block.call
|
|
32
|
+
|
|
33
|
+
# Note: There's no way how to stop the
|
|
34
|
+
# reactor when there are no remaining events.
|
|
35
|
+
EM.add_periodic_timer(0.1) do
|
|
36
|
+
EM.stop if @in_progress == 0
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def send(data, &callback)
|
|
42
|
+
request = @client.post(head: HEADERS, body: data)
|
|
43
|
+
@in_progress += 1
|
|
44
|
+
request.callback do |response|
|
|
45
|
+
if callback
|
|
46
|
+
callback.call(response.response)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
@in_progress -= 1
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def async?
|
|
54
|
+
true
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require "uri"
|
|
4
|
+
|
|
5
|
+
# Note that we support only HTTP POST. JSON-RPC can be done
|
|
6
|
+
# via HTTP GET as well, but since HTTP POST is the preferred
|
|
7
|
+
# method, I decided to implement only it. More info can is here:
|
|
8
|
+
# http://groups.google.com/group/json-rpc/web/json-rpc-over-http
|
|
9
|
+
|
|
10
|
+
module Net
|
|
11
|
+
autoload :HTTP, "net/http"
|
|
12
|
+
autoload :HTTPS, "net/https"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module RPC
|
|
16
|
+
module Clients
|
|
17
|
+
class NetHttp
|
|
18
|
+
HEADERS ||= {"Accept" => "application/json-rpc"}
|
|
19
|
+
|
|
20
|
+
def initialize(uri)
|
|
21
|
+
@uri = URI.parse(uri)
|
|
22
|
+
klass = Net.const_get(@uri.scheme.upcase)
|
|
23
|
+
@client = klass.new(@uri.host, @uri.port)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def connect
|
|
27
|
+
@client.start
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def disconnect
|
|
31
|
+
@client.finish
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def run(&block)
|
|
35
|
+
self.connect
|
|
36
|
+
block.call
|
|
37
|
+
self.disconnect
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def send(data)
|
|
41
|
+
path = @uri.path.empty? ? "/" : @uri.path
|
|
42
|
+
|
|
43
|
+
begin
|
|
44
|
+
@client.post(path, data, HEADERS).body
|
|
45
|
+
rescue EOFError
|
|
46
|
+
retry
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def async?
|
|
51
|
+
false
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
File without changes
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require "uri"
|
|
4
|
+
require "socket"
|
|
5
|
+
|
|
6
|
+
module RPC
|
|
7
|
+
module Clients
|
|
8
|
+
class Socket
|
|
9
|
+
def initialize(uri)
|
|
10
|
+
@uri = URI.parse(uri)
|
|
11
|
+
|
|
12
|
+
# Localhost doesn't work for me for some reason.
|
|
13
|
+
@uri.host = "127.0.0.1" if @uri.host.eql?("localhost")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def connect
|
|
17
|
+
@client = TCPSocket.new(@uri.host, @uri.port)
|
|
18
|
+
rescue Errno::ECONNREFUSED
|
|
19
|
+
raise Errno::ECONNREFUSED.new("You have to start the server first!")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def disconnect
|
|
23
|
+
@client.close
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def run(&block)
|
|
27
|
+
self.connect
|
|
28
|
+
block.call
|
|
29
|
+
self.disconnect
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# TODO: support for notifications, probably refactor send to:
|
|
33
|
+
# def send(encoder, data)
|
|
34
|
+
# binary = encoder.encode(data)
|
|
35
|
+
# @client.puts(binary)
|
|
36
|
+
# @client.readline if data[:id]
|
|
37
|
+
# end
|
|
38
|
+
# ... and don't forget to add support for notifications to the example socket server!
|
|
39
|
+
def send(data)
|
|
40
|
+
@client.puts(data)
|
|
41
|
+
@client.readline
|
|
42
|
+
# TODO: sync vs. async: @socket.read or a callback and a loop
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def async?
|
|
46
|
+
false
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# http://en.wikipedia.org/wiki/JSON-RPC
|
|
4
|
+
|
|
5
|
+
begin
|
|
6
|
+
require "yajl/json_gem"
|
|
7
|
+
rescue LoadError
|
|
8
|
+
require "json"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module RPC
|
|
12
|
+
module Encoders
|
|
13
|
+
module Json
|
|
14
|
+
# This library works with JSON-RPC 2.0
|
|
15
|
+
# http://groups.google.com/group/json-rpc/web/json-rpc-2-0
|
|
16
|
+
JSON_RPC_VERSION ||= "2.0"
|
|
17
|
+
|
|
18
|
+
# http://json-rpc.org/wd/JSON-RPC-1-1-WD-20060807.html#ErrorObject
|
|
19
|
+
module Errors
|
|
20
|
+
# @note The exceptions are "eaten", because no client should be able to shut the server down.
|
|
21
|
+
def exception(exception, code = 000, message = "#{exception.class}: #{exception.message}")
|
|
22
|
+
unless RPC.development?
|
|
23
|
+
object = {class: exception.class.to_s, message: exception.message, backtrace: exception.backtrace}
|
|
24
|
+
self.error(message, code, object)
|
|
25
|
+
else
|
|
26
|
+
raise exception
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def error(message, code, object)
|
|
31
|
+
error = {name: "JSONRPCError", code: code, message: message, error: object}
|
|
32
|
+
RPC.log "ERROR #{message} (#{code}) #{error[:error].inspect}"
|
|
33
|
+
error
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class Request
|
|
38
|
+
attr_reader :data
|
|
39
|
+
def initialize(method, params, id = self.generate_id)
|
|
40
|
+
@data = {jsonrpc: JSON_RPC_VERSION, method: method, params: params}
|
|
41
|
+
@data.merge!(id: id) unless id.nil?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def generate_id
|
|
45
|
+
rand(999_999_999_999)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
class Client
|
|
50
|
+
include Errors
|
|
51
|
+
|
|
52
|
+
def encode(method, *args)
|
|
53
|
+
data = Request.new(method, args).data
|
|
54
|
+
RPC.log "CLIENT ENCODE #{data.inspect}"
|
|
55
|
+
data.to_json
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Notifications are calls which don't require response.
|
|
59
|
+
# They look just the same, but they don't have any id.
|
|
60
|
+
def notification(method, *args)
|
|
61
|
+
data = Request.new(method, args, nil).data
|
|
62
|
+
RPC.log "CLIENT ENCODE NOTIFICATION #{data.inspect}"
|
|
63
|
+
data.to_json
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Provide list of requests and notifications to run on the server.
|
|
67
|
+
#
|
|
68
|
+
# @example
|
|
69
|
+
# ["list", ["/"], ["clear", "logs", nil]]
|
|
70
|
+
def batch(requests)
|
|
71
|
+
data = requests.map { |request| Request.new(*request).data }
|
|
72
|
+
RPC.log "CLIENT ENCODE BATCH #{data.inspect}"
|
|
73
|
+
data.to_json
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# TODO: support batch
|
|
77
|
+
def decode(binary)
|
|
78
|
+
if binary.nil?
|
|
79
|
+
raise TypeError.new("#{self.class}#decode takes binary data as an argument, not nil!")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
object = JSON.parse(binary)
|
|
83
|
+
RPC.log "CLIENT DECODE #{object.inspect}"
|
|
84
|
+
object
|
|
85
|
+
rescue JSON::ParserError => error
|
|
86
|
+
self.exception(error, -32600, "Invalid Request.")
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
class Server
|
|
91
|
+
include Errors
|
|
92
|
+
|
|
93
|
+
def decode(binary)
|
|
94
|
+
object = JSON.parse(binary)
|
|
95
|
+
RPC.log "SERVER DECODE #{object.inspect}"
|
|
96
|
+
object
|
|
97
|
+
rescue JSON::ParserError => error
|
|
98
|
+
# This is supposed to result in HTTP 500.
|
|
99
|
+
raise self.exception(error, -32700, "Parse error.")
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def execute(encoded_result, subject)
|
|
103
|
+
result = self.decode(encoded_result)
|
|
104
|
+
|
|
105
|
+
if result.respond_to?(:merge) # Hash, only one result.
|
|
106
|
+
self.encode(result_or_error(subject, result))
|
|
107
|
+
else # Array, multiple results.
|
|
108
|
+
self.encode(
|
|
109
|
+
result.map do |result|
|
|
110
|
+
result_or_error(subject, result)
|
|
111
|
+
end
|
|
112
|
+
)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def result_or_error(subject, command)
|
|
117
|
+
method, args = command["method"], command["params"]
|
|
118
|
+
result = subject.send(method, *args)
|
|
119
|
+
self.response(result, nil, command["id"])
|
|
120
|
+
rescue NoMethodError => error
|
|
121
|
+
error = self.exception(error, -32601, "Method not found.")
|
|
122
|
+
self.response(nil, error, command["id"])
|
|
123
|
+
rescue ArgumentError => error
|
|
124
|
+
error = self.exception(error, -32602, "Invalid params.")
|
|
125
|
+
self.response(nil, error, command["id"])
|
|
126
|
+
rescue Exception => exception
|
|
127
|
+
error = self.exception(exception)
|
|
128
|
+
self.response(nil, error, command["id"])
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def response(result, error, id)
|
|
132
|
+
{jsonrpc: JSON_RPC_VERSION, result: result, error: error, id: id}
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def encode(response)
|
|
136
|
+
RPC.log "SERVER ENCODE: #{response.inspect}"
|
|
137
|
+
response.to_json
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
File without changes
|
data/lib/rpc/rpc.gemspec
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env gem build
|
|
2
|
+
# encoding: utf-8
|
|
3
|
+
|
|
4
|
+
require "base64"
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |s|
|
|
7
|
+
s.name = "rpc"
|
|
8
|
+
s.version = "0.3.1"
|
|
9
|
+
s.authors = ["Jakub Stastny aka botanicus"]
|
|
10
|
+
s.homepage = "http://github.com/ruby-amqp/rpc"
|
|
11
|
+
s.summary = "Generic RPC library for Ruby."
|
|
12
|
+
s.description = "#{s.summary} Currently it supports JSON-RPC over HTTP, support for AMQP and Redis will follow soon."
|
|
13
|
+
s.cert_chain = []
|
|
14
|
+
s.email = Base64.decode64("c3Rhc3RueUAxMDFpZGVhcy5jeg==\n")
|
|
15
|
+
s.has_rdoc = true
|
|
16
|
+
|
|
17
|
+
# files
|
|
18
|
+
s.files = `git ls-files`.split("\n")
|
|
19
|
+
s.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
# Ruby version
|
|
22
|
+
s.required_ruby_version = ::Gem::Requirement.new("~> 1.9")
|
|
23
|
+
|
|
24
|
+
begin
|
|
25
|
+
require "changelog"
|
|
26
|
+
rescue LoadError
|
|
27
|
+
warn "You have to have changelog gem installed for post install message"
|
|
28
|
+
else
|
|
29
|
+
s.post_install_message = CHANGELOG.new.version_changes
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# RubyForge
|
|
33
|
+
s.rubyforge_project = "rpc"
|
|
34
|
+
end
|
data/lib/sync_service.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Standard
|
|
2
|
+
require 'syslog'
|
|
3
|
+
|
|
4
|
+
# Gems
|
|
5
|
+
require "rack/request"
|
|
6
|
+
require 'thin'
|
|
7
|
+
|
|
8
|
+
# Bundled RPC
|
|
9
|
+
$:.push(Pathname.new(File.dirname(__FILE__)).join('rpc', 'lib').to_path)
|
|
10
|
+
require 'rpc'
|
|
11
|
+
|
|
12
|
+
# Local
|
|
13
|
+
require_relative 'mobme/infrastructure/rpc/version'
|
|
14
|
+
require_relative 'mobme/infrastructure/rpc/error'
|
|
15
|
+
require_relative 'mobme/infrastructure/rpc/base'
|
|
16
|
+
require_relative 'mobme/infrastructure/rpc/adaptor'
|
|
17
|
+
require_relative 'mobme/infrastructure/rpc/runner'
|
|
18
|
+
|
|
19
|
+
# Alias the client too
|
|
20
|
+
SyncService::Client = RPC::Client
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Gems
|
|
2
|
+
require 'rspec'
|
|
3
|
+
|
|
4
|
+
# Local
|
|
5
|
+
require_relative 'spec_helper'
|
|
6
|
+
require_relative '../lib/async_service'
|
|
7
|
+
|
|
8
|
+
module MobME::Infrastructure::RPC
|
|
9
|
+
describe Adaptor do
|
|
10
|
+
let(:dummy_service_object) { double "DummyService" }
|
|
11
|
+
let(:dummy_server) { double(RPC::Server).as_null_object }
|
|
12
|
+
|
|
13
|
+
before :each do
|
|
14
|
+
RPC::Server.stub(:new).and_return(dummy_server)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
subject { Adaptor.new dummy_service_object }
|
|
18
|
+
|
|
19
|
+
it "accepts service object" do
|
|
20
|
+
Adaptor.should respond_to(:new).with(1).argument
|
|
21
|
+
Adaptor.new dummy_service_object
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it { should respond_to(:server).with(0).arguments }
|
|
25
|
+
it { should respond_to(:call).with(1).argument }
|
|
26
|
+
it { should respond_to(:response).with(2).arguments }
|
|
27
|
+
|
|
28
|
+
describe "#server" do
|
|
29
|
+
it "creates an instance of RPC::Server" do
|
|
30
|
+
RPC::Server.should_receive(:new).with(dummy_service_object)
|
|
31
|
+
subject.server
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "returns an instance of RPC::Server" do
|
|
35
|
+
subject.server.should be dummy_server
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context "when called multiple times" do
|
|
39
|
+
it "returns the same (original) instance of RPC::Server" do
|
|
40
|
+
subject.server.should be dummy_server
|
|
41
|
+
second_dummy_server = double(RPC::Server)
|
|
42
|
+
RPC::Server.stub(:new).and_return(second_dummy_server)
|
|
43
|
+
subject.server.should be dummy_server
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe "#call" do
|
|
49
|
+
let(:dummy_environment) { double("Environment") }
|
|
50
|
+
let(:dummy_command) { double("Request Command") }
|
|
51
|
+
let(:dummy_body) { double("Request Body", :read => dummy_command) }
|
|
52
|
+
let(:dummy_request) { double(Rack::Request, :body => dummy_body) }
|
|
53
|
+
|
|
54
|
+
before :each do
|
|
55
|
+
Rack::Request.stub(:new).and_return(dummy_request)
|
|
56
|
+
subject.stub(:response)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "creates a new rack request object" do
|
|
60
|
+
Rack::Request.should_receive(:new).with(dummy_environment)
|
|
61
|
+
subject.call(dummy_environment)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "extracts command from request" do
|
|
65
|
+
dummy_request.should_receive(:body)
|
|
66
|
+
dummy_body.should_receive(:read)
|
|
67
|
+
subject.call(dummy_environment)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "executes the extracted command" do
|
|
71
|
+
dummy_server.stub(:execute).and_return(double("Binary Response").as_null_object)
|
|
72
|
+
dummy_server.should_receive(:execute).with(dummy_command)
|
|
73
|
+
subject.call(dummy_environment)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
context "when response from executed command contains string NoMethodError" do
|
|
77
|
+
it "calls response method with status 404" do
|
|
78
|
+
dummy_server.stub(:execute).and_return('NoMethodError')
|
|
79
|
+
subject.should_receive(:response).with(404, 'NoMethodError')
|
|
80
|
+
subject.call(dummy_environment)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
context "when response from executed command does not contain NoMethodError" do
|
|
85
|
+
it "calls response method with status 200" do
|
|
86
|
+
dummy_server.stub(:execute).and_return('Method Exists!')
|
|
87
|
+
subject.should_receive(:response).with(200, 'Method Exists!')
|
|
88
|
+
subject.call(dummy_environment)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
describe "#response" do
|
|
94
|
+
it "returns response array acceptable to Rack" do
|
|
95
|
+
dummy_body = "Dummy Body Content"
|
|
96
|
+
headers = {
|
|
97
|
+
"Content-Type" => "application/json-rpc",
|
|
98
|
+
"Content-Length" => dummy_body.bytesize.to_s
|
|
99
|
+
}
|
|
100
|
+
subject.response(200, dummy_body).should == [200, headers, [dummy_body]]
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|