right_agent 2.0.7-x86-mingw32

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.
Files changed (176) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +82 -0
  3. data/Rakefile +113 -0
  4. data/lib/right_agent.rb +59 -0
  5. data/lib/right_agent/actor.rb +182 -0
  6. data/lib/right_agent/actor_registry.rb +76 -0
  7. data/lib/right_agent/actors/agent_manager.rb +232 -0
  8. data/lib/right_agent/agent.rb +1149 -0
  9. data/lib/right_agent/agent_config.rb +480 -0
  10. data/lib/right_agent/agent_identity.rb +210 -0
  11. data/lib/right_agent/agent_tag_manager.rb +237 -0
  12. data/lib/right_agent/audit_formatter.rb +107 -0
  13. data/lib/right_agent/clients.rb +31 -0
  14. data/lib/right_agent/clients/api_client.rb +383 -0
  15. data/lib/right_agent/clients/auth_client.rb +247 -0
  16. data/lib/right_agent/clients/balanced_http_client.rb +369 -0
  17. data/lib/right_agent/clients/base_retry_client.rb +495 -0
  18. data/lib/right_agent/clients/right_http_client.rb +279 -0
  19. data/lib/right_agent/clients/router_client.rb +493 -0
  20. data/lib/right_agent/command.rb +30 -0
  21. data/lib/right_agent/command/agent_manager_commands.rb +150 -0
  22. data/lib/right_agent/command/command_client.rb +136 -0
  23. data/lib/right_agent/command/command_constants.rb +33 -0
  24. data/lib/right_agent/command/command_io.rb +126 -0
  25. data/lib/right_agent/command/command_parser.rb +87 -0
  26. data/lib/right_agent/command/command_runner.rb +118 -0
  27. data/lib/right_agent/command/command_serializer.rb +63 -0
  28. data/lib/right_agent/connectivity_checker.rb +179 -0
  29. data/lib/right_agent/console.rb +65 -0
  30. data/lib/right_agent/core_payload_types.rb +44 -0
  31. data/lib/right_agent/core_payload_types/cookbook.rb +61 -0
  32. data/lib/right_agent/core_payload_types/cookbook_position.rb +46 -0
  33. data/lib/right_agent/core_payload_types/cookbook_repository.rb +116 -0
  34. data/lib/right_agent/core_payload_types/cookbook_sequence.rb +70 -0
  35. data/lib/right_agent/core_payload_types/dev_repositories.rb +100 -0
  36. data/lib/right_agent/core_payload_types/dev_repository.rb +76 -0
  37. data/lib/right_agent/core_payload_types/event_categories.rb +38 -0
  38. data/lib/right_agent/core_payload_types/executable_bundle.rb +130 -0
  39. data/lib/right_agent/core_payload_types/login_policy.rb +72 -0
  40. data/lib/right_agent/core_payload_types/login_user.rb +79 -0
  41. data/lib/right_agent/core_payload_types/planned_volume.rb +94 -0
  42. data/lib/right_agent/core_payload_types/recipe_instantiation.rb +73 -0
  43. data/lib/right_agent/core_payload_types/repositories_bundle.rb +50 -0
  44. data/lib/right_agent/core_payload_types/right_script_attachment.rb +95 -0
  45. data/lib/right_agent/core_payload_types/right_script_instantiation.rb +94 -0
  46. data/lib/right_agent/core_payload_types/runlist_policy.rb +44 -0
  47. data/lib/right_agent/core_payload_types/secure_document.rb +66 -0
  48. data/lib/right_agent/core_payload_types/secure_document_location.rb +63 -0
  49. data/lib/right_agent/core_payload_types/software_repository_instantiation.rb +61 -0
  50. data/lib/right_agent/daemonize.rb +35 -0
  51. data/lib/right_agent/dispatched_cache.rb +109 -0
  52. data/lib/right_agent/dispatcher.rb +272 -0
  53. data/lib/right_agent/enrollment_result.rb +221 -0
  54. data/lib/right_agent/exceptions.rb +87 -0
  55. data/lib/right_agent/history.rb +145 -0
  56. data/lib/right_agent/log.rb +460 -0
  57. data/lib/right_agent/minimal.rb +46 -0
  58. data/lib/right_agent/monkey_patches.rb +30 -0
  59. data/lib/right_agent/monkey_patches/ruby_patch.rb +55 -0
  60. data/lib/right_agent/monkey_patches/ruby_patch/array_patch.rb +29 -0
  61. data/lib/right_agent/monkey_patches/ruby_patch/darwin_patch.rb +24 -0
  62. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch.rb +24 -0
  63. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch/file_patch.rb +30 -0
  64. data/lib/right_agent/monkey_patches/ruby_patch/object_patch.rb +49 -0
  65. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch.rb +32 -0
  66. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/file_patch.rb +60 -0
  67. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/process_patch.rb +63 -0
  68. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/stdio_patch.rb +27 -0
  69. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/time_patch.rb +55 -0
  70. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/win32ole_patch.rb +34 -0
  71. data/lib/right_agent/multiplexer.rb +102 -0
  72. data/lib/right_agent/offline_handler.rb +270 -0
  73. data/lib/right_agent/operation_result.rb +300 -0
  74. data/lib/right_agent/packets.rb +673 -0
  75. data/lib/right_agent/payload_formatter.rb +104 -0
  76. data/lib/right_agent/pending_requests.rb +128 -0
  77. data/lib/right_agent/pid_file.rb +159 -0
  78. data/lib/right_agent/platform.rb +770 -0
  79. data/lib/right_agent/platform/unix/darwin/platform.rb +102 -0
  80. data/lib/right_agent/platform/unix/linux/platform.rb +305 -0
  81. data/lib/right_agent/platform/unix/platform.rb +226 -0
  82. data/lib/right_agent/platform/windows/mingw/platform.rb +447 -0
  83. data/lib/right_agent/platform/windows/mswin/platform.rb +236 -0
  84. data/lib/right_agent/platform/windows/platform.rb +1808 -0
  85. data/lib/right_agent/protocol_version_mixin.rb +69 -0
  86. data/lib/right_agent/retryable_request.rb +195 -0
  87. data/lib/right_agent/scripts/agent_controller.rb +543 -0
  88. data/lib/right_agent/scripts/agent_deployer.rb +400 -0
  89. data/lib/right_agent/scripts/common_parser.rb +160 -0
  90. data/lib/right_agent/scripts/log_level_manager.rb +192 -0
  91. data/lib/right_agent/scripts/stats_manager.rb +268 -0
  92. data/lib/right_agent/scripts/usage.rb +58 -0
  93. data/lib/right_agent/secure_identity.rb +92 -0
  94. data/lib/right_agent/security.rb +32 -0
  95. data/lib/right_agent/security/cached_certificate_store_proxy.rb +77 -0
  96. data/lib/right_agent/security/certificate.rb +102 -0
  97. data/lib/right_agent/security/certificate_cache.rb +89 -0
  98. data/lib/right_agent/security/distinguished_name.rb +56 -0
  99. data/lib/right_agent/security/encrypted_document.rb +83 -0
  100. data/lib/right_agent/security/rsa_key_pair.rb +76 -0
  101. data/lib/right_agent/security/signature.rb +86 -0
  102. data/lib/right_agent/security/static_certificate_store.rb +85 -0
  103. data/lib/right_agent/sender.rb +792 -0
  104. data/lib/right_agent/serialize.rb +29 -0
  105. data/lib/right_agent/serialize/message_pack.rb +107 -0
  106. data/lib/right_agent/serialize/secure_serializer.rb +151 -0
  107. data/lib/right_agent/serialize/secure_serializer_initializer.rb +47 -0
  108. data/lib/right_agent/serialize/serializable.rb +151 -0
  109. data/lib/right_agent/serialize/serializer.rb +159 -0
  110. data/lib/right_agent/subprocess.rb +38 -0
  111. data/lib/right_agent/tracer.rb +124 -0
  112. data/right_agent.gemspec +101 -0
  113. data/spec/actor_registry_spec.rb +80 -0
  114. data/spec/actor_spec.rb +162 -0
  115. data/spec/agent_config_spec.rb +235 -0
  116. data/spec/agent_identity_spec.rb +78 -0
  117. data/spec/agent_spec.rb +734 -0
  118. data/spec/agent_tag_manager_spec.rb +319 -0
  119. data/spec/clients/api_client_spec.rb +423 -0
  120. data/spec/clients/auth_client_spec.rb +272 -0
  121. data/spec/clients/balanced_http_client_spec.rb +576 -0
  122. data/spec/clients/base_retry_client_spec.rb +635 -0
  123. data/spec/clients/router_client_spec.rb +594 -0
  124. data/spec/clients/spec_helper.rb +111 -0
  125. data/spec/command/agent_manager_commands_spec.rb +51 -0
  126. data/spec/command/command_io_spec.rb +93 -0
  127. data/spec/command/command_parser_spec.rb +79 -0
  128. data/spec/command/command_runner_spec.rb +107 -0
  129. data/spec/command/command_serializer_spec.rb +51 -0
  130. data/spec/connectivity_checker_spec.rb +83 -0
  131. data/spec/core_payload_types/dev_repositories_spec.rb +64 -0
  132. data/spec/core_payload_types/dev_repository_spec.rb +33 -0
  133. data/spec/core_payload_types/executable_bundle_spec.rb +67 -0
  134. data/spec/core_payload_types/login_user_spec.rb +102 -0
  135. data/spec/core_payload_types/recipe_instantiation_spec.rb +81 -0
  136. data/spec/core_payload_types/right_script_attachment_spec.rb +65 -0
  137. data/spec/core_payload_types/right_script_instantiation_spec.rb +79 -0
  138. data/spec/core_payload_types/spec_helper.rb +23 -0
  139. data/spec/dispatched_cache_spec.rb +136 -0
  140. data/spec/dispatcher_spec.rb +324 -0
  141. data/spec/enrollment_result_spec.rb +53 -0
  142. data/spec/history_spec.rb +246 -0
  143. data/spec/log_spec.rb +192 -0
  144. data/spec/monkey_patches/eventmachine_spec.rb +62 -0
  145. data/spec/multiplexer_spec.rb +48 -0
  146. data/spec/offline_handler_spec.rb +340 -0
  147. data/spec/operation_result_spec.rb +208 -0
  148. data/spec/packets_spec.rb +461 -0
  149. data/spec/pending_requests_spec.rb +136 -0
  150. data/spec/platform/spec_helper.rb +216 -0
  151. data/spec/platform/unix/darwin/platform_spec.rb +181 -0
  152. data/spec/platform/unix/linux/platform_spec.rb +540 -0
  153. data/spec/platform/unix/spec_helper.rb +149 -0
  154. data/spec/platform/windows/mingw/platform_spec.rb +222 -0
  155. data/spec/platform/windows/mswin/platform_spec.rb +259 -0
  156. data/spec/platform/windows/spec_helper.rb +720 -0
  157. data/spec/retryable_request_spec.rb +306 -0
  158. data/spec/secure_identity_spec.rb +50 -0
  159. data/spec/security/cached_certificate_store_proxy_spec.rb +62 -0
  160. data/spec/security/certificate_cache_spec.rb +71 -0
  161. data/spec/security/certificate_spec.rb +49 -0
  162. data/spec/security/distinguished_name_spec.rb +46 -0
  163. data/spec/security/encrypted_document_spec.rb +55 -0
  164. data/spec/security/rsa_key_pair_spec.rb +55 -0
  165. data/spec/security/signature_spec.rb +66 -0
  166. data/spec/security/static_certificate_store_spec.rb +58 -0
  167. data/spec/sender_spec.rb +1045 -0
  168. data/spec/serialize/message_pack_spec.rb +131 -0
  169. data/spec/serialize/secure_serializer_spec.rb +132 -0
  170. data/spec/serialize/serializable_spec.rb +90 -0
  171. data/spec/serialize/serializer_spec.rb +197 -0
  172. data/spec/spec.opts +2 -0
  173. data/spec/spec.win32.opts +1 -0
  174. data/spec/spec_helper.rb +130 -0
  175. data/spec/tracer_spec.rb +114 -0
  176. metadata +447 -0
