vidibus-service 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|