rhcp 0.1.9 → 0.2.14

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/lib/rhcp/request.rb CHANGED
@@ -6,41 +6,53 @@ require 'json'
6
6
 
7
7
  module RHCP
8
8
 
9
- # This class represents a request made by a RHCP client to a RHCP server.
9
+ # This class represents a request initiated by a RHCP client to a RHCP server.
10
10
  # It is passed as an argument to the method that should execute the requested
11
11
  # command
12
12
  class Request
13
-
13
+
14
14
  attr_reader :command
15
15
  attr_reader :param_values
16
+ attr_reader :context
16
17
 
17
18
  # default constructor; will throw exceptions on invalid values
18
- def initialize(command, param_values = {})
19
+ def initialize(command, some_param_values = {}, context = RHCP::Context.new())
20
+ param_values = some_param_values.clone()
21
+ @logger = RHCP::ModuleHelper.instance().logger
19
22
  raise RHCP::RhcpException.new("command may not be null") if command == nil
20
-
23
+ @logger.debug "initializing request #{command.name} with params #{param_values}"
24
+
25
+ @context = context
26
+
27
+ command.params.each do |param|
28
+ value_from_context = param.find_value_in_context(context)
29
+ if value_from_context != nil
30
+ # if the parameter has been specified in the param values, do not override
31
+ if ! param_values.has_key?(param.name)
32
+ @logger.debug "pre-filling param #{param.name} with value '#{value_from_context}' (context key '#{param.autofill_context_key}')"
33
+ param_values[param.name] = value_from_context
34
+ end
35
+ end
36
+ end
37
+
21
38
  # autobox the parameters if necessary
22
39
  param_values.each do |k,v|
23
40
  if ! v.instance_of?(Array)
24
41
  param_values[k] = [ v ]
25
42
  end
26
43
  end
27
-
28
- # check all param values for plausibility
29
- param_values.each do |key,value|
30
- command.get_param(key).check_param_is_valid(value)
31
- end
32
-
33
- # check that we've got all mandatory params
34
- command.params.each do |name, param|
35
- raise RHCP::RhcpException.new("missing mandatory parameter '#{name}'") if param.mandatory && ! param_values.has_key?(name)
36
- end
37
-
44
+
38
45
  @command = command
39
46
  @param_values = param_values
47
+
48
+ printable_param_values = param_values.map do |a,b|
49
+ a + '=' + b.join(',')
50
+ end.join('; ')
51
+ @logger.debug("request initialized : command '#{command.name}', params : #{printable_param_values}")
40
52
  end
41
53
 
42
54
  # used to retrieve the value for the specified parameter
43
- # returns either the value or an array of values if the parameter allows
55
+ # returns either the value or an array of values if the parameter allows
44
56
  # multiple values
45
57
  def get_param_value(param_name)
46
58
  raise "no such parameter : #{param_name}" unless @param_values.has_key?(param_name)
@@ -55,13 +67,13 @@ module RHCP
55
67
  def has_param_value(param_name)
56
68
  @param_values.has_key?(param_name)
57
69
  end
58
-
70
+
59
71
  # convenience method that executes the command that actually delegates to the
60
72
  # command that's inside this request
61
73
  def execute
62
74
  @command.execute_request(self)
63
75
  end
64
-
76
+
65
77
  # reconstructs the request from it's JSON representation
66
78
  # Since the JSON version of a request does hold the command name instead
67
79
  # of the full command only, a broker is needed to lookup the command by
@@ -72,18 +84,25 @@ module RHCP
72
84
  # +json_data+ is the JSON data that represents the request
73
85
  def self.reconstruct_from_json(broker, json_data)
74
86
  object = JSON.parse(json_data)
75
- command = broker.get_command(object['command_name'])
76
- self.new(command, object['param_values'])
87
+
88
+ context = object.has_key?('context') ?
89
+ RHCP::Context.reconstruct_from_json(object['context']) :
90
+ RHCP::Context.new(object['cookies'])
91
+
92
+ command = broker.get_command(object['command_name'], context)
93
+
94
+ self.new(command, object['param_values'], context)
77
95
  end
78
-
96
+
79
97
  # returns a JSON representation of this request.
80
98
  def to_json(*args)