@@ -0,0 +1,79 @@
1
+ #-- -*- mode: ruby; encoding: utf-8 -*-
2
+ # Copyright: Copyright (c) 2009-2013 RightScale, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # 'Software'), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
25
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'right_agent', 'core_payload_types'))
26
+
27
+ module RightScale
28
+ describe RightScriptInstantiation do
29
+ let(:nickname) { 'foo' }
30
+ let(:source) { "echo 'hello world'" }
31
+ let(:parameters) { { 'ADMIN_PASSWORD' => 'clandestine' } }
32
+ let(:attachments) { [] }
33
+ let(:packages) { '' }
34
+ let(:id) { 123 }
35
+ let(:ready) { true }
36
+ let(:external_inputs) { {} }
37
+ let(:input_flags) { {} }
38
+ let(:display_version) { 'HEAD' }
39
+
40
+ context 'given all fields' do
41
+ subject do
42
+ described_class.new(
43
+ nickname, source, parameters, attachments, packages, id, ready,
44
+ external_inputs, input_flags, display_version)
45
+ end
46
+
47
+ its(:title) { should == "'#{nickname}' #{display_version}" }
48
+ its(:nickname) { should == nickname }
49
+ its(:source) { should == source }
50
+ its(:parameters) { should == parameters }
51
+ its(:attachments) { should == attachments }
52
+ its(:packages) { should == packages }
53
+ its(:id) { should == id }
54
+ its(:ready) { should == ready }
55
+ its(:external_inputs) { should == external_inputs }
56
+ its(:input_flags) { should == input_flags }
57
+ its(:display_version) { should == display_version }
58
+ end
59
+
60
+ context 'given minimal fields' do
61
+ subject do
62
+ described_class.new(
63
+ nickname, source, parameters, attachments, packages, id, ready)
64
+ end
65
+
66
+ its(:title) { should == nickname }
67
+ its(:nickname) { should == nickname }
68
+ its(:source) { should == source }
69
+ its(:parameters) { should == parameters }
70
+ its(:attachments) { should == attachments }
71
+ its(:packages) { should == packages }
72
+ its(:id) { should == id }
73
+ its(:ready) { should == ready }
74
+ its(:external_inputs) { should be_nil }
75
+ its(:input_flags) { should be_nil }
76
+ its(:display_version) { should be_nil }
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,23 @@
1
+ #
2
+ # Copyright (c) 2009-2011 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec', 'spec_helper'))
@@ -0,0 +1,136 @@
1
+ #
2
+ # Copyright (c) 2012 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
24
+
25
+ describe "RightScale::DispatchedCache" do
26
+
27
+ include FlexMock::ArgumentTypes
28
+
29
+ before(:each) do
30
+ flexmock(RightScale::Log).should_receive(:error).by_default.and_return { |m| raise RightScale::Log.format(*m) }
31
+ flexmock(RightScale::Log).should_receive(:info).by_default
32
+ @now = Time.at(1000000)
33
+ flexmock(Time).should_receive(:now).and_return(@now).by_default
34
+ @agent_id = "rs-agent-1-1"
35
+ @cache = RightScale::DispatchedCache.new(@agent_id)
36
+ @token1 = "token1"
37
+ @token2 = "token2"
38
+ @token3 = "token3"
39
+ end
40
+
41
+ context "initialize" do
42
+
43
+ it "should initialize cache" do
44
+ @cache.instance_variable_get(:@cache).should == {}
45
+ @cache.instance_variable_get(:@lru).should == []
46
+ end
47
+
48
+ it "should initialize agent identity" do
49
+ @cache.instance_variable_get(:@identity).should == @agent_id
50
+ end
51
+
52
+ end
53
+
54
+ context "store" do
55
+
56
+ it "should store request token" do
57
+ @cache.store(@token1)
58
+ @cache.instance_variable_get(:@cache)[@token1].should == @now.to_i
59
+ @cache.instance_variable_get(:@lru).should == [@token1]
60
+ end
61
+
62
+ it "should update lru list when store to existing entry" do
63
+ @cache.store(@token1)
64
+ @cache.instance_variable_get(:@cache)[@token1].should == @now.to_i
65
+ @cache.instance_variable_get(:@lru).should == [@token1]
66
+ @cache.store(@token2)
67
+ @cache.instance_variable_get(:@cache)[@token2].should == @now.to_i
68
+ @cache.instance_variable_get(:@lru).should == [@token1, @token2]
69
+ flexmock(Time).should_receive(:now).and_return(@now += 10)
70
+ @cache.store(@token1)
71
+ @cache.instance_variable_get(:@cache)[@token1].should == @now.to_i
72
+ @cache.instance_variable_get(:@lru).should == [@token2, @token1]
73
+ end
74
+
75
+ it "should remove old cache entries when store new one" do
76
+ @cache.store(@token1)
77
+ @cache.store(@token2)
78
+ @cache.instance_variable_get(:@cache).keys.should =~ [@token1, @token2]
79
+ @cache.instance_variable_get(:@lru).should == [@token1, @token2]
80
+ flexmock(Time).should_receive(:now).and_return(@now += RightScale::DispatchedCache::MAX_AGE + 1)
81
+ @cache.store(@token3)
82
+ @cache.instance_variable_get(:@cache).keys.should == [@token3]
83
+ @cache.instance_variable_get(:@lru).should == [@token3]
84
+ end
85
+
86
+ it "should not store anything if token is nil" do
87
+ @cache.store(nil)
88
+ @cache.instance_variable_get(:@cache).should be_empty
89
+ @cache.instance_variable_get(:@lru).should be_empty
90
+ end
91
+
92
+ end
93
+
94
+ context "serviced_by" do
95
+
96
+ it "should return who request was serviced by and make it the most recently used" do
97
+ @cache.store(@token1)
98
+ @cache.store(@token2)
99
+ @cache.instance_variable_get(:@lru).should == [@token1, @token2]
100
+ @cache.serviced_by(@token1).should == @agent_id
101
+ @cache.instance_variable_get(:@lru).should == [@token2, @token1]
102
+ end
103
+
104
+ it "should return nil if request was not previously serviced" do
105
+ @cache.serviced_by(@token1).should be_nil
106
+ @cache.store(@token1)
107
+ @cache.serviced_by(@token1).should == @agent_id
108
+ @cache.serviced_by(@token2).should be_nil
109
+ end
110
+
111
+ end
112
+
113
+ context "stats" do
114
+
115
+ it "should return nil if cache empty" do
116
+ @cache.stats.should be_nil
117
+ end
118
+
119
+ it "should return total and max age" do
120
+ @cache.store(@token1)
121
+ flexmock(Time).should_receive(:now).and_return(@now += 10)
122
+ @cache.store(@token2)
123
+ @cache.stats.should == {
124
+ "local total" => 2,
125
+ "local max age" => "10 sec"
126
+ }
127
+ @cache.serviced_by(@token1)
128
+ @cache.stats.should == {
129
+ "local total" => 2,
130
+ "local max age" => "0 sec"
131
+ }
132
+ end
133
+
134
+ end
135
+
136
+ end # RightScale::Dispatcher
@@ -0,0 +1,324 @@
1
+ #
2
+ # Copyright (c) 2009-2012 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
24
+
25
+ class Foo
26
+ include RightScale::Actor
27
+ expose_idempotent :bar, :index, :i_kill_you
28
+ expose_non_idempotent :bar_non
29
+ on_exception :handle_exception
30
+
31
+ def index(payload)
32
+ bar(payload)
33
+ end
34
+
35
+ def bar(payload)
36
+ ['hello', payload]
37
+ end
38
+
39
+ def bar2(payload, request)
40
+ ['hello', payload, request]
41
+ end
42
+
43
+ def bar_non(payload)
44
+ @i = (@i || 0) + payload
45
+ end
46
+
47
+ def i_kill_you(payload)
48
+ raise RuntimeError.new('I kill you!')
49
+ end
50
+
51
+ def handle_exception(method, deliverable, error)
52
+ end
53
+ end
54
+
55
+ class Bar
56
+ include RightScale::Actor
57
+ expose :i_kill_you
58
+ on_exception do |method, deliverable, error|
59
+ @scope = self
60
+ @called_with = [method, deliverable, error]
61
+ end
62
+
63
+ def i_kill_you(payload)
64
+ raise RuntimeError.new('I kill you!')
65
+ end
66
+ end
67
+
68
+ # No specs, simply ensures multiple methods for assigning on_exception callback,
69
+ # on_exception raises exception when called with an invalid argument.
70
+ class Doomed
71
+ include RightScale::Actor
72
+ on_exception do
73
+ end
74
+ on_exception lambda {}
75
+ on_exception :doh
76
+ end
77
+
78
+ describe "RightScale::Dispatcher" do
79
+
80
+ include FlexMock::ArgumentTypes
81
+
82
+ before(:each) do
83
+ @log = flexmock(RightScale::Log)
84
+ @log.should_receive(:error).by_default.and_return { |m| raise RightScale::Log.format(*m) }
85
+ @log.should_receive(:info).by_default
86
+ @now = Time.at(1000000)
87
+ flexmock(Time).should_receive(:now).and_return(@now).by_default
88
+ @actor = Foo.new
89
+ @registry = RightScale::ActorRegistry.new
90
+ @registry.register(@actor, nil)
91
+ @agent_id = "rs-agent-1-1"
92
+ @agent = flexmock("Agent", :identity => @agent_id, :registry => @registry, :exception_callback => nil).by_default
93
+ @cache = RightScale::DispatchedCache.new(@agent_id)
94
+ @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
95
+ end
96
+
97
+ context "routable?" do
98
+
99
+ it "should return false if actor is not available for routing" do
100
+ @dispatcher.routable?("foo").should be_true
101
+ end
102
+
103
+ it "should return true if actor is available for routing" do
104
+ @dispatcher.routable?("bar").should be_false
105
+ end
106
+
107
+ end
108
+
109
+ context "dispatch" do
110
+
111
+ it "should dispatch a request" do
112
+ req = RightScale::Request.new('/foo/bar', 'you', :token => 'token')
113
+ res = @dispatcher.dispatch(req)
114
+ res.should(be_kind_of(RightScale::Result))
115
+ res.token.should == 'token'
116
+ res.results.should == ['hello', 'you']
117
+ end
118
+
119
+ it "should dispatch a request with required arity" do
120
+ req = RightScale::Request.new('/foo/bar2', 'you', :token => 'token')
121
+ res = @dispatcher.dispatch(req)
122
+ res.should(be_kind_of(RightScale::Result))
123
+ res.token.should == 'token'
124
+ res.results.should == ['hello', 'you', req]
125
+ end
126
+
127
+ it "should dispatch a request to the default action" do
128
+ req = RightScale::Request.new('/foo', 'you', :token => 'token')
129
+ res = @dispatcher.dispatch(req)
130
+ res.should(be_kind_of(RightScale::Result))
131
+ res.token.should == req.token
132
+ res.results.should == ['hello', 'you']
133
+ end
134
+
135
+ it "should return nil for successful push" do
136
+ req = RightScale::Push.new('/foo', 'you', :token => 'token')
137
+ res = @dispatcher.dispatch(req)
138
+ res.should be_nil
139
+ end
140
+
141
+ it "should handle custom prefixes" do
142
+ @registry.register(Foo.new, 'umbongo')
143
+ req = RightScale::Request.new('/umbongo/bar', 'you')
144
+ res = @dispatcher.dispatch(req)
145
+ res.should(be_kind_of(RightScale::Result))
146
+ res.token.should == req.token
147
+ res.results.should == ['hello', 'you']
148
+ end
149
+
150
+ it "should raise exception if actor is unknown" do
151
+ req = RightScale::Request.new('/bad', 'you', :token => 'token')
152
+ lambda { @dispatcher.dispatch(req) }.should raise_error(RightScale::Dispatcher::InvalidRequestType)
153
+ end
154
+
155
+ it "should raise exception if actor method is unknown" do
156
+ req = RightScale::Request.new('/foo/bar-none', 'you', :token => 'token')
157
+ lambda { @dispatcher.dispatch(req) }.should raise_error(RightScale::Dispatcher::InvalidRequestType)
158
+ end
159
+
160
+ it "should call the on_exception callback if something goes wrong" do
161
+ @log.should_receive(:error).once
162
+ req = RightScale::Request.new('/foo/i_kill_you', nil)
163
+ flexmock(@actor).should_receive(:handle_exception).with(:i_kill_you, req, Exception).once
164
+ res = @dispatcher.dispatch(req)
165
+ res.results.error?.should be_true
166
+ (res.results.content =~ /Could not handle \/foo\/i_kill_you request/).should be_true
167
+ end
168
+
169
+ it "should call on_exception Procs defined in a subclass with the correct arguments" do
170
+ @log.should_receive(:error).once
171
+ actor = Bar.new
172
+ @registry.register(actor, nil)
173
+ req = RightScale::Request.new('/bar/i_kill_you', nil)
174
+ @dispatcher.dispatch(req)
175
+ called_with = actor.instance_variable_get("@called_with")
176
+ called_with[0].should == :i_kill_you
177
+ called_with[1].should == req
178
+ called_with[2].should be_kind_of(RuntimeError)
179
+ called_with[2].message.should == 'I kill you!'
180
+ end
181
+
182
+ it "should call on_exception Procs defined in a subclass in the scope of the actor" do
183
+ @log.should_receive(:error).once
184
+ actor = Bar.new
185
+ @registry.register(actor, nil)
186
+ req = RightScale::Request.new('/bar/i_kill_you', nil)
187
+ @dispatcher.dispatch(req)
188
+ actor.instance_variable_get("@scope").should == actor
189
+ end
190
+
191
+ it "should log error if dispatch fails" do
192
+ RightScale::Log.should_receive(:error).once
193
+ req = RightScale::Request.new('/foo/i_kill_you', nil)
194
+ @dispatcher.dispatch(req)
195
+ end
196
+
197
+ it "should reject requests whose time-to-live has expired" do
198
+ flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
199
+ @log.should_receive(:info).once.with(on {|arg| arg =~ /REJECT EXPIRED.*TTL 2 sec ago/})
200
+ @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
201
+ req = RightScale::Push.new('/foo/bar', 'you', :expires_at => @now.to_i + 8)
202
+ flexmock(Time).should_receive(:now).and_return(@now += 10)
203
+ @dispatcher.dispatch(req).should be_nil
204
+ end
205
+
206
+ it "should return non-delivery result if Request is rejected because its time-to-live has expired" do
207
+ flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
208
+ @log.should_receive(:info).once.with(on {|arg| arg =~ /REJECT EXPIRED/})
209
+ @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
210
+ req = RightScale::Request.new('/foo/bar', 'you', {:reply_to => @response_queue, :expires_at => @now.to_i + 8})
211
+ flexmock(Time).should_receive(:now).and_return(@now += 10)
212
+ res = @dispatcher.dispatch(req)
213
+ res.results.non_delivery?.should be_true
214
+ res.results.content.should == RightScale::OperationResult::TTL_EXPIRATION
215
+ end
216
+
217
+ it "should return error result instead of non-delivery if agent does not know about non-delivery" do
218
+ flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
219
+ @log.should_receive(:info).once.with(on {|arg| arg =~ /REJECT EXPIRED/})
220
+ @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
221
+ req = RightScale::Request.new('/foo/bar', 'you', {:reply_to => "rs-router-1-1", :expires_at => @now.to_i + 8},
222
+ [version_cannot_handle_non_delivery_result, RightScale::AgentConfig.protocol_version])
223
+ flexmock(Time).should_receive(:now).and_return(@now += 10)
224
+ res = @dispatcher.dispatch(req)
225
+ res.results.error?.should be_true
226
+ res.results.content.should =~ /Could not deliver/
227
+ end
228
+
229
+ it "should not reject requests whose time-to-live has not expired" do
230
+ flexmock(Time).should_receive(:now).and_return(Time.at(1000000)).by_default
231
+ @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
232
+ req = RightScale::Request.new('/foo/bar', 'you', :expires_at => @now.to_i + 11)
233
+ flexmock(Time).should_receive(:now).and_return(@now += 10)
234
+ res = @dispatcher.dispatch(req)
235
+ res.should(be_kind_of(RightScale::Result))
236
+ res.token.should == req.token
237
+ res.results.should == ['hello', 'you']
238
+ end
239
+
240
+ it "should not check age of requests with time-to-live check disabled" do
241
+ @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
242
+ req = RightScale::Request.new('/foo/bar', 'you', :expires_at => 0)
243
+ res = @dispatcher.dispatch(req)
244
+ res.should(be_kind_of(RightScale::Result))
245
+ res.token.should == req.token
246
+ res.results.should == ['hello', 'you']
247
+ end
248
+
249
+ it "should reject duplicate request by raising exception" do
250
+ @log.should_receive(:info).once.with(on {|arg| arg =~ /REJECT DUP/})
251
+ EM.run do
252
+ @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
253
+ req = RightScale::Request.new('/foo/bar_non', 1, :token => "try")
254
+ @cache.store(req.token)
255
+ lambda { @dispatcher.dispatch(req) }.should raise_error(RightScale::Dispatcher::DuplicateRequest)
256
+ EM.stop
257
+ end
258
+ end
259
+
260
+ it "should reject duplicate request from a retry by raising exception" do
261
+ @log.should_receive(:info).once.with(on {|arg| arg =~ /REJECT RETRY DUP/})
262
+ EM.run do
263
+ @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
264
+ req = RightScale::Request.new('/foo/bar_non', 1, :token => "try")
265
+ req.tries.concat(["try1", "try2"])
266
+ @cache.store("try2")
267
+ lambda { @dispatcher.dispatch(req) }.should raise_error(RightScale::Dispatcher::DuplicateRequest)
268
+ EM.stop
269
+ end
270
+ end
271
+
272
+ it "should not reject non-duplicate requests" do
273
+ EM.run do
274
+ @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
275
+ req = RightScale::Request.new('/foo/bar_non', 1, :token => "try")
276
+ req.tries.concat(["try1", "try2"])
277
+ @cache.store("try3")
278
+ @dispatcher.dispatch(req).should_not be_nil
279
+ EM.stop
280
+ end
281
+ end
282
+
283
+ it "should not reject duplicate idempotent requests" do
284
+ EM.run do
285
+ @dispatcher = RightScale::Dispatcher.new(@agent, @cache)
286
+ req = RightScale::Request.new('/foo/bar', 'you', :token => "try")
287
+ @cache.store(req.token)
288
+ @dispatcher.dispatch(req).should_not be_nil
289
+ EM.stop
290
+ end
291
+ end
292
+
293
+ it "should not check for duplicates if duplicate checking is disabled" do
294
+ EM.run do
295
+ @dispatcher = RightScale::Dispatcher.new(@agent, dispatched_cache = nil)
296
+ req = RightScale::Request.new('/foo/bar_non', 1, :token => "try")
297
+ req.tries.concat(["try1", "try2"])
298
+ @dispatcher.instance_variable_get(:@dispatched_cache).should be_nil
299
+ @dispatcher.dispatch(req).should_not be_nil
300
+ EM.stop
301
+ end
302
+ end
303
+
304
+ it "should not check for duplicates if actor method is idempotent" do
305
+ EM.run do
306
+ @dispatcher = RightScale::Dispatcher.new(@agent, dispatched_cache = nil)
307
+ req = RightScale::Request.new('/foo/bar', 1, :token => "try")
308
+ req.tries.concat(["try1", "try2"])
309
+ @dispatcher.instance_variable_get(:@dispatched_cache).should be_nil
310
+ @dispatcher.dispatch(req).should_not be_nil
311
+ EM.stop
312
+ end
313
+ end
314
+
315
+ it "should return error result if dispatch fails" do
316
+ @log.should_receive(:error).with(/Could not handle/, Exception, :trace).once
317
+ req = RightScale::Request.new('/foo/i_kill_you', nil)
318
+ res = @dispatcher.dispatch(req)
319
+ res.results.error?.should be_true
320
+ end
321
+
322
+ end
323
+
324
+ end # RightScale::Dispatcher