psc 0.0.1
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/.gitignore +13 -0
- data/.rvmrc +2 -0
- data/.yardopts +4 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +20 -0
- data/LICENSE +20 -0
- data/README.md +163 -0
- data/Rakefile +69 -0
- data/cucumber.yml +13 -0
- data/features/step_definitions/eval_steps.rb +14 -0
- data/features/step_definitions/setup_steps.rb +7 -0
- data/features/studies.feature +21 -0
- data/features/support/env.rb +33 -0
- data/features/support/int_psc.rb +165 -0
- data/int-psc/README-int-psc.md +57 -0
- data/int-psc/hsqldb/baseline.log +197 -0
- data/int-psc/hsqldb/baseline.properties +17 -0
- data/int-psc/hsqldb/baseline.script +295 -0
- data/int-psc/hsqldb/datasource.properties +18 -0
- data/int-psc/hsqldb/datasource.script +2205 -0
- data/int-psc/jetty/jetty-runner-7.4.0.v20110414.jar +0 -0
- data/int-psc/state/ABC 1200.xml +115 -0
- data/int-psc/state/int-psc-state.xml +64 -0
- data/lib/psc.rb +47 -0
- data/lib/psc/client.rb +35 -0
- data/lib/psc/connection.rb +96 -0
- data/lib/psc/faraday.rb +11 -0
- data/lib/psc/faraday/http_basic.rb +35 -0
- data/lib/psc/faraday/psc_token.rb +42 -0
- data/lib/psc/faraday/string_is_xml.rb +25 -0
- data/lib/psc/version.rb +3 -0
- data/meta.rakefile +30 -0
- data/psc.gemspec +33 -0
- data/spec/fixtures/studies-json.http +37 -0
- data/spec/middleware_helper.rb +18 -0
- data/spec/psc/client_spec.rb +39 -0
- data/spec/psc/connection_spec.rb +156 -0
- data/spec/psc/faraday/http_basic_spec.rb +15 -0
- data/spec/psc/faraday/psc_token_spec.rb +38 -0
- data/spec/psc/faraday/string_is_xml_spec.rb +49 -0
- data/spec/psc/version_spec.rb +11 -0
- data/spec/psc_spec.rb +16 -0
- data/spec/spec_helper.rb +15 -0
- data/tasks/int-psc.rake +84 -0
- data/tasks/psc/TODO +3 -0
- data/tasks/psc/state.rb +393 -0
- metadata +311 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'psc/faraday'
|
2
|
+
|
3
|
+
module Psc
|
4
|
+
module Faraday
|
5
|
+
##
|
6
|
+
# Middleware which sets the request content type to `text/xml` if
|
7
|
+
# the provided body is a `String` and the content type isn't
|
8
|
+
# already set.
|
9
|
+
class StringIsXml
|
10
|
+
def initialize(app)
|
11
|
+
@app = app
|
12
|
+
end
|
13
|
+
|
14
|
+
##
|
15
|
+
# Sets the content type request header if appropriate
|
16
|
+
def call(env)
|
17
|
+
if String === env[:body]
|
18
|
+
env[:request_headers]['Content-Type'] ||= 'text/xml'
|
19
|
+
end
|
20
|
+
|
21
|
+
@app.call(env)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/psc/version.rb
ADDED
data/meta.rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
PLATFORMS = {
|
2
|
+
:ruby18 => 'ruby-1.8.7-p334',
|
3
|
+
:jruby => 'jruby-1.6.1',
|
4
|
+
:ruby19 => 'ruby-1.9.2-p180'
|
5
|
+
}
|
6
|
+
|
7
|
+
BUNDLER_VERSION = '1.0.13'
|
8
|
+
|
9
|
+
def ci_env
|
10
|
+
(ENV["PSC_RB_ENV"] || :ruby18).to_sym
|
11
|
+
end
|
12
|
+
|
13
|
+
namespace :ci do
|
14
|
+
task :rvmrc do
|
15
|
+
puts "#{PLATFORMS[ci_env]}@psc-rb"
|
16
|
+
end
|
17
|
+
|
18
|
+
task :ensure_bundler_available do
|
19
|
+
unless Gem.available?('bundler', BUNDLER_VERSION)
|
20
|
+
puts "Installing bundler"
|
21
|
+
sh "gem install bundler -v '#{BUNDLER_VERSION}'"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
task :setup => [:ensure_bundler_available] do
|
26
|
+
sh "bundle _#{BUNDLER_VERSION}_ update"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
task :default => 'ci:setup'
|
data/psc.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "psc/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "psc"
|
7
|
+
s.version = Psc::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Rhett Sutphin"]
|
10
|
+
s.email = ["r-sutphin@northwestern.edu"]
|
11
|
+
s.homepage = "https://github.com/NUBIC/psc.rb"
|
12
|
+
s.summary = "A lightweight ruby client for Patient Study Calendar's RESTful HTTP API"
|
13
|
+
s.description = "A lightweight ruby client for Patient Study Calendar's RESTful HTTP API"
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_dependency 'faraday', '~> 0.7.0'
|
21
|
+
s.add_dependency 'builder', '>= 2.1.2'
|
22
|
+
s.add_dependency 'faraday-stack', '~> 0.1.1'
|
23
|
+
s.add_dependency 'nokogiri', '~> 1.4'
|
24
|
+
s.add_dependency 'activesupport', '>= 2.3' # for the JSON adapter
|
25
|
+
|
26
|
+
s.add_development_dependency 'rspec', '~> 2.6'
|
27
|
+
s.add_development_dependency 'ci_reporter', '~> 1.6'
|
28
|
+
s.add_development_dependency 'cucumber', '~> 0.10.2'
|
29
|
+
s.add_development_dependency 'childprocess', '~> 0.1'
|
30
|
+
s.add_development_dependency 'highline'
|
31
|
+
s.add_development_dependency 'webmock', '~> 1.6'
|
32
|
+
s.add_development_dependency 'yard', '~> 0.6.8'
|
33
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
HTTP/1.1 200 OK
|
2
|
+
Date: Mon, 16 May 2011 21:47:14 GMT
|
3
|
+
Server: Restlet-Framework/2.0.3
|
4
|
+
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
|
5
|
+
Pragma: no-cache
|
6
|
+
Accept-Ranges: bytes
|
7
|
+
Vary: Accept-Charset,Accept-Encoding,Accept-Language,Accept
|
8
|
+
Content-Type: application/json
|
9
|
+
Connection: close
|
10
|
+
Transfer-Encoding: chunked
|
11
|
+
|
12
|
+
{
|
13
|
+
"studies": [
|
14
|
+
{
|
15
|
+
"privileges": [
|
16
|
+
"develop",
|
17
|
+
"see-development",
|
18
|
+
"set-managing-sites",
|
19
|
+
"release",
|
20
|
+
"assign-identifiers",
|
21
|
+
"purge"
|
22
|
+
],
|
23
|
+
"assigned_identifier": "NU 1404"
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"privileges": [
|
27
|
+
"develop",
|
28
|
+
"see-development",
|
29
|
+
"set-managing-sites",
|
30
|
+
"release",
|
31
|
+
"assign-identifiers",
|
32
|
+
"purge"
|
33
|
+
],
|
34
|
+
"assigned_identifier": "ECOG 5607"
|
35
|
+
}
|
36
|
+
]
|
37
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
shared_context 'middleware' do
|
2
|
+
let(:app) { mock('app') }
|
3
|
+
let(:env) { { :request_headers => ::Faraday::Utils::Headers.new } }
|
4
|
+
let(:headers) { env[:request_headers] }
|
5
|
+
|
6
|
+
before { app.stub!(:call) }
|
7
|
+
|
8
|
+
def do_call
|
9
|
+
subject.call(env)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
shared_examples 'unconditional middleware' do
|
14
|
+
it 'continues the chain' do
|
15
|
+
app.should_receive(:call)
|
16
|
+
subject.call(env)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.expand_path("../../spec_helper.rb", __FILE__)
|
2
|
+
|
3
|
+
module Psc
|
4
|
+
describe Client do
|
5
|
+
let(:options) { { :authenticator => { :basic => %w(superuser superuser) } } }
|
6
|
+
let(:url) { 'http://psc.example.org/' }
|
7
|
+
let(:client) { Psc::Client.new(url, options) }
|
8
|
+
|
9
|
+
def mockable_uri(path)
|
10
|
+
URI.join(url.sub(%r{//}, '//superuser:superuser@'), "api/v1/#{path}").to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '.new' do
|
14
|
+
it 'creates a connection from a string and options' do
|
15
|
+
client.connection.should be_a(Psc::Connection)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'yields a connection builder if given a block' do
|
19
|
+
client = Psc::Client.new(url, options) do |builder|
|
20
|
+
builder.response :logger
|
21
|
+
end
|
22
|
+
client.connection.builder[-2].should == ::Faraday::Response::Logger
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#studies' do
|
27
|
+
before do
|
28
|
+
stub_request(:get, mockable_uri('studies.json')).
|
29
|
+
to_return(http_fixture('studies-json'))
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:actual) { client.studies }
|
33
|
+
|
34
|
+
it "has the data from the response" do
|
35
|
+
actual.first['assigned_identifier'].should == 'NU 1404'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require File.expand_path("../../spec_helper.rb", __FILE__)
|
2
|
+
|
3
|
+
module Psc
|
4
|
+
describe Connection do
|
5
|
+
let(:conn) {
|
6
|
+
Psc::Connection.new('http://psc.example.org/', options)
|
7
|
+
}
|
8
|
+
|
9
|
+
let(:options) {
|
10
|
+
{ :authenticator => { :basic => ['foo', 'bar'] } }
|
11
|
+
}
|
12
|
+
|
13
|
+
describe 'appending the API path' do
|
14
|
+
def actual_path_prefix(url)
|
15
|
+
Psc::Connection.new(url, options).path_prefix
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'is appended correctly if the URL ends with a slash' do
|
19
|
+
actual_path_prefix('http://psc.example.org/').should == '/api/v1'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'is appended correctly if the URL does not end with a slash' do
|
23
|
+
actual_path_prefix('http://psc.example.org').should == '/api/v1'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'is appended correctly if the URL has path info that ends with a slash' do
|
27
|
+
actual_path_prefix('http://www.example.net/psc/').should == '/psc/api/v1'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'is appended correctly if the URL has path info that does not end with a slash' do
|
31
|
+
actual_path_prefix('http://www.example.net/psc').should == '/psc/api/v1'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'is not appended if it is already there and it ends with a slash' do
|
35
|
+
actual_path_prefix('http://www.example.net/api/v1').should == '/api/v1'
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'is not appended if it is already there and it does not end with a slash' do
|
39
|
+
actual_path_prefix('http://www.example.net/api/v1/').should == '/api/v1'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
DEFAULT_MIDDLEWARE_COUNT = 6
|
44
|
+
|
45
|
+
describe 'the default middleware' do
|
46
|
+
it 'has the authentication middleware first' do
|
47
|
+
conn.builder[0].should == Psc::Faraday::HttpBasic
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'has the string-is-xml middleware next' do
|
51
|
+
conn.builder[1].should == Psc::Faraday::StringIsXml
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'has the Faraday JSON request middleware next' do
|
55
|
+
conn.builder[2].should == ::Faraday::Request::JSON
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'has the Faraday URL-encoded request middleware next' do
|
59
|
+
conn.builder[3].should == ::Faraday::Request::UrlEncoded
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'has the FaradayStack XML parser middleware next' do
|
63
|
+
conn.builder[4].should == ::FaradayStack::ResponseXML
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'has the FaradayStack JSON parser middleware next' do
|
67
|
+
conn.builder[5].should == ::FaradayStack::ResponseJSON
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'user-specified additional middleware' do
|
72
|
+
let(:custom_conn) {
|
73
|
+
Psc::Connection.new('http://psc.example.org/', options) do |builder|
|
74
|
+
builder.use ::Faraday::Response::Logger
|
75
|
+
end
|
76
|
+
}
|
77
|
+
|
78
|
+
it 'comes after the default middleware' do
|
79
|
+
custom_conn.builder[DEFAULT_MIDDLEWARE_COUNT].should == ::Faraday::Response::Logger
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'comes before the adapter' do
|
83
|
+
custom_conn.builder.handlers.last.should == ::Faraday::Adapter::NetHttp
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'selecting authentication middleware' do
|
88
|
+
let(:auth_middleware) { conn.builder[0] } # this is a Faraday::Builder::Handler
|
89
|
+
let(:auth_mw_args) { conn.builder[0].instance_eval { @args } }
|
90
|
+
|
91
|
+
context 'when :basic' do
|
92
|
+
before do
|
93
|
+
options[:authenticator] = { :basic => %w(foo bar) }
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'uses the HttpBasic middleware' do
|
97
|
+
auth_middleware.klass.should == Psc::Faraday::HttpBasic
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'provides the username and password to the middleware' do
|
101
|
+
auth_mw_args.should == %w(foo bar)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'when :token' do
|
106
|
+
before do
|
107
|
+
options[:authenticator] = { :token => lambda { 'foo' } }
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'uses the PscToken middleware' do
|
111
|
+
auth_middleware.klass.should == Psc::Faraday::PscToken
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'provides the token (or creator) to the middleware' do
|
115
|
+
auth_mw_args.first.call.should == 'foo'
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'when an unknown kind' do
|
120
|
+
before do
|
121
|
+
options[:authenticator] = { :quuxor => 7 }
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'raises an error' do
|
125
|
+
lambda { conn }.should raise_error('Unsupported authentication method :quuxor.')
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'when :authenticator not specified' do
|
130
|
+
before do
|
131
|
+
options.delete :authenticator
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'raises an error' do
|
135
|
+
lambda { conn }.should raise_error(
|
136
|
+
'No authentication method specified. Please include the :authenticator option.')
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe 'selecting an adapter' do
|
142
|
+
let(:adapter) { conn.builder.handlers.last }
|
143
|
+
|
144
|
+
it 'defaults to net/http' do
|
145
|
+
adapter.klass.should == ::Faraday::Adapter::NetHttp
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'uses the one the user provides if any' do
|
149
|
+
custom_conn = Connection.new('dc', options) do |builder|
|
150
|
+
builder.adapter :excon
|
151
|
+
end
|
152
|
+
custom_conn.builder.handlers.last.should == ::Faraday::Adapter::Excon
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.expand_path("../../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
module Psc::Faraday
|
4
|
+
describe HttpBasic do
|
5
|
+
include_context "middleware"
|
6
|
+
it_behaves_like "unconditional middleware"
|
7
|
+
|
8
|
+
subject { HttpBasic.new(app, 'jo', 'basil') }
|
9
|
+
|
10
|
+
it 'adds the appropriate Authorization header' do
|
11
|
+
do_call
|
12
|
+
headers['Authorization'].should == 'Basic am86YmFzaWw='
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.expand_path("../../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
module Psc::Faraday
|
4
|
+
describe PscToken do
|
5
|
+
include_context "middleware"
|
6
|
+
|
7
|
+
describe "with a static token" do
|
8
|
+
it_behaves_like "unconditional middleware"
|
9
|
+
|
10
|
+
subject { PscToken.new(app, 'jo-9') }
|
11
|
+
|
12
|
+
it 'adds the appropriate Authorization header' do
|
13
|
+
do_call
|
14
|
+
headers['Authorization'].should == 'psc_token jo-9'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "with a dynamic token" do
|
19
|
+
it_behaves_like "unconditional middleware"
|
20
|
+
|
21
|
+
subject do
|
22
|
+
i = 7
|
23
|
+
PscToken.new(app, lambda { i += 1; i ** 2 })
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'adds the appropriate Authorization header' do
|
27
|
+
do_call
|
28
|
+
headers['Authorization'].should == 'psc_token 64'
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'invokes the lambda for each call' do
|
32
|
+
do_call
|
33
|
+
do_call
|
34
|
+
headers['Authorization'].should == 'psc_token 81'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.expand_path('../../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
module Psc::Faraday
|
4
|
+
describe StringIsXml do
|
5
|
+
include_context 'middleware'
|
6
|
+
|
7
|
+
subject { StringIsXml.new(app) }
|
8
|
+
|
9
|
+
before do
|
10
|
+
env[:body] = '<foo/>'
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'treats a string body as text/xml' do
|
14
|
+
do_call
|
15
|
+
headers['Content-Type'].should == 'text/xml'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'leaves a Hash body alone' do
|
19
|
+
env[:body] = { 'foo' => 'bar' }
|
20
|
+
do_call
|
21
|
+
headers['Content-Type'].should be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'does nothing if the content type is already set' do
|
25
|
+
headers['Content-Type'] = 'application/vnd.sun.wadl+xml'
|
26
|
+
do_call
|
27
|
+
headers['Content-Type'].should == 'application/vnd.sun.wadl+xml'
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'in the same stack as Faraday::Request::JSON' do
|
31
|
+
let(:conn) do
|
32
|
+
::Faraday::Connection.new('http://example.org/') do |builder|
|
33
|
+
builder.use StringIsXml
|
34
|
+
builder.use ::Faraday::Request::JSON
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'sets the content type for a string body' do
|
39
|
+
response = conn.put('dc', '<foo/>')
|
40
|
+
response.env[:request_headers]['Content-Type'].should == 'text/xml'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'does not interfere with the JSON middleware for a Hash body' do
|
44
|
+
response = conn.put('dc', { 'bar' => 'baz' })
|
45
|
+
response.env[:request_headers]['Content-Type'].should == 'application/json'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|