81
99
  {
82
100
  'command_name' => @command.name,
83
- 'param_values' => @param_values
101
+ 'param_values' => @param_values,
102
+ 'context' => @context.to_json
84
103
  }.to_json(*args)
85
- end
86
-
104
+ end
105
+
87
106
  def to_s
88
107
  "#{@command.name} (#{@param_values})"
89
108
  end
data/lib/rhcp/response.rb CHANGED
@@ -15,15 +15,20 @@ module RHCP
15
15
  attr_accessor :error_text
16
16
  attr_accessor :error_detail
17
17
  attr_accessor :data
18
+ # TODO this should be called 'cookies'
19
+ attr_accessor :context
18
20
 
19
21
  # textual description of the result (optional)
20
22
  attr_accessor :result_text
23
+ attr_accessor :created_at
21
24
 
22
25
  def initialize
23
26
  @status = Status::OK
24
27
  @error_text = ""
25
28
  @error_detail = ""
26
- @result_text = "";
29
+ @result_text = ""
30
+ @context = nil
31
+ @created_at = Time.now().to_i
27
32
  end
28
33
 
29
34
  def mark_as_error(text, detail="")
@@ -35,6 +40,10 @@ module RHCP
35
40
  def set_payload(data)
36
41
  @data = data
37
42
  end
43
+
44
+ def set_context(new_context)
45
+ @context = new_context
46
+ end
38
47
 
39
48
  def self.reconstruct_from_json(json_data)
40
49
  object = JSON.parse(json_data)
@@ -44,6 +53,8 @@ module RHCP
44
53
  instance.error_detail = object["error_detail"]
45
54
  instance.set_payload(object["data"])
46
55
  instance.result_text = object['result_text']
56
+ instance.context = object['cookies']
57
+ instance.created_at = object['created_at']
47
58
  instance
48
59
  end
49
60
 
@@ -53,10 +64,12 @@ module RHCP
53
64
  'error_text' => @error_text,
54
65
  'error_detail' => @error_detail,
55
66
  'data' => @data, # TODO what about JSONinification of data? (probably data should be JSON-ish data only, i.e. no special objects)
56
- 'result_text' => @result_text
67
+ 'result_text' => @result_text,
68
+ 'cookies' => @context,
69
+ 'created_at' => @created_at
57
70
  }.to_json(*args)
58
71
  end
59
72
 
60
73
  end
61
74
 
62
- end
75
+ end
@@ -1,29 +1,19 @@
1
- $:.unshift File.join(File.dirname(__FILE__),'..','lib')
1
+ $:.unshift File.join(File.dirname(__FILE__),'..','..','lib')
2
2
 
3
3
  require 'test/unit'
4
4
 
5
5
  require 'rhcp'
6
+ require 'rhcp/tests_for_brokers'
7
+ require 'rhcp/tests_for_writable_brokers'
6
8
 
7
9
  class BrokerTest < Test::Unit::TestCase
8
10
 
9
- def test_register_commands
10
- broker = RHCP::Broker.new()
11
- assert_not_nil broker
12
- commands = broker.get_command_list
13
- assert_not_nil commands
14
- assert_equal 0, commands.size
15
-
16
- command = RHCP::Command.new("test", "a test command", lambda {})
17
- broker.register_command(command)
18
- commands = broker.get_command_list
19
- assert_equal 1, commands.size
20
- assert_equal command, commands["test"]
21
- end
22
-
23
- def test_register_duplicate
24
- broker = RHCP::Broker.new()
25
- broker.register_command RHCP::Command.new("test", "a test command", lambda {})
26
- assert_raise(RHCP::RhcpException) { broker.register_command RHCP::Command.new("test", "a command with the same name", lambda {}) }
11
+ include TestsForBrokers
12
+ include TestsForWritableBrokers
13
+
14
+ def setup
15
+ @broker = RHCP::Broker.new()
16
+ @test_broker = @broker
27
17
  end
28
-
18
+
29
19
  end
@@ -1,10 +1,12 @@
1
- $:.unshift File.join(File.dirname(__FILE__),'..','lib')
1
+ $:.unshift File.join(File.dirname(__FILE__),'..','..', '..', 'lib')
2
2
 
