holoserve 0.3.1 → 0.4.0
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/README.rdoc +46 -62
- data/Rakefile +5 -57
- data/bin/holoserve +8 -7
- data/lib/holoserve/interface/control/bucket.rb +24 -0
- data/lib/holoserve/interface/control/history.rb +24 -0
- data/lib/holoserve/interface/control/pair.rb +24 -0
- data/lib/holoserve/interface/control/state.rb +38 -0
- data/lib/holoserve/interface/control.rb +25 -157
- data/lib/holoserve/interface/fake.rb +35 -27
- data/lib/holoserve/interface.rb +17 -1
- data/lib/holoserve/pair/finder.rb +5 -15
- data/lib/holoserve/pair/loader.rb +70 -0
- data/lib/holoserve/pair.rb +1 -0
- data/lib/holoserve/request/decomposer.rb +27 -17
- data/lib/holoserve/request/matcher.rb +16 -4
- data/lib/holoserve/response/combiner.rb +5 -25
- data/lib/holoserve/response/selector.rb +43 -0
- data/lib/holoserve/response.rb +1 -0
- data/lib/holoserve/state/updater.rb +14 -0
- data/lib/holoserve/state.rb +6 -0
- data/lib/holoserve/tool/data_path.rb +6 -2
- data/lib/holoserve.rb +65 -24
- data/spec/lib/holoserve/fixture/importer_spec.rb +17 -2
- data/spec/lib/holoserve/tool/data_path_spec.rb +6 -0
- data/spec/lib/holoserve_spec.rb +45 -0
- metadata +33 -35
- data/lib/holoserve/runner.rb +0 -82
@@ -1,53 +1,61 @@
|
|
1
|
+
require 'goliath/api'
|
1
2
|
require 'pp'
|
2
3
|
|
3
|
-
class Holoserve::Interface::Fake
|
4
|
+
class Holoserve::Interface::Fake < Goliath::API
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
use Goliath::Rack::Params
|
7
|
+
|
8
|
+
def response(env)
|
9
|
+
request = Holoserve::Request::Decomposer.new(env, params).hash
|
10
|
+
pair = Holoserve::Pair::Finder.new(pairs, request).pair
|
8
11
|
if pair
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
id, responses = *pair.values_at(:id, :responses)
|
13
|
+
|
14
|
+
history << id
|
15
|
+
logger.info "received handled request with id '#{id}'"
|
16
|
+
|
17
|
+
selector = Holoserve::Response::Selector.new responses, state, logger
|
18
|
+
default_response, selected_responses = selector.default_response, selector.selected_responses
|
19
|
+
|
20
|
+
update_state default_response, selected_responses
|
21
|
+
|
22
|
+
response = Holoserve::Response::Combiner.new(default_response, selected_responses).response
|
23
|
+
Holoserve::Response::Composer.new(response).response_array
|
20
24
|
else
|
21
25
|
bucket << request
|
22
26
|
logger.error "received unhandled request\n" + request.pretty_inspect
|
27
|
+
|
23
28
|
not_found
|
24
29
|
end
|
25
30
|
end
|
26
31
|
|
27
32
|
private
|
28
33
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
Holoserve.instance.logger
|
34
|
+
def update_state(default_response, selected_responses)
|
35
|
+
Holoserve::State::Updater.new(state, default_response[:transitions]).perform
|
36
|
+
(selected_responses || [ ]).each do |response|
|
37
|
+
Holoserve::State::Updater.new(state, response[:transitions]).perform
|
38
|
+
end
|
35
39
|
end
|
36
40
|
|
37
|
-
def
|
38
|
-
|
41
|
+
def not_found
|
42
|
+
[ 404, { :"Content-Type" => "text/plain" }, [ "no response found for this request" ] ]
|
39
43
|
end
|
40
44
|
|
41
45
|
def bucket
|
42
|
-
|
46
|
+
config[:bucket] ||= [ ]
|
43
47
|
end
|
44
48
|
|
45
49
|
def history
|
46
|
-
|
50
|
+
config[:history] ||= [ ]
|
51
|
+
end
|
52
|
+
|
53
|
+
def pairs
|
54
|
+
config[:pairs] ||= options[:pairs]
|
47
55
|
end
|
48
56
|
|
49
|
-
def
|
50
|
-
|
57
|
+
def state
|
58
|
+
config[:state] ||= options[:state]
|
51
59
|
end
|
52
60
|
|
53
61
|
end
|
data/lib/holoserve/interface.rb
CHANGED
@@ -1,7 +1,23 @@
|
|
1
|
+
require 'goliath/api'
|
1
2
|
|
2
|
-
|
3
|
+
class Holoserve::Interface < Goliath::API
|
3
4
|
|
4
5
|
autoload :Control, File.join(File.dirname(__FILE__), "interface", "control")
|
5
6
|
autoload :Fake, File.join(File.dirname(__FILE__), "interface", "fake")
|
6
7
|
|
8
|
+
get "/_control/bucket", Control::Bucket::Fetch
|
9
|
+
delete "/_control/bucket", Control::Bucket::Delete
|
10
|
+
|
11
|
+
get "/_control/history", Control::History::Fetch
|
12
|
+
delete "/_control/history", Control::History::Delete
|
13
|
+
|
14
|
+
get "/_control/pairs", Control::Pair::Index
|
15
|
+
get "/_control/pairs/:id", Control::Pair::Fetch
|
16
|
+
|
17
|
+
put "/_control/state", Control::State::Update
|
18
|
+
get "/_control/state", Control::State::Fetch
|
19
|
+
delete "/_control/state", Control::State::Delete
|
20
|
+
|
21
|
+
map "/*", Fake
|
22
|
+
|
7
23
|
end
|
@@ -1,26 +1,16 @@
|
|
1
1
|
|
2
2
|
class Holoserve::Pair::Finder
|
3
3
|
|
4
|
-
def initialize(
|
5
|
-
@
|
4
|
+
def initialize(pairs, request)
|
5
|
+
@pairs, @request = pairs, request
|
6
6
|
end
|
7
7
|
|
8
8
|
def pair
|
9
|
-
return nil unless pairs
|
10
|
-
pairs.each do |
|
11
|
-
return pair.merge(:
|
9
|
+
return nil unless @pairs
|
10
|
+
@pairs.each do |id, pair|
|
11
|
+
return pair.merge(:id => id) if Holoserve::Request::Matcher.new(@request, pair[:request]).match?
|
12
12
|
end
|
13
13
|
nil
|
14
14
|
end
|
15
15
|
|
16
|
-
private
|
17
|
-
|
18
|
-
def pairs
|
19
|
-
@configuration[:pairs]
|
20
|
-
end
|
21
|
-
|
22
|
-
def fixtures
|
23
|
-
@configuration[:fixtures]
|
24
|
-
end
|
25
|
-
|
26
16
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
class Holoserve::Pair::Loader
|
5
|
+
|
6
|
+
def initialize(fixture_file_pattern, pair_file_pattern, logger)
|
7
|
+
@fixtures, @pairs = { }, { }
|
8
|
+
@fixture_file_pattern, @pair_file_pattern = fixture_file_pattern, pair_file_pattern
|
9
|
+
@logger = logger
|
10
|
+
end
|
11
|
+
|
12
|
+
def pairs
|
13
|
+
load_fixtures if @fixture_file_pattern
|
14
|
+
load_pairs if @pair_file_pattern
|
15
|
+
@pairs
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def load_fixtures
|
21
|
+
Dir[ @fixture_file_pattern ].each do |filename|
|
22
|
+
id = extract_id filename
|
23
|
+
fixture = load_file filename
|
24
|
+
@fixtures[id] = fixture if fixture
|
25
|
+
@logger.info "loaded fixture '#{id}'"
|
26
|
+
end
|
27
|
+
@fixtures.freeze
|
28
|
+
end
|
29
|
+
|
30
|
+
def load_pairs
|
31
|
+
Dir[ @pair_file_pattern ].each do |filename|
|
32
|
+
id = extract_id filename
|
33
|
+
pair = load_file filename
|
34
|
+
@pairs[id] = pair_with_imports pair if pair
|
35
|
+
@logger.info "loaded pair '#{id}'"
|
36
|
+
end
|
37
|
+
@pairs.freeze
|
38
|
+
end
|
39
|
+
|
40
|
+
def extract_id(filename)
|
41
|
+
File.basename filename, ".*"
|
42
|
+
end
|
43
|
+
|
44
|
+
def load_file(filename)
|
45
|
+
format = File.extname(filename).sub(/^\./, "")
|
46
|
+
raise ArgumentError, "file extension indicates wrong format '#{format}' (choose yaml or json)" unless [ "yaml", "json" ].include?(format)
|
47
|
+
data = begin
|
48
|
+
YAML::load_file filename
|
49
|
+
rescue Psych::SyntaxError
|
50
|
+
begin
|
51
|
+
JSON.parse File.read(filename)
|
52
|
+
rescue JSON::ParserError
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
Holoserve::Tool::Hash::KeySymbolizer.new(data).hash
|
57
|
+
end
|
58
|
+
|
59
|
+
def pair_with_imports(pair)
|
60
|
+
result = {
|
61
|
+
:request => Holoserve::Fixture::Importer.new(pair[:request], @fixtures).result,
|
62
|
+
:responses => { }
|
63
|
+
}
|
64
|
+
(pair[:responses] || { }).each do |id, response|
|
65
|
+
result[:responses][id] = Holoserve::Fixture::Importer.new(response, @fixtures).result
|
66
|
+
end
|
67
|
+
result
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
data/lib/holoserve/pair.rb
CHANGED
@@ -1,19 +1,29 @@
|
|
1
1
|
|
2
2
|
class Holoserve::Request::Decomposer
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
ONLY_HEADERS = [
|
5
|
+
"SERVER_SOFTWARE",
|
6
|
+
"SERVER_NAME",
|
7
|
+
"SERVER_PORT",
|
8
|
+
"REMOTE_ADDR",
|
9
|
+
"SCRIPT_NAME",
|
10
|
+
"CONTENT_TYPE"
|
11
|
+
].freeze unless defined?(ONLY_HEADERS)
|
12
|
+
|
13
|
+
def initialize(request, parameters)
|
14
|
+
@request, @parameters = request, parameters
|
6
15
|
end
|
7
16
|
|
8
17
|
def hash
|
9
18
|
hash = {
|
10
19
|
:method => @request["REQUEST_METHOD"],
|
11
|
-
:path => @request["
|
20
|
+
:path => @request["REQUEST_PATH"]
|
12
21
|
}
|
13
|
-
hash
|
14
|
-
hash
|
15
|
-
hash
|
16
|
-
hash
|
22
|
+
hash[:headers] = headers unless headers.empty?
|
23
|
+
hash[:body] = body unless body.nil?
|
24
|
+
hash[:parameters] = parameters unless parameters.empty?
|
25
|
+
hash[:oauth] = oauth unless oauth.empty?
|
26
|
+
hash[:json] = json unless json.empty?
|
17
27
|
hash
|
18
28
|
end
|
19
29
|
|
@@ -22,7 +32,7 @@ class Holoserve::Request::Decomposer
|
|
22
32
|
def headers
|
23
33
|
headers = { }
|
24
34
|
@request.each do |key, value|
|
25
|
-
headers[ key.to_sym ] = value
|
35
|
+
headers[ key.to_sym ] = value if ONLY_HEADERS.include?(key) || key =~ /^HTTP_/
|
26
36
|
end
|
27
37
|
headers
|
28
38
|
end
|
@@ -35,15 +45,7 @@ class Holoserve::Request::Decomposer
|
|
35
45
|
end
|
36
46
|
|
37
47
|
def parameters
|
38
|
-
Holoserve::Tool::Hash::KeySymbolizer.new(
|
39
|
-
end
|
40
|
-
|
41
|
-
def query_hash
|
42
|
-
@request["rack.request.query_hash"] || { }
|
43
|
-
end
|
44
|
-
|
45
|
-
def form_hash
|
46
|
-
@request["rack.request.form_hash"] || { }
|
48
|
+
Holoserve::Tool::Hash::KeySymbolizer.new(@parameters).hash
|
47
49
|
end
|
48
50
|
|
49
51
|
def oauth
|
@@ -62,4 +64,12 @@ class Holoserve::Request::Decomposer
|
|
62
64
|
end
|
63
65
|
end
|
64
66
|
|
67
|
+
def json
|
68
|
+
@json ||= if @request["CONTENT_TYPE"] == "application/json"
|
69
|
+
Holoserve::Tool::Hash::KeySymbolizer.new(JSON.parse(@body)).hash
|
70
|
+
else
|
71
|
+
{ }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
65
75
|
end
|
@@ -1,9 +1,8 @@
|
|
1
1
|
|
2
2
|
class Holoserve::Request::Matcher
|
3
3
|
|
4
|
-
def initialize(request, request_subset
|
5
|
-
@request = request
|
6
|
-
@request_subset = Holoserve::Fixture::Importer.new(request_subset, fixtures).result
|
4
|
+
def initialize(request, request_subset)
|
5
|
+
@request, @request_subset = request, request_subset
|
7
6
|
end
|
8
7
|
|
9
8
|
def match?
|
@@ -12,7 +11,8 @@ class Holoserve::Request::Matcher
|
|
12
11
|
match_headers? &&
|
13
12
|
match_body? &&
|
14
13
|
match_parameters? &&
|
15
|
-
match_oauth?
|
14
|
+
match_oauth? &&
|
15
|
+
match_json?
|
16
16
|
end
|
17
17
|
|
18
18
|
private
|
@@ -59,4 +59,16 @@ class Holoserve::Request::Matcher
|
|
59
59
|
match
|
60
60
|
end
|
61
61
|
|
62
|
+
def match_json?
|
63
|
+
match_hash? :json
|
64
|
+
end
|
65
|
+
|
66
|
+
def match_hash?(hash_key)
|
67
|
+
match = true
|
68
|
+
(@request_subset[hash_key] || { }).each do |key, value|
|
69
|
+
match &&= @request[hash_key].is_a?(Hash) && (@request[hash_key][key] == value)
|
70
|
+
end
|
71
|
+
match
|
72
|
+
end
|
73
|
+
|
62
74
|
end
|
@@ -1,34 +1,14 @@
|
|
1
1
|
|
2
2
|
class Holoserve::Response::Combiner
|
3
3
|
|
4
|
-
def initialize(
|
5
|
-
@
|
4
|
+
def initialize(default, responses)
|
5
|
+
@default, @responses = default, responses
|
6
6
|
end
|
7
7
|
|
8
8
|
def response
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
private
|
13
|
-
|
14
|
-
def default_response
|
15
|
-
@responses[:default] ?
|
16
|
-
Holoserve::Fixture::Importer.new(@responses[:default], fixtures).result :
|
17
|
-
{ }
|
18
|
-
end
|
19
|
-
|
20
|
-
def situation_response
|
21
|
-
situation && @responses[situation.to_sym] ?
|
22
|
-
Holoserve::Fixture::Importer.new(@responses[situation.to_sym], fixtures).result :
|
23
|
-
{ }
|
24
|
-
end
|
25
|
-
|
26
|
-
def fixtures
|
27
|
-
@configuration[:fixtures]
|
28
|
-
end
|
29
|
-
|
30
|
-
def situation
|
31
|
-
@configuration[:situation]
|
9
|
+
@responses.inject @default do |result, response|
|
10
|
+
Holoserve::Tool::Merger.new(result, response).result
|
11
|
+
end
|
32
12
|
end
|
33
13
|
|
34
14
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
class Holoserve::Response::Selector
|
3
|
+
|
4
|
+
class Sandbox
|
5
|
+
|
6
|
+
def initialize(state)
|
7
|
+
state.each do |resource, value|
|
8
|
+
define_singleton_method resource.to_sym do
|
9
|
+
value ? value.to_sym : nil
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(responses, state, logger)
|
17
|
+
@responses, @logger = responses, logger
|
18
|
+
@sandbox = Sandbox.new state
|
19
|
+
end
|
20
|
+
|
21
|
+
def default_response
|
22
|
+
@responses[:default] ?
|
23
|
+
@responses[:default] :
|
24
|
+
{ }
|
25
|
+
end
|
26
|
+
|
27
|
+
def selected_responses
|
28
|
+
result = [ ]
|
29
|
+
(@responses || { }).each do |line, response|
|
30
|
+
next if line.to_s == "default"
|
31
|
+
begin
|
32
|
+
match = @sandbox.instance_eval do
|
33
|
+
eval line.to_s
|
34
|
+
end
|
35
|
+
result << response if match
|
36
|
+
rescue Object => error
|
37
|
+
@logger.error error.inspect
|
38
|
+
end
|
39
|
+
end
|
40
|
+
result
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/lib/holoserve/response.rb
CHANGED
@@ -3,5 +3,6 @@ module Holoserve::Response
|
|
3
3
|
|
4
4
|
autoload :Combiner, File.join(File.dirname(__FILE__), "response", "combiner")
|
5
5
|
autoload :Composer, File.join(File.dirname(__FILE__), "response", "composer")
|
6
|
+
autoload :Selector, File.join(File.dirname(__FILE__), "response", "selector")
|
6
7
|
|
7
8
|
end
|
@@ -4,10 +4,14 @@ class Holoserve::Tool::DataPath
|
|
4
4
|
PATH_SEPARATOR = ".".freeze unless defined?(PATH_SEPARATOR)
|
5
5
|
|
6
6
|
attr_accessor :path
|
7
|
-
|
7
|
+
attr_reader :data
|
8
8
|
|
9
9
|
def initialize(path, data)
|
10
|
-
|
10
|
+
self.path, self.data = path, data
|
11
|
+
end
|
12
|
+
|
13
|
+
def data=(value)
|
14
|
+
@data = Holoserve::Tool::Hash::KeySymbolizer.new(value).hash
|
11
15
|
end
|
12
16
|
|
13
17
|
def fetch
|
data/lib/holoserve.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'goliath/runner'
|
2
2
|
require 'logger'
|
3
3
|
|
4
4
|
class Holoserve
|
@@ -8,44 +8,85 @@ class Holoserve
|
|
8
8
|
autoload :Pair, File.join(File.dirname(__FILE__), "holoserve", "pair")
|
9
9
|
autoload :Request, File.join(File.dirname(__FILE__), "holoserve", "request")
|
10
10
|
autoload :Response, File.join(File.dirname(__FILE__), "holoserve", "response")
|
11
|
-
autoload :
|
11
|
+
autoload :State, File.join(File.dirname(__FILE__), "holoserve", "state")
|
12
12
|
autoload :Tool, File.join(File.dirname(__FILE__), "holoserve", "tool")
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
def initialize(options = { })
|
15
|
+
@port = options[:port] || 4250
|
16
|
+
@pid_filename = options[:pid_filename] || File.expand_path(File.join(File.dirname(__FILE__), "..", "holoserve.pid"))
|
17
|
+
@log_filename = options[:log_filename] || File.expand_path(File.join(File.dirname(__FILE__), "..", "holoserve.log"))
|
18
|
+
@fixture_file_pattern = options[:fixture_file_pattern]
|
19
|
+
@pair_file_pattern = options[:pair_file_pattern]
|
20
|
+
@state = options[:state] || { }
|
21
|
+
end
|
22
|
+
|
23
|
+
def start
|
24
|
+
initialize_logger
|
25
|
+
load_pairs
|
26
|
+
run_goliath true
|
27
|
+
wait_until_running
|
28
|
+
end
|
17
29
|
|
18
|
-
def
|
30
|
+
def run
|
19
31
|
initialize_logger
|
20
|
-
|
21
|
-
|
32
|
+
load_pairs
|
33
|
+
run_goliath false
|
34
|
+
end
|
35
|
+
|
36
|
+
def stop
|
37
|
+
kill_goliath
|
38
|
+
end
|
39
|
+
|
40
|
+
def running?
|
41
|
+
!!(process_id && Process.kill(0, process_id) == 1)
|
42
|
+
rescue Errno::ESRCH
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def process_id
|
47
|
+
File.read(@pid_filename).to_i
|
48
|
+
rescue Errno::ENOENT
|
49
|
+
nil
|
22
50
|
end
|
23
51
|
|
24
52
|
private
|
25
53
|
|
26
54
|
def initialize_logger
|
27
|
-
@logger = Logger.new
|
55
|
+
@logger = Logger.new @log_filename
|
28
56
|
end
|
29
57
|
|
30
|
-
def
|
31
|
-
@
|
32
|
-
:pairs => { },
|
33
|
-
:fixtures => { },
|
34
|
-
:situation => nil,
|
35
|
-
:bucket => [ ],
|
36
|
-
:history => [ ]
|
37
|
-
}
|
58
|
+
def load_pairs
|
59
|
+
@pairs = Pair::Loader.new(@fixture_file_pattern, @pair_file_pattern, @logger).pairs
|
38
60
|
end
|
39
61
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
62
|
+
def run_goliath(daemonize)
|
63
|
+
saved_directory = Dir.pwd
|
64
|
+
|
65
|
+
runner = Goliath::Runner.new [
|
66
|
+
"-P", @pid_filename,
|
67
|
+
"-l", @log_filename,
|
68
|
+
"-e", "production",
|
69
|
+
"-p", @port.to_s,
|
70
|
+
daemonize ? "-d" : "-s"
|
71
|
+
], nil
|
72
|
+
runner.options[:pairs] = @pairs
|
73
|
+
runner.options[:state] = @state
|
74
|
+
runner.api = Interface.new
|
75
|
+
runner.app = Goliath::Rack::Builder.build Interface, runner.api
|
76
|
+
runner.run
|
77
|
+
|
78
|
+
Dir.chdir saved_directory
|
79
|
+
end
|
80
|
+
|
81
|
+
def wait_until_running
|
82
|
+
sleep 0.2 while !self.running?
|
45
83
|
end
|
46
84
|
|
47
|
-
def
|
48
|
-
|
85
|
+
def kill_goliath
|
86
|
+
if File.exists?(@pid_filename)
|
87
|
+
system "kill -s QUIT `cat #{@pid_filename}`"
|
88
|
+
File.delete @pid_filename
|
89
|
+
end
|
49
90
|
end
|
50
91
|
|
51
92
|
end
|
@@ -25,9 +25,10 @@ describe Holoserve::Fixture::Importer do
|
|
25
25
|
subject.hash = {
|
26
26
|
:imports => [
|
27
27
|
{ :path => "one" }
|
28
|
-
]
|
28
|
+
],
|
29
|
+
:test => "value"
|
29
30
|
}
|
30
|
-
subject.result.should == { :first => 1, :second => 2 }
|
31
|
+
subject.result.should == { :first => 1, :second => 2, :test => "value" }
|
31
32
|
end
|
32
33
|
|
33
34
|
it "should return a hash with imported fixtures at a target path" do
|
@@ -77,6 +78,20 @@ describe Holoserve::Fixture::Importer do
|
|
77
78
|
subject.result.should == { :first => 1, :second => 2, :third => 4 }
|
78
79
|
end
|
79
80
|
|
81
|
+
it "should return a hash where all the imports (with and without an :as statement) are properly merged together" do
|
82
|
+
subject.hash = {
|
83
|
+
:imports => [
|
84
|
+
{ :path => "one" },
|
85
|
+
{ :path => "three", :as => "test" },
|
86
|
+
{ :path => "two", :as => "test.another" }
|
87
|
+
],
|
88
|
+
:test => {
|
89
|
+
:fifth => 6
|
90
|
+
}
|
91
|
+
}
|
92
|
+
subject.result.should == { :first => 1, :second => 2, :test => { :third => 4, :another => 3, :fifth => 6 } }
|
93
|
+
end
|
94
|
+
|
80
95
|
it "should return a hash where the data is merged with the imports" do
|
81
96
|
subject.hash = {
|
82
97
|
:imports => [
|
@@ -18,6 +18,12 @@ describe Holoserve::Tool::DataPath do
|
|
18
18
|
subject.fetch.should == "value"
|
19
19
|
end
|
20
20
|
|
21
|
+
it "should return the value even if string keys are used" do
|
22
|
+
subject.path = "test"
|
23
|
+
subject.data = { "test" => "value" }.freeze
|
24
|
+
subject.fetch.should == "value"
|
25
|
+
end
|
26
|
+
|
21
27
|
it "should return the nested value specified by the given path" do
|
22
28
|
subject.path = "test.nested"
|
23
29
|
subject.data = { :test => { :nested => "value" }.freeze }.freeze
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "helper"))
|
2
|
+
|
3
|
+
describe Holoserve do
|
4
|
+
|
5
|
+
subject { described_class.new }
|
6
|
+
|
7
|
+
describe "#start" do
|
8
|
+
|
9
|
+
after :each do
|
10
|
+
subject.stop
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should not change the working directory" do
|
14
|
+
lambda do
|
15
|
+
subject.start
|
16
|
+
end.should_not change(Dir, :pwd)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should start holoserve" do
|
20
|
+
lambda do
|
21
|
+
subject.start
|
22
|
+
end.should change(subject, :running?).from(false).to(true)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#stop" do
|
28
|
+
|
29
|
+
before :each do
|
30
|
+
subject.start
|
31
|
+
end
|
32
|
+
|
33
|
+
after :each do
|
34
|
+
subject.stop
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should stop holoserve" do
|
38
|
+
lambda do
|
39
|
+
subject.stop
|
40
|
+
end.should change(subject, :running?).from(true).to(false)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|