vidibus-service 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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,5 @@
1
+ require "spec_helper"
2
+
3
+ describe "Vidibus::Service::ControllerValidations" do
4
+ it "should be spec'd"
5
+ 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