3
3
  require 'test/unit'
4
+ require 'rhcp/test_base'
4
5
  require 'rhcp/client/command_param_stub'
6
+ require 'rhcp'
5
7
  require 'rhcp/command_param'
6
8
 
7
- class CommandParamStubTest < Test::Unit::TestCase
9
+ class CommandParamStubTest < TestBase
8
10
 
9
11
  def param_lookup
10
12
  ["foo", "bar", "baz"]
@@ -15,7 +17,8 @@ class CommandParamStubTest < Test::Unit::TestCase
15
17
  :mandatory => true,
16
18
  :allows_multiple_values => true,
17
19
  :lookup_method => self.method(:param_lookup),
18
- :is_default_param => true
20
+ :is_default_param => true,
21
+ :autofill_context_key => 'zaphod'
19
22
  )
20
23
  end
21
24
 
@@ -31,6 +34,7 @@ class CommandParamStubTest < Test::Unit::TestCase
31
34
  assert_equal @p.has_lookup_values, p2.has_lookup_values
32
35
  assert_equal @p.is_default_param, p2.is_default_param
33
36
  assert_equal @p.mandatory, p2.mandatory
37
+ assert_equal @p.autofill_context_key, p2.autofill_context_key
34
38
 
35
39
  json_hash = JSON.parse(json)
36
40
  p3 = RHCP::Client::CommandParamStub.reconstruct_from_json(json_hash)
@@ -49,7 +53,13 @@ class CommandParamStubTest < Test::Unit::TestCase
49
53
  |partial_value|
50
54
  [ "mascarpone", "limoncello" ]
51
55
  }
52
- lookup_values = stub.get_lookup_values()
56
+ command = RHCP::Command.new("test", "a command for testing", lambda { |request,response|
57
+ first_param = request.get_param_value("first_param")
58
+ puts "just testing : #{first_param}"
59
+ first_param.reverse
60
+ })
61
+ request = RHCP::Request.new(command, {})
62
+ lookup_values = stub.get_lookup_values(request)
53
63
  assert_equal [ "mascarpone", "limoncello" ], lookup_values
54
64
  end
55
65
 
@@ -65,7 +75,7 @@ class CommandParamStubTest < Test::Unit::TestCase
65
75
  |partial_value|
66
76
  has_been_invoked = true
67
77
  }
68
- stub.get_lookup_values()
78
+ stub.get_lookup_values(nil, nil)
69
79
  assert_equal false, has_been_invoked
70
80
  end
71
81
 
@@ -1,4 +1,4 @@
1
- $:.unshift File.join(File.dirname(__FILE__),'..','lib')
1
+ $:.unshift File.join(File.dirname(__FILE__),'..','..','..','lib')
2
2
 
3
3
  require 'rubygems'
4
4
  require 'json'
@@ -1,4 +1,4 @@
1
- $:.unshift File.join(File.dirname(__FILE__),'..','lib')
1
+ $:.unshift File.join(File.dirname(__FILE__),'..','..','lib')
2
2
 
3
3
  require 'test/unit'
4
4
  require 'rhcp/command_param'
@@ -32,41 +32,26 @@ class CommandParamTest < Test::Unit::TestCase
32
32
  assert_equal true, param.is_default_param
33
33
  end
34
34
 
