joust 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +19 -0
- data/README.rdoc +54 -0
- data/Rakefile +8 -0
- data/bin/joust +42 -0
- data/data/specifications.yml +126 -0
- data/lib/joust.rb +45 -0
- data/lib/joust/expected_response.rb +20 -0
- data/lib/joust/expected_response/version_12.rb +10 -0
- data/lib/joust/expected_response/version_20.rb +10 -0
- data/spec/joust_spec.rb +41 -0
- data/spec/spec_helper.rb +2 -0
- metadata +63 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2012 Vertive, Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
= Joust - A JSON-RPC Server testing utility
|
2
|
+
|
3
|
+
== What is JSON-RPC?
|
4
|
+
From the [JSON-RPC Spec](http://www.jsonrpc.org/spec.html):
|
5
|
+
|
6
|
+
"JSON-RPC is a stateless, light-weight remote procedure call (RPC) protocol. Primarily this specification defines several data structures and the rules around their processing.
|
7
|
+
It is transport agnostic in that the concepts can be used within the same process, over sockets, over http, or in many various message passing environments. It uses JSON (RFC 4627)
|
8
|
+
as data format. It is designed to be simple!"
|
9
|
+
|
10
|
+
== What is Joust good for?
|
11
|
+
There are many JSON-RPC frameworks available for a variety of languages, but it can be difficult to tell which ones truly conform to specifications. Joust is a utility that allows a user or
|
12
|
+
developer to determine if a particular framework meets these specifications (and if it does not it enumerates how the framework failed).
|
13
|
+
|
14
|
+
== What versions of JSON-RPC specifications can I test for?
|
15
|
+
Joust supports testing for JSON-RPC [v1.2](http://jsonrpc.org/historical/jsonrpc12_proposal.html#specification) and [v2.0](http://www.jsonrpc.org/spec.html) (v2.0 is used by default).
|
16
|
+
|
17
|
+
== How do I use Joust?
|
18
|
+
JSON-RPC tests a server framework by sending predetermined requests and examining the server's response versus the expected response. To use Joust, set up a JSON-RPC Server that supports the
|
19
|
+
following methods (and ONLY the following methods):
|
20
|
+
|
21
|
+
* subtract: takes two parameters and returns difference between the first minus the second
|
22
|
+
* subtract_named: takes two named parameters ('minuend' and 'subtrahend') in any order and subtracts minuend minus subtrahend.
|
23
|
+
* update: takes five parameters and does nothing
|
24
|
+
* foobar: takes no parameters and does nothing
|
25
|
+
* sum: takes three parameters and returns their sum
|
26
|
+
* notify_hello: takes one parameter and does nothing
|
27
|
+
* get_data: takes no paramters and returns an array of 'hello' and 5
|
28
|
+
* notify_sum: takes three parameters and does nothing
|
29
|
+
|
30
|
+
Examples of a PHP class and a Ruby class with the above methods defined can be found in the example directory of [the Github repo](https://github.com/EvilScott/joust). Note that all of these
|
31
|
+
methods are used to test a JSON-RPC v2.0 server, but only a subset of them are used to test v1.2.
|
32
|
+
|
33
|
+
After setting this up just point Joust at the server and check out the results:
|
34
|
+
|
35
|
+
joust <JSON-RPC server url>
|
36
|
+
|
37
|
+
The results should look something like this:
|
38
|
+
|
39
|
+
v2.0 Positional parameters (1/2) -- PASS
|
40
|
+
v2.0 Positional parameters (2/2) -- PASS
|
41
|
+
v2.0 Named parameters (1/2) -- PASS
|
42
|
+
v2.0 Named parameters (2/2) -- PASS
|
43
|
+
v2.0 Notification (1/2) -- PASS
|
44
|
+
v2.0 Notification (2/2) -- PASS
|
45
|
+
v2.0 Missing method -- PASS
|
46
|
+
v2.0 Invalid JSON -- PASS
|
47
|
+
v2.0 Invalid JSON-RPC -- PASS
|
48
|
+
v2.0 Invalid batch JSON -- PASS
|
49
|
+
v2.0 Empty array -- PASS
|
50
|
+
v2.0 Invalid batch JSON-RPC (1/2) -- PASS
|
51
|
+
v2.0 Invalid batch JSON-RPC (2/2) -- PASS
|
52
|
+
v2.0 Batch call -- PASS
|
53
|
+
v2.0 Batch call (all notifications) -- PASS
|
54
|
+
JSON-RPC v2.0: 15/15 tests passed
|
data/Rakefile
ADDED
data/bin/joust
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Joust - JSON-RPC Server Specification Testing
|
3
|
+
# R. Scott Reis - February 2012
|
4
|
+
|
5
|
+
# core joust code
|
6
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
7
|
+
require 'joust'
|
8
|
+
|
9
|
+
# check for valid URL
|
10
|
+
url = ARGV.first
|
11
|
+
begin
|
12
|
+
URI.parse(url)
|
13
|
+
rescue
|
14
|
+
puts "URL #{url} does not appear to be valid"
|
15
|
+
exit(1)
|
16
|
+
end
|
17
|
+
|
18
|
+
# default options
|
19
|
+
options = {:version => 'v2.0'}
|
20
|
+
|
21
|
+
# command line options
|
22
|
+
require 'optparse'
|
23
|
+
OptionParser.new do |opts|
|
24
|
+
opts.banner = 'Usage: joust <url> [options]'
|
25
|
+
|
26
|
+
opts.on('-o', '--only-check (v1.2|v2.0)', 'Check only against JSON-RPC Specifications for specified version') do |v|
|
27
|
+
options[:version] = v
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on_tail("-?", "--help", "Show this message") do
|
31
|
+
puts opts
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
|
35
|
+
end.parse!
|
36
|
+
|
37
|
+
# specification test cases
|
38
|
+
require 'yaml'
|
39
|
+
test_cases = YAML.load(File.open(File.join(File.dirname(__FILE__), '..', 'data', 'specifications.yml')))
|
40
|
+
|
41
|
+
# run the spec checking
|
42
|
+
Joust.run(url, options, test_cases)
|
@@ -0,0 +1,126 @@
|
|
1
|
+
---
|
2
|
+
|
3
|
+
v2.0: # http://www.jsonrpc.org/spec.html
|
4
|
+
- "Positional parameters (1/2)":
|
5
|
+
- '{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1}'
|
6
|
+
- !ruby/object:YAML::Joust::Version20
|
7
|
+
expected: {result: 19, id: 1}
|
8
|
+
- "Positional parameters (2/2)":
|
9
|
+
- '{"jsonrpc": "2.0", "method": "subtract", "params": [23, 42], "id": 2}'
|
10
|
+
- !ruby/object:YAML::Joust::Version20
|
11
|
+
expected: {result: -19, id: 2}
|
12
|
+
- "Named parameters (1/2)":
|
13
|
+
- '{"jsonrpc": "2.0", "method": "subtract_named", "params": {"subtrahend": 23, "minuend": 42}, "id": 3}'
|
14
|
+
- !ruby/object:YAML::Joust::Version20
|
15
|
+
expected: {result: 19, id: 3}
|
16
|
+
- "Named parameters (2/2)":
|
17
|
+
- '{"jsonrpc": "2.0", "method": "subtract_named", "params": {"minuend": 42, "subtrahend": 23}, "id": 4}'
|
18
|
+
- !ruby/object:YAML::Joust::Version20
|
19
|
+
expected: {result: 19, id: 4}
|
20
|
+
- "Notification (1/2)":
|
21
|
+
- '{"jsonrpc": "2.0", "method": "update", "params": [1,2,3,4,5]}'
|
22
|
+
- !ruby/object:YAML::Joust::Version20
|
23
|
+
expected: {}
|
24
|
+
- "Notification (2/2)":
|
25
|
+
- '{"jsonrpc": "2.0", "method": "foobar"}'
|
26
|
+
- !ruby/object:YAML::Joust::Version20
|
27
|
+
expected: {}
|
28
|
+
- "Missing method":
|
29
|
+
- '{"jsonrpc": "2.0", "method": "notthere", "id": 5}'
|
30
|
+
- !ruby/object:YAML::Joust::Version20
|
31
|
+
expected: {error: {code: -32601, message: "Method not found."}, id: 5}
|
32
|
+
- "Invalid JSON":
|
33
|
+
- '{"jsonrpc": "2.0", "method": "foobar, "params": "bar", "baz]'
|
34
|
+
- !ruby/object:YAML::Joust::Version20
|
35
|
+
expected: {error: {code: -32700, message: "Parse error."}, id: ~}
|
36
|
+
- "Invalid JSON-RPC":
|
37
|
+
- '{"jsonrpc": "2.0", "method": 1, "params": "bar"}'
|
38
|
+
- !ruby/object:YAML::Joust::Version20
|
39
|
+
expected: {error: {code: -32600, message: "Invalid Request."}, id: ~}
|
40
|
+
- "Invalid batch JSON":
|
41
|
+
- '[ {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},{"jsonrpc": "2.0", "method" ]'
|
42
|
+
- !ruby/object:YAML::Joust::Version20
|
43
|
+
expected: {error: {code: -32700, message: "Parse error."}, id: ~}
|
44
|
+
- "Empty array":
|
45
|
+
- '[]'
|
46
|
+
- !ruby/object:YAML::Joust::Version20
|
47
|
+
expected: {error: {code: -32600, message: "Invalid Request."}, id: ~}
|
48
|
+
- "Invalid batch JSON-RPC (1/2)":
|
49
|
+
- '[1]'
|
50
|
+
-
|
51
|
+
- !ruby/object:YAML::Joust::Version20
|
52
|
+
expected: {error: {code: -32600, message: "Invalid Request."}, id: ~}
|
53
|
+
- "Invalid batch JSON-RPC (2/2)":
|
54
|
+
- '[1,2,3]'
|
55
|
+
-
|
56
|
+
- !ruby/object:YAML::Joust::Version20
|
57
|
+
expected: {error: {code: -32600, message: "Invalid Request."}, id: ~}
|
58
|
+
- !ruby/object:YAML::Joust::Version20
|
59
|
+
expected: {error: {code: -32600, message: "Invalid Request."}, id: ~}
|
60
|
+
- !ruby/object:YAML::Joust::Version20
|
61
|
+
expected: {error: {code: -32600, message: "Invalid Request."}, id: ~}
|
62
|
+
- "Batch call":
|
63
|
+
- >- [{"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": 1},
|
64
|
+
{"jsonrpc": "2.0", "method": "notify_hello", "params": [7]},
|
65
|
+
{"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": 2},
|
66
|
+
{"foo": "boo"},
|
67
|
+
{"jsonrpc": "2.0", "method": "notthere", "params": {"name": "myself"}, "id": 5},
|
68
|
+
{"jsonrpc": "2.0", "method": "get_data", "id": 9}]
|
69
|
+
-
|
70
|
+
- !ruby/object:YAML::Joust::Version20
|
71
|
+
expected: {result: 7, id: 1}
|
72
|
+
- !ruby/object:YAML::Joust::Version20
|
73
|
+
expected: {result: 19, id: 2}
|
74
|
+
- !ruby/object:YAML::Joust::Version20
|
75
|
+
expected: {error: {code: -32600, message: "Invalid Request."}, id: ~}
|
76
|
+
- !ruby/object:YAML::Joust::Version20
|
77
|
+
expected: {error: {code: -32601, message: "Method not found."}, id: 5}
|
78
|
+
- !ruby/object:YAML::Joust::Version20
|
79
|
+
expected: {result: ["hello", 5], id: 9}
|
80
|
+
- "Batch call (all notifications)":
|
81
|
+
- >- [{"jsonrpc": "2.0", "method": "notify_sum", "params": [1,2,4]},
|
82
|
+
{"jsonrpc": "2.0", "method": "notify_hello", "params": [7]}]
|
83
|
+
- !ruby/object:YAML::Joust::Version20
|
84
|
+
expected: {}
|
85
|
+
|
86
|
+
v1.2: # http://jsonrpc.org/historical/jsonrpc12_proposal.html#specification
|
87
|
+
- "Positional parameters (1/2)":
|
88
|
+
- '{"method": "subtract", "params": [42, 23], "id": 1}'
|
89
|
+
- !ruby/object:YAML::Joust::Version12
|
90
|
+
expected: {result: 19, error:~, id: 1}
|
91
|
+
- "Positional parameters (2/2)":
|
92
|
+
- '{"method": "subtract", "params": [23, 42], "id": 2}'
|
93
|
+
- !ruby/object:YAML::Joust::Version12
|
94
|
+
expected: {result: -19, error:~, id: 2}
|
95
|
+
- "Named parameters (1/2)":
|
96
|
+
- '{"method": "subtract_named", "params": {"subtrahend": 23, "minuend": 42}, "id": 3}'
|
97
|
+
- !ruby/object:YAML::Joust::Version12
|
98
|
+
expected: {result: 19, error:~, id: 3}
|
99
|
+
- "Named parameters (2/2)":
|
100
|
+
- '{"method": "subtract_named", "params": {"minuend": 42, "subtrahend": 23}, "id": 4}'
|
101
|
+
- !ruby/object:YAML::Joust::Version12
|
102
|
+
expected: {result: 19, error:~, id: 4}
|
103
|
+
- "Notification (1/2)":
|
104
|
+
- '{"method": "update", "params": [1,2,3,4,5], "id": null}'
|
105
|
+
- !ruby/object:YAML::Joust::Version12
|
106
|
+
expected: {}
|
107
|
+
- "Notification (2/2)":
|
108
|
+
- '{"method": "foobar", error:~, "id": null}'
|
109
|
+
- !ruby/object:YAML::Joust::Version12
|
110
|
+
expected: {}
|
111
|
+
- "Missing method":
|
112
|
+
- '{ "method": "notthere", "id": 5}'
|
113
|
+
- !ruby/object:YAML::Joust::Version12
|
114
|
+
expected: {result:~, error: {code: -32601, message: "Procedure not found."}, id: 5}
|
115
|
+
- "Invalid JSON":
|
116
|
+
- '{"method": "foobar, "params": "bar", "baz]'
|
117
|
+
- !ruby/object:YAML::Joust::Version12
|
118
|
+
expected: {result:~, error: {code: -32700, message: "Parse error."}, id: ~}
|
119
|
+
- "Invalid JSON-RPC (1/2)":
|
120
|
+
- '[1,2,3]'
|
121
|
+
- !ruby/object:YAML::Joust::Version12
|
122
|
+
expected: {result:~, error: {code: -32600, message: "Invalid JSON-RPC."}, id: ~}
|
123
|
+
- "Invalid JSON-RPC (2/2)":
|
124
|
+
- '{"method": 1, "params": "bar"}'
|
125
|
+
- !ruby/object:YAML::Joust::Version12
|
126
|
+
expected: {result:~, error: {code: -32600, message: "Invalid JSON-RPC."}, id: ~}
|
data/lib/joust.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'rest-client'
|
3
|
+
require File.join('joust','expected_response.rb')
|
4
|
+
require File.join('joust','expected_response','version_12.rb')
|
5
|
+
require File.join('joust','expected_response','version_20.rb')
|
6
|
+
|
7
|
+
class Joust
|
8
|
+
|
9
|
+
# run each version spec and return results
|
10
|
+
def self.run(url, options, test_cases)
|
11
|
+
specs = self.new(url, test_cases[options[:version]], options[:version])
|
12
|
+
puts specs.check
|
13
|
+
end
|
14
|
+
|
15
|
+
# initialize an instance to test a specific version
|
16
|
+
def initialize(url, test_cases, version)
|
17
|
+
@url, @test_cases, @version = url, test_cases, version
|
18
|
+
end
|
19
|
+
|
20
|
+
# run specification checks and return results
|
21
|
+
def check
|
22
|
+
num_tests = passed_tests = 0
|
23
|
+
results = @test_cases.map(&:flatten).inject([]) do |results, test|
|
24
|
+
test_name, sent, expected = test.first, test.last.first, test.last.last
|
25
|
+
resp = RestClient.post(@url, sent, :content_type => 'application/json')
|
26
|
+
num_tests += 1
|
27
|
+
json_hash = JSON.parse(resp.body) rescue {}
|
28
|
+
if expected.is_a?(Array)
|
29
|
+
pass = expected.inject(true) { |pass, exp| pass = false unless exp.match?(json_hash.shift); pass }
|
30
|
+
else
|
31
|
+
pass = expected.match?(json_hash)
|
32
|
+
end
|
33
|
+
if !!pass
|
34
|
+
passed_tests += 1
|
35
|
+
result_output = 'PASS'
|
36
|
+
else
|
37
|
+
result_output = 'FAIL: ' + resp.body
|
38
|
+
end
|
39
|
+
results << "#{@version} #{test_name} -- #{result_output}"
|
40
|
+
results
|
41
|
+
end
|
42
|
+
results << "JSON-RPC #{@version}: #{passed_tests}/#{num_tests} tests passed"
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Joust
|
2
|
+
class ExpectedResponse
|
3
|
+
|
4
|
+
def match?(json_hash)
|
5
|
+
['result', 'error', 'id'].each { |key| @expected[key] = :missing if !@expected.has_key?(key) }
|
6
|
+
if json_hash.empty?
|
7
|
+
return false unless @expected.values == [:missing, :missing, :missing]
|
8
|
+
return true
|
9
|
+
end
|
10
|
+
@expected.each do |key, val|
|
11
|
+
next if val == :missing && !json_hash.has_key?(key)
|
12
|
+
return false unless json_hash[key] == val
|
13
|
+
end
|
14
|
+
true
|
15
|
+
rescue Exception
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
data/spec/joust_spec.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Joust do
|
4
|
+
|
5
|
+
describe '.run' do
|
6
|
+
context 'given a target url, options, and a test case file' do
|
7
|
+
it 'creates a new instance if joust and runs the tests' do
|
8
|
+
fake_joust = double('joust')
|
9
|
+
fake_joust.should_receive(:check)
|
10
|
+
Joust.should_receive(:new).and_return(fake_joust)
|
11
|
+
Joust.run('http://url', {:foo => :bar}, {:version => :foo})
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#initialize' do
|
17
|
+
context 'given a target url, options, and a test case file' do
|
18
|
+
it 'creates a new instance of Joust' do
|
19
|
+
joust = Joust.new('http://url', {:foo => :bar}, {:version => :foo})
|
20
|
+
joust.should be_instance_of Joust
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#check' do
|
26
|
+
it 'runs the test cases' do
|
27
|
+
fake_resp = double('resp')
|
28
|
+
fake_resp.stub!(:body)
|
29
|
+
content_type = {:content_type => 'application/json'}
|
30
|
+
RestClient.should_receive(:post).with('url', 'sent', content_type).and_return(fake_resp)
|
31
|
+
fake_expected = double('expected')
|
32
|
+
fake_expected.should_receive(:is_a?).with(Array).and_return(false)
|
33
|
+
fake_expected.should_receive(:match?).with({}).and_return(true)
|
34
|
+
fake_test_cases = [{'test' => ['sent', fake_expected]}]
|
35
|
+
joust = Joust.new('url', fake_test_cases, 'v3.14')
|
36
|
+
results = joust.check
|
37
|
+
results.last.should == "JSON-RPC v3.14: 1/1 tests passed"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: joust
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- R. Scott Reis
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-14 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description:
|
15
|
+
email:
|
16
|
+
executables:
|
17
|
+
- joust
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files:
|
20
|
+
- README.rdoc
|
21
|
+
files:
|
22
|
+
- LICENSE.txt
|
23
|
+
- README.rdoc
|
24
|
+
- Rakefile
|
25
|
+
- bin/joust
|
26
|
+
- data/specifications.yml
|
27
|
+
- lib/joust/expected_response.rb
|
28
|
+
- lib/joust/expected_response/version_12.rb
|
29
|
+
- lib/joust/expected_response/version_20.rb
|
30
|
+
- lib/joust.rb
|
31
|
+
- spec/spec_helper.rb
|
32
|
+
- spec/joust_spec.rb
|
33
|
+
homepage: https://github.com/EvilScott/joust
|
34
|
+
licenses: []
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options:
|
37
|
+
- -m
|
38
|
+
- README.rdoc
|
39
|
+
- -t
|
40
|
+
- Joust
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
requirements: []
|
56
|
+
rubyforge_project:
|
57
|
+
rubygems_version: 1.8.18
|
58
|
+
signing_key:
|
59
|
+
specification_version: 3
|
60
|
+
summary: JSON-RPC Server Specification Compatibility Testing
|
61
|
+
test_files:
|
62
|
+
- spec/spec_helper.rb
|
63
|
+
- spec/joust_spec.rb
|