holoserve 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|