farscape 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/Gemfile.lock +52 -68
- data/README.md +35 -19
- data/lib/farscape/agent.rb +32 -7
- data/lib/farscape/discovery.rb +32 -0
- data/lib/farscape/platform_resources.rb +95 -0
- data/lib/farscape/version.rb +1 -1
- data/spec/lib/farscape/agent_spec.rb +26 -0
- data/spec/lib/farscape/integration/entry_point_spec.rb +36 -0
- data/spec/lib/farscape/plugins_spec.rb +0 -1
- data/spec/spec_helper.rb +6 -0
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42ff32e415677a4ca1cb6419518d7cbf78a6df1c
|
4
|
+
data.tar.gz: 2f7d3081526f4e913c7b4d66f35378db2212de31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a45910ae4df9afafafa01805c07de5948c5a912367f5ee184b870d26167b75710d2c49055cd34d08fbaae804be542c683fc42c41d409e30007bfc44343b1fcd0
|
7
|
+
data.tar.gz: 8ee0a64cefcad9ecfc1e4c50c7f295031467b84846920baf1baffa1a3391dda3fead82eeda67144c78511cf41a8f922caf44c4a49fade8ad1a1fd395dd8324b5
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,14 +1,5 @@
|
|
1
1
|
GIT
|
2
|
-
remote:
|
3
|
-
revision: 958dc778d62897f09dd0200f3690f96cb5265b98
|
4
|
-
branch: 0-0-stable
|
5
|
-
specs:
|
6
|
-
representors (0.0.3)
|
7
|
-
addressable (~> 2.3)
|
8
|
-
rake
|
9
|
-
|
10
|
-
GIT
|
11
|
-
remote: https://www.github.com/mdsol-share/crichton.git
|
2
|
+
remote: https://github.com/mdsol-share/crichton.git
|
12
3
|
revision: 63c74ce781a41538454b81fd8c44dc36117aa92b
|
13
4
|
branch: develop
|
14
5
|
specs:
|
@@ -24,7 +15,7 @@ GIT
|
|
24
15
|
rake
|
25
16
|
|
26
17
|
GIT
|
27
|
-
remote: https://
|
18
|
+
remote: https://github.com/mdsol/moya.git
|
28
19
|
revision: 6e8b324dee6335e5d56d320ba0a605b6ebae8574
|
29
20
|
branch: develop
|
30
21
|
specs:
|
@@ -40,13 +31,12 @@ GIT
|
|
40
31
|
PATH
|
41
32
|
remote: .
|
42
33
|
specs:
|
43
|
-
farscape (1.0
|
34
|
+
farscape (1.3.0)
|
44
35
|
activesupport
|
45
|
-
addressable (~> 2.3
|
46
|
-
|
47
|
-
faraday (~> 0.8.8)
|
48
|
-
faraday_middleware (~> 0.9)
|
36
|
+
addressable (~> 2.3)
|
37
|
+
faraday (~> 0.9)
|
49
38
|
rake
|
39
|
+
representors (~> 0.0.5)
|
50
40
|
|
51
41
|
GEM
|
52
42
|
remote: https://rubygems.org/
|
@@ -77,47 +67,41 @@ GEM
|
|
77
67
|
minitest (~> 5.1)
|
78
68
|
thread_safe (~> 0.1)
|
79
69
|
tzinfo (~> 1.1)
|
80
|
-
activeuuid (0.6.
|
70
|
+
activeuuid (0.6.1)
|
81
71
|
activerecord (>= 3.1)
|
82
72
|
uuidtools
|
83
|
-
addressable (2.3.
|
73
|
+
addressable (2.3.8)
|
84
74
|
arel (5.0.1.20140414130214)
|
85
|
-
awesome_print (1.1.0)
|
86
75
|
builder (3.2.2)
|
87
|
-
|
76
|
+
byebug (9.0.5)
|
88
77
|
colorize (0.6.0)
|
89
|
-
|
78
|
+
concurrent-ruby (1.0.2)
|
79
|
+
crack (0.4.3)
|
90
80
|
safe_yaml (~> 1.0.0)
|
91
|
-
dice_bag (0.
|
81
|
+
dice_bag (0.9.0)
|
92
82
|
rake
|
93
83
|
diff-lcs (1.2.5)
|
94
84
|
diffy (3.0.7)
|
95
85
|
docile (1.1.5)
|
96
86
|
erubis (2.7.0)
|
97
|
-
faraday (0.
|
98
|
-
multipart-post (
|
99
|
-
|
100
|
-
faraday (>= 0.7.4, < 0.10)
|
101
|
-
hike (1.2.3)
|
87
|
+
faraday (0.9.2)
|
88
|
+
multipart-post (>= 1.2, < 3)
|
89
|
+
hashdiff (0.3.0)
|
102
90
|
i18n (0.7.0)
|
103
|
-
json (1.8.
|
91
|
+
json (1.8.3)
|
104
92
|
launchy (2.4.3)
|
105
93
|
addressable (~> 2.3)
|
106
|
-
mail (2.6.
|
107
|
-
mime-types (>= 1.16, <
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
multipart-post (
|
114
|
-
nokogiri (1.6.
|
115
|
-
|
116
|
-
|
117
|
-
coderay (~> 1.1.0)
|
118
|
-
method_source (~> 0.8.1)
|
119
|
-
slop (~> 3.4)
|
120
|
-
rack (1.5.2)
|
94
|
+
mail (2.6.4)
|
95
|
+
mime-types (>= 1.16, < 4)
|
96
|
+
mime-types (3.1)
|
97
|
+
mime-types-data (~> 3.2015)
|
98
|
+
mime-types-data (3.2016.0521)
|
99
|
+
mini_portile2 (2.0.0)
|
100
|
+
minitest (5.9.0)
|
101
|
+
multipart-post (2.0.0)
|
102
|
+
nokogiri (1.6.7.2)
|
103
|
+
mini_portile2 (~> 2.0.0.rc2)
|
104
|
+
rack (1.5.5)
|
121
105
|
rack-test (0.6.3)
|
122
106
|
rack (>= 1.0)
|
123
107
|
rails (4.1.8)
|
@@ -135,8 +119,11 @@ GEM
|
|
135
119
|
activesupport (= 4.1.8)
|
136
120
|
rake (>= 0.8.7)
|
137
121
|
thor (>= 0.18.1, < 2.0)
|
138
|
-
rake (
|
139
|
-
redcarpet (3.
|
122
|
+
rake (11.1.2)
|
123
|
+
redcarpet (3.3.4)
|
124
|
+
representors (0.0.5)
|
125
|
+
addressable (~> 2.3)
|
126
|
+
rake
|
140
127
|
rspec (2.99.0)
|
141
128
|
rspec-core (~> 2.99.0)
|
142
129
|
rspec-expectations (~> 2.99.0)
|
@@ -146,31 +133,28 @@ GEM
|
|
146
133
|
diff-lcs (>= 1.1.3, < 2.0)
|
147
134
|
rspec-mocks (2.99.3)
|
148
135
|
safe_yaml (1.0.4)
|
149
|
-
simplecov (0.
|
136
|
+
simplecov (0.11.2)
|
150
137
|
docile (~> 1.1.0)
|
151
|
-
|
152
|
-
simplecov-html (~> 0.
|
153
|
-
simplecov-html (0.
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
rack (~> 1.0)
|
159
|
-
tilt (~> 1.1, != 1.3.0)
|
160
|
-
sprockets-rails (2.2.4)
|
138
|
+
json (~> 1.8)
|
139
|
+
simplecov-html (~> 0.10.0)
|
140
|
+
simplecov-html (0.10.0)
|
141
|
+
sprockets (3.6.0)
|
142
|
+
concurrent-ruby (~> 1.0)
|
143
|
+
rack (> 1, < 3)
|
144
|
+
sprockets-rails (2.3.3)
|
161
145
|
actionpack (>= 3.0)
|
162
146
|
activesupport (>= 3.0)
|
163
147
|
sprockets (>= 2.8, < 4.0)
|
164
|
-
sqlite3 (1.3.
|
148
|
+
sqlite3 (1.3.11)
|
165
149
|
thor (0.19.1)
|
166
150
|
thread_safe (0.3.5)
|
167
|
-
tilt (1.4.1)
|
168
151
|
tzinfo (1.2.2)
|
169
152
|
thread_safe (~> 0.1)
|
170
153
|
uuidtools (2.1.5)
|
171
|
-
webmock (
|
172
|
-
addressable (>= 2.
|
154
|
+
webmock (2.0.3)
|
155
|
+
addressable (>= 2.3.6)
|
173
156
|
crack (>= 0.3.2)
|
157
|
+
hashdiff
|
174
158
|
yajl-ruby (1.2.1)
|
175
159
|
yard (0.8.7.6)
|
176
160
|
|
@@ -178,15 +162,15 @@ PLATFORMS
|
|
178
162
|
ruby
|
179
163
|
|
180
164
|
DEPENDENCIES
|
181
|
-
|
165
|
+
byebug
|
182
166
|
crichton!
|
183
167
|
farscape!
|
184
168
|
moya!
|
185
|
-
|
186
|
-
rake (~> 0.9)
|
187
|
-
redcarpet
|
188
|
-
representors!
|
169
|
+
redcarpet (~> 3.3)
|
189
170
|
rspec (~> 2.14)
|
190
|
-
simplecov (~> 0.
|
191
|
-
webmock (~>
|
192
|
-
yard
|
171
|
+
simplecov (~> 0.11)
|
172
|
+
webmock (~> 2.0)
|
173
|
+
yard
|
174
|
+
|
175
|
+
BUNDLED WITH
|
176
|
+
1.12.5
|
data/README.md
CHANGED
@@ -15,43 +15,59 @@ a response with a supported Hypermedia media-type and a root that lists availabl
|
|
15
15
|
|
16
16
|
### A Hypermedia API
|
17
17
|
For a interacting with an API (or individual service that supports a list of resources at its root), you enter the
|
18
|
-
API and follow your nose using the `enter` method on the agent. This method returns a [Farscape::Representor]()
|
19
|
-
instance with a simple state-machine interface of `attributes` (data) and `transitions` (link/form affordances) for
|
18
|
+
API and follow your nose using the `enter` method on the agent. This method returns a [Farscape::Representor](lib/farscape/representor.rb)
|
19
|
+
instance with a simple state-machine interface of `attributes` (data) and `transitions` (link/form affordances) for
|
20
20
|
interacting with the resource representations.
|
21
21
|
|
22
22
|
```ruby
|
23
|
-
agent = Farscape::Agent.
|
23
|
+
agent = Farscape::Agent.instance
|
24
24
|
|
25
|
-
resources = agent.enter
|
25
|
+
resources = agent.enter('http://example.com/my_api')
|
26
26
|
resources.attributes # => { meta: 'data', or: 'other data' }
|
27
27
|
resources.transitions.keys # => ['http://example.com/rel/drds', 'http://example.com/rel/leviathans']
|
28
28
|
```
|
29
29
|
|
30
30
|
### A Hypermedia Discovery Service
|
31
|
-
For interacting with a discovery service,
|
32
|
-
or immediately loading a discoverable resource if known to be registered in the service *a priori*.
|
31
|
+
For interacting with a discovery service, you can use enter and follow your nose entry to select a registered resource or setup Farscape with a discovery server.
|
33
32
|
|
34
33
|
```ruby
|
35
|
-
|
34
|
+
# Setting discovery service to https://my_discovery_api
|
35
|
+
Farscape::Agent.config = { Farscape::Discovery::DISCOVERY_KEY => 'https://my_discovery_api' }
|
36
|
+
```
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
The discovery service must return a document with a list of resource names and their root URLs like:
|
39
|
+
|
40
|
+
```json
|
41
|
+
{
|
42
|
+
"_links": {
|
43
|
+
"self": { "href": "https://my_discovery_api" },
|
44
|
+
"boxes": { "href": "https://smallboxesandpoliceboxes.com" },
|
45
|
+
"items": { "href": "https://sonicscrewdriversandotherthings.com/v1/{item}" }
|
46
|
+
}
|
47
|
+
}
|
48
|
+
```
|
40
49
|
|
41
|
-
|
42
|
-
drds.attributes # => { total_count: 25, items: [...] }
|
43
|
-
drds.transitions.keys # => ['self', 'search', 'create', 'next', 'last']
|
50
|
+
Farscape then can be used directly with resource names. Farscape will already do the heavy-lifting of contacting the discovery service and retrieving the root document of the resource.
|
44
51
|
|
45
|
-
|
52
|
+
```ruby
|
53
|
+
agent = Farscape::Agent.instance
|
54
|
+
boxes = agent.enter('boxes')
|
55
|
+
boxes.attributes # => { total_count: 13, items: [...] }
|
56
|
+
|
57
|
+
agent.enter('unknownresource') # raises Farscape::Discovery::NotFound
|
58
|
+
|
59
|
+
agent.enter('items', [{ items: 'bow-tie' }]) # Allows template variables
|
46
60
|
```
|
47
61
|
|
62
|
+
|
63
|
+
|
48
64
|
## API Interaction
|
49
|
-
Entering an API takes you into its application state-machine and, as such, the interface for interacting with that
|
50
|
-
application state is brain dead simple with Farscape. You have data that you read and hypermedia affordances that tell
|
65
|
+
Entering an API takes you into its application state-machine and, as such, the interface for interacting with that
|
66
|
+
application state is brain dead simple with Farscape. You have data that you read and hypermedia affordances that tell
|
51
67
|
you what you can do next and you can invoke those affordances to do things. That's it.
|
52
68
|
|
53
|
-
Farscape recognizes a number of media-types that support runtime knowledge of the underlying REST uniform-interface
|
54
|
-
methods. For these full-featured media-types, the interaction with with resources is as simple as a browser where
|
69
|
+
Farscape recognizes a number of media-types that support runtime knowledge of the underlying REST uniform-interface
|
70
|
+
methods. For these full-featured media-types, the interaction with with resources is as simple as a browser where
|
55
71
|
implementation of requests is completely abstracted from the user.
|
56
72
|
|
57
73
|
The following simple examples highlight interacting with resource state-machines using Farscape.
|
@@ -128,7 +144,7 @@ new_drd.attributes # => { name: 'Pike' }
|
|
128
144
|
new_drd.transitions.keys # => ['self', 'edit', 'delete', 'deactivate', 'leviathan']
|
129
145
|
```
|
130
146
|
|
131
|
-
For more examples and information on using Faraday with media-types that require specifying uniform-interface methods
|
147
|
+
For more examples and information on using Faraday with media-types that require specifying uniform-interface methods
|
132
148
|
and other protocol idioms when invoking transitions, see [Using Farscape]().
|
133
149
|
|
134
150
|
## Alternate Interface
|
data/lib/farscape/agent.rb
CHANGED
@@ -1,16 +1,32 @@
|
|
1
1
|
require 'farscape/representor'
|
2
2
|
require 'farscape/clients'
|
3
|
+
require 'farscape/discovery'
|
3
4
|
|
4
5
|
module Farscape
|
5
6
|
class Agent
|
6
|
-
|
7
|
+
|
7
8
|
include BaseAgent
|
8
|
-
|
9
|
+
|
9
10
|
PROTOCOL = :http
|
10
11
|
|
11
12
|
attr_reader :media_type
|
12
13
|
attr_reader :entry_point
|
13
|
-
|
14
|
+
|
15
|
+
class << self
|
16
|
+
# Prevents multiple threads from accessing the same agent.
|
17
|
+
def instance
|
18
|
+
Thread.current[:farscape_agent] ||= Agent.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def config
|
22
|
+
@farscape_config || {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def config=(farscape_config)
|
26
|
+
@farscape_config = farscape_config
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
14
30
|
def initialize(entry = nil, media = :hale, safe = false, plugin_hash = {})
|
15
31
|
@entry_point = entry
|
16
32
|
@media_type = media
|
@@ -23,10 +39,19 @@ module Farscape
|
|
23
39
|
safe? ? SafeRepresentorAgent : RepresentorAgent
|
24
40
|
end
|
25
41
|
|
26
|
-
|
27
|
-
|
42
|
+
# Discovers provided a key and template_variables.
|
43
|
+
# This method is here to be easily overwritten or monkey-patched if needed.
|
44
|
+
def discover_entry_point(key, template_variables = {})
|
45
|
+
Discovery.new.discover(self.class.config, key, template_variables)
|
46
|
+
end
|
47
|
+
|
48
|
+
def enter(entry = entry_point, template_variables = {})
|
28
49
|
raise "No Entry Point Provided!" unless entry
|
29
|
-
|
50
|
+
@entry_point ||= entry
|
51
|
+
unless Addressable::URI.parse(@entry_point).absolute?
|
52
|
+
@entry_point = discover_entry_point(@entry_point, template_variables)
|
53
|
+
end
|
54
|
+
response = client.invoke(url: @entry_point, headers: get_accept_header(media_type))
|
30
55
|
find_exception(response)
|
31
56
|
end
|
32
57
|
|
@@ -100,7 +125,7 @@ module Farscape
|
|
100
125
|
end
|
101
126
|
|
102
127
|
private
|
103
|
-
|
128
|
+
|
104
129
|
def default_plugin_hash
|
105
130
|
{
|
106
131
|
plugins: Farscape.plugins.dup, # A hash of plugins keyed by the plugin name
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Farscape
|
2
|
+
# This class provide discovery capabilities to Farscape.
|
3
|
+
class Discovery
|
4
|
+
|
5
|
+
DISCOVERY_KEY = :discovery_uri
|
6
|
+
|
7
|
+
class NotFound < NameError
|
8
|
+
end
|
9
|
+
|
10
|
+
# This is the simplest type of discovery. We assume that the url we will call will provide us
|
11
|
+
# document with links which keys are the names we want to discover and hrefs are root URLS.
|
12
|
+
# Templated URLs are supported, an exception will be raised if the template does not match the variables.
|
13
|
+
# {
|
14
|
+
# "_links": {
|
15
|
+
# "boxes": { "href": "https://smallboxesandpoliceboxes.com" },
|
16
|
+
# "items": { "href": "https://sonicscrewdriversandotherthings.com/v1/{item}" }
|
17
|
+
# }
|
18
|
+
# }
|
19
|
+
def discover(config, key, url_template_variables)
|
20
|
+
discovery_uri = config[DISCOVERY_KEY]
|
21
|
+
raise NotFound, "No discovery uri setup for Farscape. Discovery of #{key} unavailable" unless discovery_uri
|
22
|
+
raise NotFound, "Discover URL #{discovery_uri} is not a valid URL." unless discovery_uri =~ URI::regexp
|
23
|
+
discovery_document = Farscape::Agent.new(discovery_uri).enter
|
24
|
+
if discovery_document.kind_of?(Faraday::Response) # Parse errors give us a raw Faraday Response
|
25
|
+
raise NotFound, "The discovery document for #{key} is not valid JSON. We got: #{discovery_document.body}"
|
26
|
+
end
|
27
|
+
found = discovery_document.transitions[key.to_s]
|
28
|
+
raise NotFound, "No key '#{key}' found in the response from the discovery service." unless found
|
29
|
+
found.uri(url_template_variables)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Farscape
|
2
|
+
class PlatformResources
|
3
|
+
ROOT_ITEMS_KEY = 'items'.freeze
|
4
|
+
|
5
|
+
class NotFound < StandardError; end
|
6
|
+
|
7
|
+
def self.agent
|
8
|
+
@agent ||= Agent.new # This is only done once in the application because is expensive
|
9
|
+
# @agent is global to the application. We dup it so each thread has its own copy
|
10
|
+
Thread.current[:farscape_agent] ||= @agent.dup
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.root_for(resource_name, template_variables = {})
|
14
|
+
rescuing_farscape(resource_name) do
|
15
|
+
Farscape.logger.info("Discovering #{resource_name} providing data >#{template_variables}<")
|
16
|
+
root = agent.discover(resource_name, template_variables)
|
17
|
+
Farscape.logger.info("Accessing the root #{root} for #{resource_name}")
|
18
|
+
agent.instance_variable_set(:@entry_point, root)
|
19
|
+
agent.enter(root)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.items_for(resource_name, template_variables = {})
|
24
|
+
root_document = root_for(resource_name, template_variables)
|
25
|
+
attributes = root_document_data(resource_name, root_document)
|
26
|
+
attributes[ROOT_ITEMS_KEY] || []
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.root_document_data(resource_name, root_document)
|
30
|
+
if root_document.respond_to?(:attributes)
|
31
|
+
Farscape.logger.debug("Called #{resource_name} and got #{root_document.attributes[ROOT_ITEMS_KEY]}")
|
32
|
+
root_document.attributes
|
33
|
+
elsif root_document.respond_to?(:body) # Farscape will happily return a Faraday Response when it can not be parsed
|
34
|
+
Farscape.logger.error("The document retrieved for #{resource_name} is not valid JSON. We got: >#{root_document.body}<")
|
35
|
+
{}
|
36
|
+
else
|
37
|
+
Farscape.logger.error("Unknown response trying to access #{resource_name}. We got: >#{root_document}<")
|
38
|
+
{}
|
39
|
+
end
|
40
|
+
rescue StandardError => e
|
41
|
+
log_error("Error accessing the attributes on the root of #{resource_name}", e)
|
42
|
+
{}
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.rescuing_farscape(resource_name)
|
46
|
+
yield
|
47
|
+
rescue Net::ReadTimeout => e
|
48
|
+
log_error("Network read error accessing #{resource_name}", e)
|
49
|
+
rescue Farscape::Exceptions::NotFound => e
|
50
|
+
log_error("Resource not found accessing #{resource_name}", e)
|
51
|
+
rescue Farscape::Exceptions::Forbidden => e
|
52
|
+
log_error("Forbidden access accessing #{resource_name}", e)
|
53
|
+
rescue Farscape::Exceptions::InternalServerError => e
|
54
|
+
log_error("The server responded with an internal server error when accessing #{resource_name}", e)
|
55
|
+
rescue Farscape::Discovery::KeyNotFound => e
|
56
|
+
log_error("The resource #{resource_name} is not registered in our Hypermedia discovery service", e)
|
57
|
+
rescue StandardError => e
|
58
|
+
Farscape.logger.error("Unknown error class '#{e.class}'")
|
59
|
+
log_error("Unknown error accessing #{resource_name}", e)
|
60
|
+
end
|
61
|
+
|
62
|
+
# This is a simple wrapper over Farscape::Agent which provides access to the URL on the enter method.
|
63
|
+
# Recreating the agent is very costly. As it tries to load the plugins and these may be heavy
|
64
|
+
# Specially the discovery service plugin is trying to load a file from disk every single time.
|
65
|
+
# We need to access a variable inside farscape to reuse the agent more than once.
|
66
|
+
# Once Farscape has a version which let us reuse the agent we will delete this helper.
|
67
|
+
class Agent
|
68
|
+
def initialize
|
69
|
+
@agent = Farscape::Agent.new
|
70
|
+
end
|
71
|
+
|
72
|
+
def enter(root)
|
73
|
+
@agent.instance_variable_set(:@entry_point, root)
|
74
|
+
@agent.enter(root)
|
75
|
+
end
|
76
|
+
|
77
|
+
def discover(resource_name, template_variables)
|
78
|
+
if @agent.respond_to?(:discover)
|
79
|
+
@agent.discover(resource_name)
|
80
|
+
else
|
81
|
+
@agent.enter(resource_name)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def method_missing(name, *args, &block)
|
86
|
+
@agent.send(name, *args, &block)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.log_error(message, e)
|
91
|
+
Farscape.logger.error("Hippocrates Error, class #{e.class} \n #{message}: '#{e.message}' \n #{e.backtrace.join("\n")}")
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/lib/farscape/version.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Farscape::Agent do
|
4
|
+
describe '#instance' do
|
5
|
+
it 'returns an Farscape::Agent object' do
|
6
|
+
expect(described_class.instance.class).to eq(described_class)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'returns the same agent if called twice' do
|
10
|
+
agent1 = described_class.instance
|
11
|
+
expect(described_class.instance).to eq(agent1)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#config' do
|
16
|
+
it 'defaults to an empty hash' do
|
17
|
+
expect(described_class.config).to eq({})
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'can be set' do
|
21
|
+
described_class.config = { me: 'too' }
|
22
|
+
expect(described_class.config).to eq( me: 'too' )
|
23
|
+
described_class.config = nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -3,6 +3,42 @@ require 'spec_helper'
|
|
3
3
|
describe Farscape::Agent do
|
4
4
|
let(:entry_point) { "http://localhost:#{RAILS_PORT}"}
|
5
5
|
|
6
|
+
describe '#discover' do
|
7
|
+
let(:resource_name) { 'user' }
|
8
|
+
let(:links) do
|
9
|
+
{
|
10
|
+
_links: {
|
11
|
+
resource_name => { href: entry_point }
|
12
|
+
}
|
13
|
+
}
|
14
|
+
end
|
15
|
+
before do
|
16
|
+
described_class.config = { discovery_uri: "https://www.example.com" }
|
17
|
+
stub_request(:any, "https://www.example.com").to_return(body: links.to_json)
|
18
|
+
end
|
19
|
+
after do
|
20
|
+
described_class.config = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns a Farscape::Representor from a name' do
|
24
|
+
expect(Farscape::Agent.new(resource_name).enter).to be_a Farscape::RepresentorAgent
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'raises Discovery::NotFound if the name does not exist in the discovery service' do
|
28
|
+
expect{ Farscape::Agent.new('unknown').enter }.to raise_error Farscape::Discovery::NotFound
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'raises Discovery::NotFound if the discovery url is not setup' do
|
32
|
+
described_class.config = nil
|
33
|
+
expect{ Farscape::Agent.new.discover_entry_point(resource_name) }.to raise_error Farscape::Discovery::NotFound
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'raises Discovery::NotFound if the discovery url is not a proper url' do
|
37
|
+
described_class.config = { discovery_uri: "aaaaa" }
|
38
|
+
expect{ Farscape::Agent.new.discover_entry_point(resource_name) }.to raise_error Farscape::Discovery::NotFound
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
6
42
|
describe '#enter' do
|
7
43
|
it 'returns a Farscape::Representor' do
|
8
44
|
expect(Farscape::Agent.new(entry_point).enter).to be_a Farscape::RepresentorAgent
|
@@ -276,7 +276,6 @@ describe Farscape do
|
|
276
276
|
Farscape.register_plugin(name: :Wormlet, type: :discovery, extensions: {Agent: [ServiceCatalogue]})
|
277
277
|
expect(Farscape::Agent.new(:moya).enter.transitions.keys).to include("drds")
|
278
278
|
expect(Farscape::Agent.new.enter(:moya).transitions.keys).to include("drds")
|
279
|
-
expect { Farscape::Agent.new.omitting(:discovery).enter(:moya).transitions.keys }.to raise_error(NoMethodError)
|
280
279
|
end
|
281
280
|
|
282
281
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -5,6 +5,9 @@ require 'crichton'
|
|
5
5
|
require 'representors'
|
6
6
|
require 'moya'
|
7
7
|
|
8
|
+
require 'webmock/rspec'
|
9
|
+
|
10
|
+
|
8
11
|
RAILS_PORT = 1234
|
9
12
|
SPEC_DIR = File.expand_path("..", __FILE__)
|
10
13
|
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
@@ -12,6 +15,9 @@ require 'farscape'
|
|
12
15
|
|
13
16
|
Dir["#{SPEC_DIR}/support/*.rb"].each { |f| require f }
|
14
17
|
|
18
|
+
|
19
|
+
WebMock.disable_net_connect!(allow_localhost: true)
|
20
|
+
|
15
21
|
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
16
22
|
RSpec.configure do |config|
|
17
23
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: farscape
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark W. Foster
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '2.14'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: webmock
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '2.0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '2.0'
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: simplecov
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -171,14 +185,17 @@ files:
|
|
171
185
|
- lib/farscape/client/base_client.rb
|
172
186
|
- lib/farscape/client/http_client.rb
|
173
187
|
- lib/farscape/clients.rb
|
188
|
+
- lib/farscape/discovery.rb
|
174
189
|
- lib/farscape/errors.rb
|
175
190
|
- lib/farscape/helpers/partially_ordered_list.rb
|
176
191
|
- lib/farscape/logger.rb
|
192
|
+
- lib/farscape/platform_resources.rb
|
177
193
|
- lib/farscape/plugins.rb
|
178
194
|
- lib/farscape/representor.rb
|
179
195
|
- lib/farscape/transition.rb
|
180
196
|
- lib/farscape/version.rb
|
181
197
|
- lib/plugins/plugins.rb
|
198
|
+
- spec/lib/farscape/agent_spec.rb
|
182
199
|
- spec/lib/farscape/cache_spec.rb
|
183
200
|
- spec/lib/farscape/integration/entry_point_spec.rb
|
184
201
|
- spec/lib/farscape/integration/interface_spec.rb
|