35
- def test_lookup_values
36
- param = RHCP::CommandParam.new("lookup_test", "testing if lookup values are working",
37
- :lookup_method => self.method(:param_lookup)
38
- )
39
- assert_not_nil param
40
- assert_equal param_lookup(), param.get_lookup_values()
41
- end
42
-
43
- def test_partial_lookup_values
44
- param = RHCP::CommandParam.new("lookup_test", "testing if partial lookup values are working",
45
- :lookup_method => self.method(:param_lookup)
46
- )
47
- assert_not_nil param
48
- assert_equal ["bar", "baz"], param.get_lookup_values("ba")
49
- end
50
-
51
- def test_get_lookup_values_without_lookup
52
- param = RHCP::CommandParam.new("lookup_test", "testing if partial lookup values are working")
53
- assert_not_nil param
54
- assert_equal [], param.get_lookup_values()
55
- end
56
-
57
- def test_check_param_is_valid
58
- param = RHCP::CommandParam.new("validity_test", "testing if valid values are valid")
59
- assert_not_nil param
60
- assert param.check_param_is_valid([ "bla" ])
61
- assert_raise(RHCP::RhcpException) { param.check_param_is_valid [ "bla", "blubb" ] }
62
- end
63
-
64
- # values that aren't part of the lookup values are invalid
65
- def test_check_param_is_valid_lookup_values
66
- param = RHCP::CommandParam.new("lookup_test", "testing if partial lookup values are working",
67
- :lookup_method => self.method(:param_lookup)
68
- )
69
- assert_raise(RHCP::RhcpException) { param.check_param_is_valid(["zaphod"]) }
70
- end
35
+ # def test_lookup_values
36
+ # param = RHCP::CommandParam.new("lookup_test", "testing if lookup values are working",
37
+ # :lookup_method => self.method(:param_lookup)
38
+ # )
39
+ # assert_not_nil param
40
+ # assert_equal param_lookup(), param.get_lookup_values(nil, nil)
41
+ # end
42
+ #
43
+ # def test_partial_lookup_values
44
+ # param = RHCP::CommandParam.new("lookup_test", "testing if partial lookup values are working",
45
+ # :lookup_method => self.method(:param_lookup)
46
+ # )
47
+ # assert_not_nil param
48
+ # assert_equal ["bar", "baz"], param.get_lookup_values("ba")
49
+ # end
50
+
51
+ # def test_get_lookup_values_without_lookup
52
+ # param = RHCP::CommandParam.new("lookup_test", "testing if partial lookup values are working")
53
+ # assert_not_nil param
54
+ # assert_equal [], param.get_lookup_values()
55
+ # end
71
56
 
72
57
  end
@@ -1,4 +1,4 @@
1
- $:.unshift File.join(File.dirname(__FILE__),'..','lib')
1
+ $:.unshift File.join(File.dirname(__FILE__),'..','..','lib')
2
2
 
3
3
  require 'test/unit'
4
4
  require 'rhcp'
@@ -20,8 +20,9 @@ class CommandTest < Test::Unit::TestCase
20
20
  assert_not_nil command
21
21
  assert_equal "test", command.name
22
22
  assert_equal "a command for testing", command.description
23
+
23
24
  assert_not_nil command.params
24
- assert_instance_of Hash, command.params
25
+ assert_instance_of Array, command.params
25
26
  assert_equal 0, command.params.size
26
27
 
27
28
  command.add_param(RHCP::CommandParam.new("first_param", "this is the first param"))
@@ -132,5 +133,62 @@ class CommandTest < Test::Unit::TestCase
132
133
  assert ! @listener2_fired
133
134
  end
134
135
 
136
+ def test_enabled_through_context
137
+ command = RHCP::Command.new("context_test", "testing the context", lambda {
138
+ |req,res|
139
+ puts "While I think there could be something important to say right now, I just cannot remember what it might have been..."
140
+ res.result_text = "the test is working"
141
+ })
142
+
143
+ # by default, commands should be enabled even with an empty context
144
+ assert command.is_enabled?
145
+ assert command.is_enabled?({})
146
+
147
+ # if we pass an empty list of context_keys, the command should be disabled
148
+ command.enabled_through_context_keys = []
149
+ assert ! command.is_enabled?
150
+
151
+ context = RHCP::Context.new()
152
+ context.cookies['ankh'] = 'morpork'
153
+
154
+ command.enabled_through_context_keys = ['host']
155
+ assert ! command.is_enabled?
156
+ assert ! command.is_enabled?(context)
157
+ context.cookies['host'] = 'deepthought'
158
+ assert command.is_enabled?(context)
159
+ end
160
+
161
+ def test_invalid_param_name
162
+ command = RHCP::Command.new("test", "another test", lambda {})
163
+ command.add_param(RHCP::CommandParam.new("real_param", "this param does exist"))
164
+
165
+ assert_raise(RHCP::RhcpException) {
166
+ request = RHCP::Request.new(command, {
167
+ "does_not_exist" => [ "single value for non-existing param" ]
168
+ })
169
+ command.execute_request(request)
170
+ }
171
+ end
172
+
173
+ def test_invalid_param_values
174
+ command = RHCP::Command.new("test", "another test", lambda {})
175
+ command.add_param(RHCP::CommandParam.new("real_param", "this param does exist"))
176
+ request = RHCP::Request.new(command, {
177
+ "real_param" => [ "value for the real param", "another value for the real param" ]
178
+ })
179
+ assert_raise(RHCP::RhcpException) { command.execute_request(request) }
180
+ end
181
+
182
+ def test_missing_mandatory_param
183
+ command = RHCP::Command.new("test", "another test", lambda {})
184
+ command.add_param(RHCP::CommandParam.new("first_param", "this is the first param", { :mandatory => true }))
185
+ command.add_param(RHCP::CommandParam.new("second_param", "this param is optional", { :mandatory => false }))
186
+
187
+ assert_raise(RHCP::RhcpException) {
188
+ request = RHCP::Request.new(command, {})
189
+ command.execute_request(request)
190
+ }
191
+ end
192
+
135
193
  end
