vidibus-service 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/.bundle/config +2 -0
- data/.document +5 -0
- data/.gitignore +21 -0
- data/.rspec +2 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +135 -0
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +42 -0
- data/VERSION +1 -0
- data/app/models/service.rb +4 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +5 -0
- data/lib/vidibus/service/client.rb +66 -0
- data/lib/vidibus/service/connector_app.rb +154 -0
- data/lib/vidibus/service/controller_validations.rb +35 -0
- data/lib/vidibus/service/mongoid.rb +130 -0
- data/lib/vidibus/service.rb +15 -0
- data/lib/vidibus-service.rb +14 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/vidibus/service/client_spec.rb +73 -0
- data/spec/vidibus/service/connector_app_spec.rb +246 -0
- data/spec/vidibus/service/controller_validations_spec.rb +5 -0
- data/spec/vidibus/service/mongoid_spec.rb +226 -0
- data/spec/vidibus/service_spec.rb +14 -0
- data/vidibus-service.gemspec +92 -0
- metadata +199 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
module Vidibus # :nodoc
|
2
|
+
module Service # :nodoc
|
3
|
+
class Error < StandardError; end
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
require "service/client"
|
8
|
+
require "service/mongoid"
|
9
|
+
require "service/connector_app"
|
10
|
+
require "service/controller_validations"
|
11
|
+
|
12
|
+
# Shorthand for Service.discover
|
13
|
+
def Service(wanted, realm)
|
14
|
+
Service.discover(wanted, realm)
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# require "rails"
|
2
|
+
require "vidibus-secure"
|
3
|
+
require "vidibus-validate_uri"
|
4
|
+
require "vidibus-uuid"
|
5
|
+
require "vidibus-core_extensions"
|
6
|
+
|
7
|
+
$:.unshift(File.join(File.dirname(__FILE__), "vidibus"))
|
8
|
+
require "service"
|
9
|
+
|
10
|
+
if defined?(Rails)
|
11
|
+
module Vidibus::Service
|
12
|
+
class Engine < ::Rails::Engine; end
|
13
|
+
end
|
14
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
3
|
+
|
4
|
+
require "rubygems"
|
5
|
+
require "active_support/core_ext"
|
6
|
+
require "rspec"
|
7
|
+
require "rr"
|
8
|
+
require "mongoid"
|
9
|
+
require "webmock/rspec"
|
10
|
+
|
11
|
+
require "vidibus-service"
|
12
|
+
require "app/models/service"
|
13
|
+
|
14
|
+
Mongoid.configure do |config|
|
15
|
+
name = "vidibus-service_test"
|
16
|
+
host = "localhost"
|
17
|
+
config.master = Mongo::Connection.new.db(name)
|
18
|
+
config.logger = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
RSpec.configure do |config|
|
22
|
+
config.include WebMock
|
23
|
+
config.mock_with :rr
|
24
|
+
config.before(:each) do
|
25
|
+
Mongoid.master.collections.select {|c| c.name !~ /system/}.each(&:drop)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
I18n.load_path += Dir[File.join('config', 'locales', '**', '*.{rb,yml}')]
|
30
|
+
|
31
|
+
#ENV["VIDIBUS_SECURE_KEY"] = "c4l60HC/lyerr2VEnrP7s2YAldyZGfIBePUzCl+tBsTs1EWJOc8dEJ7F2Vty7KPEeRuBWGxZHVAbku8pLo+UvXRpLcRiF7lxKiKl"
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Vidibus::Service::Client do
|
4
|
+
let(:this) {Service.create!(:function => "manager", :url => "http://manager.local", :uuid => "973a8710926e012d0a8c58b035f038ab", :secret => "EaDai5nz16DbQTWQuuFdd4WcAiZYRPDwZTn2IQeXbPE4yBg3rr", :this => true, :realm_uuid => nil)}
|
5
|
+
let(:uploader) {Service.create!(:function => "uploader", :url => "http://uploader.local", :uuid => "ddeb4500668e012d47bb58b035f038ab", :secret => "XaDai5nz1sDbQTWQuuFdd4WcAiZYRPDwZTn2IQeXbPE4yBg3rr", :realm_uuid => "e33f0d9093f9012d0dbc58b035f038ab")}
|
6
|
+
let(:client) { this; Vidibus::Service::Client.new(uploader) }
|
7
|
+
|
8
|
+
describe "#initialize" do
|
9
|
+
it "should require a service object" do
|
10
|
+
expect { Vidibus::Service::Client.new(:uploader) }.should raise_error(Vidibus::Service::Client::ServiceError)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should require this" do
|
14
|
+
expect { Vidibus::Service::Client.new(uploader) }.should raise_error(Service::ConfigurationError)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should set URL of given service as base_uri" do
|
18
|
+
this
|
19
|
+
client = Vidibus::Service::Client.new(uploader)
|
20
|
+
client.base_uri.should eql(uploader.url)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#get" do
|
25
|
+
it "should load data via GET" do
|
26
|
+
stub_http_request(:get, "http://uploader.local/success").
|
27
|
+
with(:query => {:realm => uploader.realm_uuid, :service => this.uuid, :sign => "43a4d004c55113131f198c9772760467727b5564de74aacfcf4686751e3d388a"}).
|
28
|
+
to_return(:status => 200, :body => %({"hot":"stuff"}))
|
29
|
+
response = client.get("/success")
|
30
|
+
response.code.should eql(200)
|
31
|
+
response.should eql({"hot" => "stuff"})
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should handle non-JSON responses" do
|
35
|
+
stub_http_request(:get, "http://uploader.local/success").
|
36
|
+
with(:query => {:realm => uploader.realm_uuid, :service => this.uuid, :sign => "43a4d004c55113131f198c9772760467727b5564de74aacfcf4686751e3d388a"}).
|
37
|
+
to_return(:status => 200, :body => "something")
|
38
|
+
response = client.get("/success")
|
39
|
+
response.code.should eql(200)
|
40
|
+
response.should eql("something")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#post" do
|
45
|
+
it "should send data via POST" do
|
46
|
+
stub_http_request(:post, "http://uploader.local/create").
|
47
|
+
with(:body => {:some => "thing", :realm => uploader.realm_uuid, :service => this.uuid, :sign => "9c16bc080f106c73f28813f02899be97301b1b627d25a65d52f68a3c9732559d"}).
|
48
|
+
to_return(:status => 200)
|
49
|
+
response = client.post("/create", :body => {:some => "thing"})
|
50
|
+
response.code.should eql(200)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#put" do
|
55
|
+
it "should send data via PUT" do
|
56
|
+
stub_http_request(:put, "http://uploader.local/update").
|
57
|
+
with(:body => {:some => "thing", :realm => uploader.realm_uuid, :service => this.uuid, :sign => "57e75433e49d9ef160b03b9e6a7d91fbd6523471eb8e7e36bb861066101f0903"}).
|
58
|
+
to_return(:status => 200)
|
59
|
+
response = client.put("/update", :body => {:some => "thing"})
|
60
|
+
response.code.should eql(200)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#delete" do
|
65
|
+
it "should send a DELETE request" do
|
66
|
+
stub_http_request(:delete, "http://uploader.local/record/123").
|
67
|
+
with(:query => {:realm => uploader.realm_uuid, :service => this.uuid, :sign => "b9c026563d950a719e168c6f072f75c13f4843b82274f57f6e5a9a4cd8e0cc64"}).
|
68
|
+
to_return(:status => 200)
|
69
|
+
response = client.delete("/record/123")
|
70
|
+
response.code.should eql(200)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,246 @@
|
|
1
|
+
require "spec_helper.rb"
|
2
|
+
|
3
|
+
describe "Vidibus::Service::ConnectorApp" do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
|
6
|
+
let(:this_params) { {"uuid" => "344b4b8088fb012dd3e558b035f038ab", "url" => "http://manager.local", "function" => "manager"} }
|
7
|
+
let(:connector_params) { {"uuid" => "60dfef509a8e012d599558b035f038ab", "url" => "https://connector.local"} }
|
8
|
+
let(:this) { Service.create!(this_params.merge(:secret => "EaDai5nz16DbQTWQuuFdd4WcAiZYRPDwZTn2IQeXbPE4yBg3rr", :realm_uuid => nil, :this => true)) }
|
9
|
+
let(:connector) { Service.create!(connector_params.merge(:function => "connector", :secret => nil, :realm_uuid => nil)) }
|
10
|
+
|
11
|
+
def app
|
12
|
+
@app ||= Vidibus::Service::ConnectorApp
|
13
|
+
end
|
14
|
+
|
15
|
+
# Sends a signed request.
|
16
|
+
def signed_request(method, url, params = nil)
|
17
|
+
self.send(method, *Vidibus::Secure.sign_request(method, url, params, this.secret))
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should fail for request methods other than GET, POST, PUT, and DELETE" do
|
21
|
+
head "http://manager.local/connector"
|
22
|
+
last_response.status.should eql(400)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should fail for paths other than /connector" do
|
26
|
+
get "http://manager.local/something"
|
27
|
+
last_response.status.should eql(400)
|
28
|
+
last_response.body.should eql(%({"error":"This app must be configured to respond to /connector path."}))
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "GET requests" do
|
32
|
+
it "should fail without signature" do
|
33
|
+
this and connector
|
34
|
+
get "http://manager.local/connector"
|
35
|
+
last_response.status.should eql(400)
|
36
|
+
last_response.body.should eql(%({"error":"Invalid signature."}))
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should fail without valid signature" do
|
40
|
+
this and connector
|
41
|
+
get "http://manager.local/connector?sign=xxx"
|
42
|
+
last_response.status.should eql(400)
|
43
|
+
last_response.body.should eql(%({"error":"Invalid signature."}))
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should fail without this service" do
|
47
|
+
connector
|
48
|
+
get "http://manager.local/connector"
|
49
|
+
last_response.status.should eql(400)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should return public data of this service as JSON" do
|
53
|
+
this
|
54
|
+
signed_request(:get, "http://manager.local/connector")
|
55
|
+
last_response.body.should eql({:this => this.public_data}.to_json)
|
56
|
+
last_response.status.should eql(200)
|
57
|
+
last_response.content_type.should eql("text/javascript; charset=utf-8")
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should also return public data of connector as JSON, if a connector is given" do
|
61
|
+
this and connector
|
62
|
+
signed_request(:get, "http://manager.local/connector")
|
63
|
+
last_response.body.should eql({:this => this.public_data, :connector => connector.public_data}.to_json)
|
64
|
+
last_response.content_type.should eql("text/javascript; charset=utf-8")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "POST requests" do
|
69
|
+
it "should fail if this service has already been set up" do
|
70
|
+
this
|
71
|
+
post "http://manager/connector", {}
|
72
|
+
last_response.status.should eql(400)
|
73
|
+
last_response.body.should eql(%({"error":"Service has already been set up."}))
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should require Connector params" do
|
77
|
+
post "http://manager.local/connector"
|
78
|
+
last_response.status.should eql(400)
|
79
|
+
last_response.body.should eql(%({"error":"No Connector data given."}))
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should fail if Connector data is invalid" do
|
83
|
+
post "http://manager.local/connector", {:connector => {:some => "thing"}}
|
84
|
+
last_response.status.should eql(400)
|
85
|
+
last_response.body.should match("Setting up the Connector failed:")
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should set up a Connector" do
|
89
|
+
mock(::Service).new(connector_params.merge(:function => "connector"))
|
90
|
+
expect {
|
91
|
+
post "http://manager.local/connector", {:connector => connector_params}
|
92
|
+
}.to raise_error(NoMethodError, "undefined method `save' for nil:NilClass")
|
93
|
+
end
|
94
|
+
|
95
|
+
context "with Connector or Connector params" do
|
96
|
+
before { connector }
|
97
|
+
|
98
|
+
it "should not require Connector params if a Connector is present" do
|
99
|
+
post "http://manager.local/connector"
|
100
|
+
last_response.body.should_not eql(%({"error":"No Connector data given."}))
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should require params for this service" do
|
104
|
+
post "http://manager.local/connector"
|
105
|
+
last_response.status.should eql(400)
|
106
|
+
last_response.body.should eql(%({"error":"No data for this service given."}))
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should fail if params for this service are invalid" do
|
110
|
+
post "http://manager.local/connector", {:this => {:some => "thing"}}
|
111
|
+
last_response.status.should eql(400)
|
112
|
+
last_response.body.should match("Setting up this service failed:")
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should set up this Service" do
|
116
|
+
mock(::Service).new(this_params.merge(:this => true))
|
117
|
+
expect {
|
118
|
+
post "http://manager.local/connector", {:this => this_params}
|
119
|
+
}.to raise_error(NoMethodError, "undefined method `secret=' for nil:NilClass")
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should request a secret for this Service" do
|
123
|
+
uri = "https://connector.local/services/#{this_params["uuid"]}/secret"
|
124
|
+
stub_http_request(:get, uri).to_return(:status => 200)
|
125
|
+
post "http://manager.local/connector", {:this => this_params}
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should require a valid nonce to decrypt requested secret" do
|
129
|
+
uri = "https://connector.local/services/#{this_params["uuid"]}/secret"
|
130
|
+
params = {}
|
131
|
+
stub_http_request(:get, uri).to_return(:status => 200, :body => %({"secret":"something","sign":"else"}))
|
132
|
+
post "http://manager.local/connector", {:this => this_params.merge("nonce" => "invalid")}
|
133
|
+
last_response.status.should eql(400)
|
134
|
+
last_response.body.should match("Nonce is invalid.")
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should decrypt requested secret and store it on the service object" do
|
138
|
+
nonce = "hkO2ssb28Gks19s9h2hdhbBs83hdis"
|
139
|
+
secret = "EaDai5nz16DbQTWQuuFdd4WcAiZYRPDwZTn2IQeXbPE4yBg3rr"
|
140
|
+
encrypted_secret = Vidibus::Secure.encrypt(secret, nonce)
|
141
|
+
signature = Vidibus::Secure.sign(encrypted_secret, nonce)
|
142
|
+
uri = "https://connector.local/services/#{this_params["uuid"]}/secret"
|
143
|
+
params = {:secret => encrypted_secret, :sign => signature}
|
144
|
+
stub_http_request(:get, uri).to_return(:status => 200, :body => params.to_json)
|
145
|
+
post "http://manager.local/connector", {:this => this_params.merge("nonce" => nonce)}
|
146
|
+
last_response.status.should eql(201)
|
147
|
+
this = ::Service.where(:this => true).first
|
148
|
+
this.should be_a(::Service)
|
149
|
+
this.secret.should eql(secret)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "PUT requests" do
|
155
|
+
it "should fail without signature" do
|
156
|
+
this and connector
|
157
|
+
put "http://manager.local/connector"
|
158
|
+
last_response.status.should eql(400)
|
159
|
+
last_response.body.should eql(%({"error":"Invalid signature."}))
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should fail without valid signature" do
|
163
|
+
this and connector
|
164
|
+
put "http://manager.local/connector?sign=xxx"
|
165
|
+
last_response.status.should eql(400)
|
166
|
+
last_response.body.should eql(%({"error":"Invalid signature."}))
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should succeed with valid signature" do
|
170
|
+
this and connector
|
171
|
+
signed_request(:put, "http://manager.local/connector")
|
172
|
+
last_response.status.should eql(200)
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should fail if this service is unconfigured" do
|
176
|
+
get "http://manager.local/connector?sign=jkasdnkajdb"
|
177
|
+
last_response.status.should eql(400)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should update existing services" do
|
181
|
+
this and connector
|
182
|
+
url = "http://newconnector.local"
|
183
|
+
signed_request(:put, "http://manager.local/connector", {:connector => {:url => url}})
|
184
|
+
last_response.status.should eql(200)
|
185
|
+
Service.local(:connector).url.should eql(url)
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should fail if invalid data are given" do
|
189
|
+
this and connector
|
190
|
+
url = "http://newconnector.local"
|
191
|
+
signed_request(:put, "http://manager.local/connector", {:connector => {:secret => "not allowed"}})
|
192
|
+
last_response.status.should eql(400)
|
193
|
+
last_response.body.should match("Updating connector failed:")
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should create new services" do
|
197
|
+
this and connector
|
198
|
+
url = "http://newconnector.local"
|
199
|
+
signed_request(:put, "http://manager.local/connector",
|
200
|
+
{:uploader => {:url => "http://uploader.local", :uuid => "c0861d609247012d0a8b58b035f038ab", :secret => "A7q8Vzxgrk9xrw2FCnvV4bv01UP/LBUUM0lIGDmMcB2GsBTIqx", :realm_uuid => "12ab69f099a4012d4df558b035f038ab"}})
|
201
|
+
last_response.status.should eql(200)
|
202
|
+
Service.local(:uploader, "12ab69f099a4012d4df558b035f038ab").url.should eql("http://uploader.local")
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe "DELETE requests" do
|
207
|
+
it "should fail without signature" do
|
208
|
+
this and connector
|
209
|
+
delete "http://manager.local/connector"
|
210
|
+
last_response.status.should eql(400)
|
211
|
+
last_response.body.should eql(%({"error":"Invalid signature."}))
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should fail without valid signature" do
|
215
|
+
this and connector
|
216
|
+
delete "http://manager.local/connector?sign=xxx"
|
217
|
+
last_response.status.should eql(400)
|
218
|
+
last_response.body.should eql(%({"error":"Invalid signature."}))
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should fail if this service is unconfigured" do
|
222
|
+
delete "http://manager.local/connector?sign=jkasdnkajdb"
|
223
|
+
last_response.status.should eql(400)
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should fail if list of UUIDs is not given" do
|
227
|
+
this and connector
|
228
|
+
signed_request(:delete, "http://manager.local/connector", {})
|
229
|
+
last_response.status.should eql(400)
|
230
|
+
last_response.body.should eql(%({"error":"Provide list of :uuids"}))
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should delete services given by UUID" do
|
234
|
+
this and connector
|
235
|
+
signed_request(:delete, "http://manager.local/connector", {:uuids =>["60dfef509a8e012d599558b035f038ab"]})
|
236
|
+
last_response.status.should eql(200)
|
237
|
+
Service.local(:connector).should be_nil
|
238
|
+
end
|
239
|
+
|
240
|
+
it "should not care if any given UUID is invalid" do
|
241
|
+
this and connector
|
242
|
+
signed_request(:delete, "http://manager.local/connector", {:uuids =>["invalid", "60dfef509a8e012d599558b035f038ab"]})
|
243
|
+
last_response.status.should eql(200)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Vidibus::Service::Mongoid" do
|
4
|
+
let(:realm) { "12ab69f099a4012d4df558b035f038ab" }
|
5
|
+
let(:this) { Service.create!(:function => "manager", :url => "http://manager.local", :uuid => "344b4b8088fb012dd3e558b035f038ab", :secret => "EaDai5nz16DbQTWQuuFdd4WcAiZYRPDwZTn2IQeXbPE4yBg3rr", :realm_uuid => nil, :this => true) }
|
6
|
+
let(:connector) { Service.create!(:function => "connector", :url => "http://connector.local", :uuid => "60dfef509a8e012d599558b035f038ab", :secret => nil, :realm_uuid => nil) }
|
7
|
+
let(:uploader) { Service.create!(:function => "uploader", :url => "http://uploader.local", :uuid => "c0861d609247012d0a8b58b035f038ab", :secret => "A7q8Vzxgrk9xrw2FCnvV4bv01UP/LBUUM0lIGDmMcB2GsBTIqx", :realm_uuid => realm) }
|
8
|
+
let(:client_mock) { this; mock.any_instance_of(Vidibus::Service::Client) }
|
9
|
+
|
10
|
+
describe "validation" do
|
11
|
+
it "should pass with valid attributes" do
|
12
|
+
this.should be_valid
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should fail without a valid URL" do
|
16
|
+
this.url = "something"
|
17
|
+
this.should be_invalid
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should fail without a function" do
|
21
|
+
this.function = ""
|
22
|
+
this.should be_invalid
|
23
|
+
this.errors[:function].should have(1).error
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should pass with arbitrary functions" do
|
27
|
+
this.function = :something
|
28
|
+
this.should be_valid
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should fail if a secret is given for Connector" do
|
32
|
+
connector.secret = "something"
|
33
|
+
connector.should be_invalid
|
34
|
+
connector.errors[:secret].should have(1).error
|
35
|
+
connector.errors[:secret].first.should eql("is not allowed for a Connector")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should pass with empty secret for Connector" do
|
39
|
+
connector.secret = nil
|
40
|
+
connector.should be_valid
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should fail without a secret for services except Connector" do
|
44
|
+
uploader.secret = nil
|
45
|
+
uploader.should be_invalid
|
46
|
+
uploader.errors[:secret].should have(1).error
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should fail without a realm_uuid for services except Connector and this" do
|
50
|
+
uploader.realm_uuid = nil
|
51
|
+
uploader.should be_invalid
|
52
|
+
uploader.errors[:realm_uuid].should have(1).error
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should pass with empty realm_uuid for Connector" do
|
56
|
+
connector.realm_uuid = nil
|
57
|
+
connector.should be_valid
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should pass if realm_uuid is given for Connector" do
|
61
|
+
connector.realm_uuid = realm
|
62
|
+
connector.should be_valid
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should pass if a realm_uuid is given for this" do
|
66
|
+
this.realm_uuid = realm
|
67
|
+
this.should be_valid
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should fail for duplicate UUIDs within same realm" do
|
71
|
+
duplicate_service = Service.new(:uuid => uploader.uuid, :realm_uuid => realm)
|
72
|
+
duplicate_service.should be_invalid
|
73
|
+
duplicate_service.errors[:uuid].should have(1).error
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#url" do
|
78
|
+
it "should be set without trailing slash" do
|
79
|
+
this.url = "http://manager.local/"
|
80
|
+
this.url.should eql("http://manager.local")
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should be stored without trailing slash" do
|
84
|
+
this.update_attributes(:url => "http://manager.local/")
|
85
|
+
this.reload.url.should eql("http://manager.local")
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "#domain" do
|
90
|
+
it "should return the url without protocol" do
|
91
|
+
this.domain.should eql(this.url.gsub(/https?:\/\//, ""))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "#connector?" do
|
96
|
+
it "should return true if service is a Connector" do
|
97
|
+
connector.connector?.should be_true
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should return false if service is not a Connector" do
|
101
|
+
uploader.connector?.should be_false
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#get" do
|
106
|
+
it "should trigger a GET request" do
|
107
|
+
client_mock.get("/something", :query => { :gotta => "give" })
|
108
|
+
uploader.get("/something", :query => { :gotta => "give" })
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "#post" do
|
113
|
+
it "should trigger a POST request" do
|
114
|
+
client_mock.post("/something", :query => { :do => "it" })
|
115
|
+
uploader.post("/something", :query => { :do => "it" })
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "#put" do
|
120
|
+
it "should trigger a PUT request" do
|
121
|
+
client_mock.put("/something", :query => { :new => "stuff" })
|
122
|
+
uploader.put("/something", :query => { :new => "stuff" })
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "#delete" do
|
127
|
+
it "should trigger a DELETE request" do
|
128
|
+
client_mock.delete("/something/else", {})
|
129
|
+
uploader.delete("/something/else")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe ".this" do
|
134
|
+
it "should return this service" do
|
135
|
+
this
|
136
|
+
Service.this.should eql(this)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should raise an error if this service has not been configured yet" do
|
140
|
+
expect {Service.this}.to raise_error(Service::ConfigurationError)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe ".connector" do
|
145
|
+
it "should return the Connector" do
|
146
|
+
connector
|
147
|
+
Service.connector.should eql(connector)
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should raise an error if the Connector has not been configured yet" do
|
151
|
+
expect {Service.connector}.to raise_error(Service::ConfigurationError)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe ".local" do
|
156
|
+
before {uploader}
|
157
|
+
|
158
|
+
it "should return a service matching given function without a realm" do
|
159
|
+
connector
|
160
|
+
Service.local(:connector).should eql(connector)
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should return a service matching given function and realm" do
|
164
|
+
Service.local(:uploader, realm).should eql(uploader)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should return no service if it does not match given realm" do
|
168
|
+
Service.local(:uploader).should be_nil
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should return no service if it does not match given function" do
|
172
|
+
Service.local(:connector, realm).should be_nil
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should return a service matching given UUID and realm" do
|
176
|
+
Service.local(uploader.uuid, realm).should eql(uploader)
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should return no service if it does not match given function" do
|
180
|
+
Service.local("123", realm).should be_nil
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe ".discover" do
|
185
|
+
it "should first try to find a local service" do
|
186
|
+
uploader
|
187
|
+
mock(Service).local(:uploader, realm) {uploader}
|
188
|
+
dont_allow(Service).remote(:uploader, realm)
|
189
|
+
Service.discover(:uploader, realm).should eql(uploader)
|
190
|
+
end
|
191
|
+
|
192
|
+
it "if no local service can be found a remote one should be fetched" do
|
193
|
+
mock(Service).local(:uploader, realm) {nil}
|
194
|
+
mock(Service).remote(:uploader, realm) {uploader}
|
195
|
+
Service.discover(:uploader, realm).should eql(uploader)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
describe ".remote" do
|
200
|
+
it "should require a realm" do
|
201
|
+
expect {Service.remote(:uploader, nil)}.to raise_error(ArgumentError)
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should fetch service data from Connector and create a local service object" do
|
205
|
+
connector and this
|
206
|
+
stub_http_request(:get, "http://connector.local/services/uploader").
|
207
|
+
with(:query => {:realm => "12ab69f099a4012d4df558b035f038ab", :service => "344b4b8088fb012dd3e558b035f038ab", :sign => "d27be37e9440765d38789f9000a5b3a86c741b3954c88f7b1769e4067ac9fbd0"}).
|
208
|
+
to_return(:status => 200, :body => %({"uuid":"c0861d609247012d0a8b58b035f038ab", "url":"http://uploader.local", "function":"uploader", "secret":"kjO8AjgX68Yp7OQ1XF8dTfPBE5GCuCnd/OPko+A9yCaw8qnj9xoyMGZEXQpf\niVBOUcux1qlW8hfT6UPKGoVfYA==\n"}))
|
209
|
+
Service.remote(:uploader, realm)
|
210
|
+
|
211
|
+
uploader = Service.local(:uploader, realm)
|
212
|
+
uploader.uuid.should eql("c0861d609247012d0a8b58b035f038ab")
|
213
|
+
uploader.function.should eql("uploader")
|
214
|
+
uploader.url.should eql("http://uploader.local")
|
215
|
+
uploader.secret.should eql(Vidibus::Secure.decrypt("kjO8AjgX68Yp7OQ1XF8dTfPBE5GCuCnd/OPko+A9yCaw8qnj9xoyMGZEXQpf\niVBOUcux1qlW8hfT6UPKGoVfYA==\n", this.secret))
|
216
|
+
end
|
217
|
+
|
218
|
+
it "should raise an error requested service has already been stored" do
|
219
|
+
connector and this and uploader
|
220
|
+
stub_http_request(:get, "http://connector.local/services/uploader").
|
221
|
+
with(:query => {:realm => "e75234809111012d05ac58b035f038ab", :service => "973a8710926e012d0a8c58b035f038ab", :sign => "a93d3a1a0124e969f97d68feab37638ec8737b1d8ddc582cd204fbb228ad7e2b"}).
|
222
|
+
to_return(:status => 200, :body => %({"uuid":"c0861d609247012d0a8b58b035f038ab", "url":"http://uploader.local", "function":"uploader", "secret":"kjO8AjgX68Yp7OQ1XF8dTfPBE5GCuCnd/OPko+A9yCaw8qnj9xoyMGZEXQpf\niVBOUcux1qlW8hfT6UPKGoVfYA==\n"}))
|
223
|
+
expect { Service.remote(:uploader, realm) }.to raise_error
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Vidibus::Service::Error" do
|
4
|
+
it "should be derived from StandardError" do
|
5
|
+
Vidibus::Service::Error.superclass.should eql(StandardError)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "Service" do
|
10
|
+
it "should be a shorthand for Service.discover" do
|
11
|
+
mock(Service).discover(:uploader, "realm")
|
12
|
+
Service(:uploader, "realm")
|
13
|
+
end
|
14
|
+
end
|