136
194
 
@@ -0,0 +1,86 @@
1
+ $:.unshift File.join(File.dirname(__FILE__),'..','..','lib')
2
+
3
+ require 'test/unit'
4
+ require 'rhcp'
5
+
6
+ require 'test/unit'
7
+ require 'rhcp/tests_for_brokers'
8
+
9
+ class ContextAwareBrokerTest < Test::Unit::TestCase
10
+
11
+ include TestsForBrokers
12
+
13
+ def setup
14
+ broker = RHCP::Broker.new()
15
+
16
+ @broker = broker
17
+ @test_broker = RHCP::Client::ContextAwareBroker.new(broker)
18
+ end
19
+
20
+ def add_context_commands
21
+ @switch_host = RHCP::Command.new("switch_host", "modifies the context",
22
+ lambda { |request, response|
23
+ response.set_context({'host' => request.get_param_value('new_host')})
24
+ }
25
+ )
26
+ @switch_host.add_param(RHCP::CommandParam.new("new_host", "the new host name",
27
+ {
28
+ :mandatory => true,
29
+ :is_default_param => true,
30
+ }
31
+ ))
32
+ @broker.register_command @switch_host
33
+
34
+ @host_command = RHCP::Command.new("say_hello", "uses context",
35
+ lambda { |request, response|
36
+ "hello from " + request.get_param_value('the_host')
37
+ }
38
+ )
39
+ @host_command.add_param(RHCP::CommandParam.new("the_host", "the host name (should be taken from context)",
40
+ {
41
+ :mandatory => true,
42
+ :is_default_param => true,
43
+ :autofill_context_key => 'host'
44
+ }
45
+ ))
46
+ @broker.register_command @host_command
47
+
48
+ context_command = RHCP::Command.new("let_explode_host", "available only in host context",
49
+ lambda { |request, response|
50
+ "kaboom."
51
+ }
52
+ )
53
+ context_command.enabled_through_context_keys = ['host']
54
+ @broker.register_command context_command
55
+ end
56
+
57
+ def test_context_aware_command_list
58
+ add_context_commands
59
+
60
+ assert_equal 2, @test_broker.get_command_list().size
61
+ @test_broker.context.cookies['host'] = 'moriturus'
62
+ assert_equal 3, @test_broker.get_command_list().size
63
+ end
64
+
65
+ def test_context_setting_command
66
+ add_context_commands
67
+
68
+ request = RHCP::Request.new(@switch_host, {'new_host' => 'lucky bastard'})
69
+ @test_broker.execute(request)
70
+ assert_equal 'lucky bastard', @test_broker.context.cookies['host']
71
+ request = RHCP::Request.new(@host_command, {})
72
+ assert_equal "hello from lucky bastard", @test_broker.execute(request).data
73
+ end
74
+
75
+ def test_invoke_twice
76
+ add_context_commands
77
+
78
+ @test_broker.context.cookies['host'] = 'the_host'
79
+ request = RHCP::Request.new(@host_command)
80
+ response = @test_broker.execute(request)
81
+ assert_equal "hello from the_host", response.data
82
+
83
+ response = @test_broker.execute(request)
84
+ assert_equal "hello from the_host", response.data
85
+ end
86
+ end