right_agent 0.5.1

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 (147) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +78 -0
  3. data/Rakefile +86 -0
  4. data/lib/right_agent.rb +66 -0
  5. data/lib/right_agent/actor.rb +163 -0
  6. data/lib/right_agent/actor_registry.rb +76 -0
  7. data/lib/right_agent/actors/agent_manager.rb +189 -0
  8. data/lib/right_agent/agent.rb +735 -0
  9. data/lib/right_agent/agent_config.rb +403 -0
  10. data/lib/right_agent/agent_identity.rb +209 -0
  11. data/lib/right_agent/agent_tags_manager.rb +213 -0
  12. data/lib/right_agent/audit_formatter.rb +107 -0
  13. data/lib/right_agent/broker_client.rb +683 -0
  14. data/lib/right_agent/command.rb +30 -0
  15. data/lib/right_agent/command/agent_manager_commands.rb +134 -0
  16. data/lib/right_agent/command/command_client.rb +136 -0
  17. data/lib/right_agent/command/command_constants.rb +42 -0
  18. data/lib/right_agent/command/command_io.rb +128 -0
  19. data/lib/right_agent/command/command_parser.rb +87 -0
  20. data/lib/right_agent/command/command_runner.rb +105 -0
  21. data/lib/right_agent/command/command_serializer.rb +63 -0
  22. data/lib/right_agent/console.rb +65 -0
  23. data/lib/right_agent/core_payload_types.rb +42 -0
  24. data/lib/right_agent/core_payload_types/cookbook.rb +61 -0
  25. data/lib/right_agent/core_payload_types/cookbook_position.rb +46 -0
  26. data/lib/right_agent/core_payload_types/cookbook_repository.rb +116 -0
  27. data/lib/right_agent/core_payload_types/cookbook_sequence.rb +70 -0
  28. data/lib/right_agent/core_payload_types/dev_repositories.rb +90 -0
  29. data/lib/right_agent/core_payload_types/event_categories.rb +38 -0
  30. data/lib/right_agent/core_payload_types/executable_bundle.rb +138 -0
  31. data/lib/right_agent/core_payload_types/login_policy.rb +72 -0
  32. data/lib/right_agent/core_payload_types/login_user.rb +62 -0
  33. data/lib/right_agent/core_payload_types/planned_volume.rb +94 -0
  34. data/lib/right_agent/core_payload_types/recipe_instantiation.rb +60 -0
  35. data/lib/right_agent/core_payload_types/repositories_bundle.rb +50 -0
  36. data/lib/right_agent/core_payload_types/right_script_attachment.rb +95 -0
  37. data/lib/right_agent/core_payload_types/right_script_instantiation.rb +73 -0
  38. data/lib/right_agent/core_payload_types/secure_document.rb +66 -0
  39. data/lib/right_agent/core_payload_types/secure_document_location.rb +63 -0
  40. data/lib/right_agent/core_payload_types/software_repository_instantiation.rb +61 -0
  41. data/lib/right_agent/daemonize.rb +35 -0
  42. data/lib/right_agent/dispatcher.rb +348 -0
  43. data/lib/right_agent/enrollment_result.rb +217 -0
  44. data/lib/right_agent/exceptions.rb +30 -0
  45. data/lib/right_agent/ha_broker_client.rb +1278 -0
  46. data/lib/right_agent/idempotent_request.rb +140 -0
  47. data/lib/right_agent/log.rb +418 -0
  48. data/lib/right_agent/monkey_patches.rb +29 -0
  49. data/lib/right_agent/monkey_patches/amqp_patch.rb +274 -0
  50. data/lib/right_agent/monkey_patches/ruby_patch.rb +49 -0
  51. data/lib/right_agent/monkey_patches/ruby_patch/array_patch.rb +29 -0
  52. data/lib/right_agent/monkey_patches/ruby_patch/darwin_patch.rb +24 -0
  53. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch.rb +24 -0
  54. data/lib/right_agent/monkey_patches/ruby_patch/linux_patch/file_patch.rb +30 -0
  55. data/lib/right_agent/monkey_patches/ruby_patch/object_patch.rb +49 -0
  56. data/lib/right_agent/monkey_patches/ruby_patch/singleton_patch.rb +46 -0
  57. data/lib/right_agent/monkey_patches/ruby_patch/string_patch.rb +107 -0
  58. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch.rb +32 -0
  59. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/file_patch.rb +90 -0
  60. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/process_patch.rb +63 -0
  61. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/stdio_patch.rb +27 -0
  62. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/time_patch.rb +55 -0
  63. data/lib/right_agent/monkey_patches/ruby_patch/windows_patch/win32ole_patch.rb +34 -0
  64. data/lib/right_agent/multiplexer.rb +91 -0
  65. data/lib/right_agent/operation_result.rb +270 -0
  66. data/lib/right_agent/packets.rb +637 -0
  67. data/lib/right_agent/payload_formatter.rb +104 -0
  68. data/lib/right_agent/pid_file.rb +159 -0
  69. data/lib/right_agent/platform.rb +319 -0
  70. data/lib/right_agent/platform/darwin.rb +227 -0
  71. data/lib/right_agent/platform/linux.rb +268 -0
  72. data/lib/right_agent/platform/windows.rb +1204 -0
  73. data/lib/right_agent/scripts/agent_controller.rb +522 -0
  74. data/lib/right_agent/scripts/agent_deployer.rb +379 -0
  75. data/lib/right_agent/scripts/common_parser.rb +153 -0
  76. data/lib/right_agent/scripts/log_level_manager.rb +193 -0
  77. data/lib/right_agent/scripts/stats_manager.rb +256 -0
  78. data/lib/right_agent/scripts/usage.rb +58 -0
  79. data/lib/right_agent/secure_identity.rb +92 -0
  80. data/lib/right_agent/security.rb +32 -0
  81. data/lib/right_agent/security/cached_certificate_store_proxy.rb +63 -0
  82. data/lib/right_agent/security/certificate.rb +102 -0
  83. data/lib/right_agent/security/certificate_cache.rb +89 -0
  84. data/lib/right_agent/security/distinguished_name.rb +56 -0
  85. data/lib/right_agent/security/encrypted_document.rb +84 -0
  86. data/lib/right_agent/security/rsa_key_pair.rb +76 -0
  87. data/lib/right_agent/security/signature.rb +86 -0
  88. data/lib/right_agent/security/static_certificate_store.rb +69 -0
  89. data/lib/right_agent/sender.rb +937 -0
  90. data/lib/right_agent/serialize.rb +29 -0
  91. data/lib/right_agent/serialize/message_pack.rb +102 -0
  92. data/lib/right_agent/serialize/secure_serializer.rb +131 -0
  93. data/lib/right_agent/serialize/secure_serializer_initializer.rb +47 -0
  94. data/lib/right_agent/serialize/serializable.rb +135 -0
  95. data/lib/right_agent/serialize/serializer.rb +149 -0
  96. data/lib/right_agent/stats_helper.rb +731 -0
  97. data/lib/right_agent/subprocess.rb +38 -0
  98. data/lib/right_agent/tracer.rb +124 -0
  99. data/right_agent.gemspec +60 -0
  100. data/spec/actor_registry_spec.rb +81 -0
  101. data/spec/actor_spec.rb +99 -0
  102. data/spec/agent_config_spec.rb +226 -0
  103. data/spec/agent_identity_spec.rb +75 -0
  104. data/spec/agent_spec.rb +571 -0
  105. data/spec/broker_client_spec.rb +961 -0
  106. data/spec/command/agent_manager_commands_spec.rb +51 -0
  107. data/spec/command/command_io_spec.rb +93 -0
  108. data/spec/command/command_parser_spec.rb +79 -0
  109. data/spec/command/command_runner_spec.rb +72 -0
  110. data/spec/command/command_serializer_spec.rb +51 -0
  111. data/spec/core_payload_types/dev_repositories_spec.rb +64 -0
  112. data/spec/core_payload_types/executable_bundle_spec.rb +59 -0
  113. data/spec/core_payload_types/login_user_spec.rb +98 -0
  114. data/spec/core_payload_types/right_script_attachment_spec.rb +65 -0
  115. data/spec/core_payload_types/spec_helper.rb +23 -0
  116. data/spec/dispatcher_spec.rb +372 -0
  117. data/spec/enrollment_result_spec.rb +53 -0
  118. data/spec/ha_broker_client_spec.rb +1673 -0
  119. data/spec/idempotent_request_spec.rb +136 -0
  120. data/spec/log_spec.rb +177 -0
  121. data/spec/monkey_patches/amqp_patch_spec.rb +100 -0
  122. data/spec/monkey_patches/eventmachine_spec.rb +62 -0
  123. data/spec/monkey_patches/string_patch_spec.rb +99 -0
  124. data/spec/multiplexer_spec.rb +48 -0
  125. data/spec/operation_result_spec.rb +171 -0
  126. data/spec/packets_spec.rb +418 -0
  127. data/spec/platform/platform_spec.rb +60 -0
  128. data/spec/results_mock.rb +45 -0
  129. data/spec/secure_identity_spec.rb +50 -0
  130. data/spec/security/cached_certificate_store_proxy_spec.rb +56 -0
  131. data/spec/security/certificate_cache_spec.rb +71 -0
  132. data/spec/security/certificate_spec.rb +49 -0
  133. data/spec/security/distinguished_name_spec.rb +46 -0
  134. data/spec/security/encrypted_document_spec.rb +55 -0
  135. data/spec/security/rsa_key_pair_spec.rb +55 -0
  136. data/spec/security/signature_spec.rb +66 -0
  137. data/spec/security/static_certificate_store_spec.rb +52 -0
  138. data/spec/sender_spec.rb +887 -0
  139. data/spec/serialize/message_pack_spec.rb +131 -0
  140. data/spec/serialize/secure_serializer_spec.rb +102 -0
  141. data/spec/serialize/serializable_spec.rb +90 -0
  142. data/spec/serialize/serializer_spec.rb +174 -0
  143. data/spec/spec.opts +2 -0
  144. data/spec/spec_helper.rb +77 -0
  145. data/spec/stats_helper_spec.rb +681 -0
  146. data/spec/tracer_spec.rb +114 -0
  147. metadata +320 -0
@@ -0,0 +1,99 @@
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_helper'))
24
+
25
+ describe String do
26
+
27
+ describe ".snake_case" do
28
+
29
+ it "should downcase single word" do
30
+ ["FOO", "Foo", "foo"].each do |w|
31
+ w.snake_case.should == "foo"
32
+ end
33
+ end
34
+
35
+ it "should not separate numbers from end of word" do
36
+ ["Foo1234", "foo1234"].each do |w|
37
+ w.snake_case.should == "foo1234"
38
+ end
39
+ end
40
+
41
+ it "should not separate numbers from word that starts with uppercase letter" do
42
+ "1234Foo".snake_case.should == "1234foo"
43
+ end
44
+
45
+ it "should not separate numbers from word that starts with lowercase letter" do
46
+ "1234foo".snake_case.should == "1234foo"
47
+ end
48
+
49
+ it "should downcase camel-cased words and connect with underscore" do
50
+ ["FooBar", "fooBar"].each do |w|
51
+ w.snake_case.should == "foo_bar"
52
+ end
53
+ end
54
+
55
+ it "should start new word with uppercase letter before lower case letter" do
56
+ ["FooBARBaz", "fooBARBaz"].each do |w|
57
+ w.snake_case.should == "foo_bar_baz"
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ describe ".to_const_path" do
64
+
65
+ it "should snake-case the string" do
66
+ "Hello::World".to_const_path.should == "hello/world"
67
+ end
68
+
69
+ it "should leave (snake-cased) string without '::' unchanged" do
70
+ "hello".to_const_path.should == "hello"
71
+ end
72
+
73
+ it "should replace single '::' with '/'" do
74
+ "hello::world".to_const_path.should == "hello/world"
75
+ end
76
+
77
+ it "should replace multiple '::' with '/'" do
78
+ "hello::rightscale::world".to_const_path.should == "hello/rightscale/world"
79
+ end
80
+
81
+ end
82
+
83
+ describe '.camelize' do
84
+
85
+ it 'should camelize the string' do
86
+ 'hello/world_hello'.camelize.should == 'Hello::WorldHello'
87
+ end
88
+
89
+ it 'should camelize strings with integers' do
90
+ '1hel2lo3/4wor5ld6_7hel8lo9'.camelize.should == '1hel2lo3::4wor5ld67hel8lo9'
91
+ end
92
+
93
+ it 'should leave camelized strings alone' do
94
+ '1Hel2lo3::4Wor5ld67Hel8lo9'.camelize.should == '1Hel2lo3::4Wor5ld67Hel8lo9'
95
+ end
96
+
97
+ end
98
+
99
+ end # String
@@ -0,0 +1,48 @@
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_helper'))
24
+
25
+ describe RightScale::Multiplexer do
26
+
27
+ before(:all) do
28
+ @target1 = flexmock('Target 1')
29
+ @target2 = flexmock('Target 2')
30
+ @target3 = flexmock('Target 3')
31
+ @multiplexer = RightScale::Multiplexer.new(@target1, @target2, @target3)
32
+ end
33
+
34
+ it 'should multiplex' do
35
+ @target1.should_receive(:some_method).once.with('arg', 'arg2').once
36
+ @target2.should_receive(:some_method).once.with('arg', 'arg2').once
37
+ @target3.should_receive(:some_method).once.with('arg', 'arg2').once
38
+ @multiplexer.some_method('arg', 'arg2')
39
+ end
40
+
41
+ it 'should retrieve the first result' do
42
+ @target1.should_receive(:some_method).once.with('arg', 'arg2').and_return('res1').once
43
+ @target2.should_receive(:some_method).once.with('arg', 'arg2').and_return('res2').once
44
+ @target3.should_receive(:some_method).once.with('arg', 'arg2').and_return('res3').once
45
+ @multiplexer.some_method('arg', 'arg2').should == 'res1'
46
+ end
47
+
48
+ end
@@ -0,0 +1,171 @@
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_helper'))
24
+
25
+ describe RightScale::OperationResult do
26
+
27
+ describe "when fetching results" do
28
+
29
+ before do
30
+ @success1 = RightScale::OperationResult.success(1)
31
+ @success2 = RightScale::OperationResult.success(2)
32
+ @simple_result = RightScale::Result.new("token", "to", @success1, "from")
33
+ @hash = {"from1" => @success1, "from2" => @success2}
34
+ @hash_result = RightScale::Result.new("token", "to", @hash, "from")
35
+ @nil_result = RightScale::Result.new("token", "to", nil, "from")
36
+ @error_result = RightScale::Result.new("token", "to", RightScale::OperationResult.error("Error"), "from")
37
+ end
38
+
39
+ it "should handle results hash and return only first value as an OperationResult" do
40
+ result = RightScale::OperationResult.from_results(@hash)
41
+ result.kind_of?(RightScale::OperationResult).should be_true
42
+ result.status_code.should == RightScale::OperationResult::SUCCESS
43
+ result.content.should == 1
44
+ end
45
+
46
+ it "should handle individual result and return it as an OperationResult" do
47
+ result = RightScale::OperationResult.from_results(@simple_result)
48
+ result.kind_of?(RightScale::OperationResult).should be_true
49
+ result.status_code.should == RightScale::OperationResult::SUCCESS
50
+ result.content.should == 1
51
+ end
52
+
53
+ it "should handle non-success result and return it as an OperationResult" do
54
+ result = RightScale::OperationResult.from_results(@error_result)
55
+ result.kind_of?(RightScale::OperationResult).should be_true
56
+ result.status_code.should == RightScale::OperationResult::ERROR
57
+ result.content.should == "Error"
58
+ end
59
+
60
+ it "should return error OperationResult if results is nil" do
61
+ result = RightScale::OperationResult.from_results(nil)
62
+ result.kind_of?(RightScale::OperationResult).should be_true
63
+ result.status_code.should == RightScale::OperationResult::ERROR
64
+ result.content.should == "No results"
65
+ end
66
+
67
+ it "should return error OperationResult if the results value is not recognized" do
68
+ result = RightScale::OperationResult.from_results(0)
69
+ result.kind_of?(RightScale::OperationResult).should be_true
70
+ result.status_code.should == RightScale::OperationResult::ERROR
71
+ result.content.should == "Invalid operation result type: 0"
72
+ end
73
+ end
74
+
75
+ describe "when handling each type of result" do
76
+
77
+ it "should store success content value and respond to success query" do
78
+ result = RightScale::OperationResult.success({})
79
+ result.kind_of?(RightScale::OperationResult).should be_true
80
+ result.success?.should be_true
81
+ result.error?.should be_false
82
+ result.continue?.should be_false
83
+ result.retry?.should be_false
84
+ result.non_delivery?.should be_false
85
+ result.content.should == {}
86
+ end
87
+
88
+ it "should treat non-delivery as error" do
89
+ RightScale::OperationResult.non_delivery(0).error?.should be_true
90
+ end
91
+
92
+ it "should store error content value and respond to error query" do
93
+ result = RightScale::OperationResult.error("Error")
94
+ result.kind_of?(RightScale::OperationResult).should be_true
95
+ result.error?.should be_true
96
+ result.content.should == "Error"
97
+ end
98
+
99
+ it 'should store additional error string when given' do
100
+ result = RightScale::OperationResult.error("Error", "details")
101
+ result.kind_of?(RightScale::OperationResult).should be_true
102
+ result.error?.should be_true
103
+ result.content.should == "Error (details)"
104
+ end
105
+
106
+ it "should store exception info in error content value when given" do
107
+ begin
108
+ nil + "string"
109
+ rescue Exception => e
110
+ result = RightScale::OperationResult.error("Error", e)
111
+ end
112
+ result.kind_of?(RightScale::OperationResult).should be_true
113
+ result.error?.should be_true
114
+ (result.content =~ /Error \(NoMethodError: undefined method \`\+' for nil:NilClass in .*operation_result_spec.*\)$/).should be_true
115
+ end
116
+
117
+ it "should store continue content value and respond to continue query" do
118
+ result = RightScale::OperationResult.continue("Continue")
119
+ result.kind_of?(RightScale::OperationResult).should be_true
120
+ result.continue?.should be_true
121
+ result.content.should == "Continue"
122
+ end
123
+
124
+ it "should store retry content value and respond to retry query" do
125
+ result = RightScale::OperationResult.retry("Retry")
126
+ result.kind_of?(RightScale::OperationResult).should be_true
127
+ result.retry?.should be_true
128
+ result.content.should == "Retry"
129
+ end
130
+
131
+ it "should store multicast targets" do
132
+ result = RightScale::OperationResult.multicast(["target"])
133
+ result.kind_of?(RightScale::OperationResult).should be_true
134
+ result.content.should == ["target"]
135
+ end
136
+
137
+ it "should store non-delivery content value and respond to non-delivery query" do
138
+ result = RightScale::OperationResult.non_delivery("Non-delivery")
139
+ result.kind_of?(RightScale::OperationResult).should be_true
140
+ result.non_delivery?.should be_true
141
+ result.content.should == "Non-delivery"
142
+ end
143
+ end
144
+
145
+ describe "when converting result to string" do
146
+
147
+ it "should display error message" do
148
+ result = RightScale::OperationResult.error("some problem")
149
+ result.to_s.should == "error (some problem)"
150
+ end
151
+
152
+ it "should convert error content to string if necessary" do
153
+ result = RightScale::OperationResult.error({"data" => "some data", "message" => "some problem"})
154
+ result.to_s.should == "error ({\"data\"=>\"some data\", \"message\"=>\"some problem\"})"
155
+ end
156
+
157
+ it "should truncate error message if too long" do
158
+ result = RightScale::OperationResult.error("123456789012345678901234567890123456789012345678901234567890")
159
+ result.to_s.should == "error (123456789012345678901234567890123456789012345678901234567...)"
160
+ result.status.should == "error"
161
+ end
162
+
163
+ it "should display non-delivery reason" do
164
+ result = RightScale::OperationResult.non_delivery(RightScale::OperationResult::TTL_EXPIRATION)
165
+ result.to_s.should == "non-delivery (TTL expiration)"
166
+ result.status.should == "non-delivery"
167
+ end
168
+
169
+ end
170
+
171
+ end
@@ -0,0 +1,418 @@
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_helper'))
24
+
25
+ class TestPacket < RightScale::Packet
26
+ @@cls_attr = "ignore"
27
+ def initialize(attr1, duration = nil, size = nil)
28
+ @attr1 = attr1
29
+ @duration = duration
30
+ @size = size
31
+ @version = [RightScale::Packet::VERSION, RightScale::Packet::VERSION]
32
+ end
33
+ end
34
+
35
+ describe "Packet: Base class" do
36
+
37
+ it "should be an abstract class" do
38
+ lambda { RightScale::Packet.new }.should raise_error(NotImplementedError, "RightScale::Packet is an abstract class.")
39
+ end
40
+
41
+ it "should retrieve version" do
42
+ packet = TestPacket.new(1)
43
+ packet.recv_version.should == RightScale::Packet::VERSION
44
+ packet.send_version.should == RightScale::Packet::VERSION
45
+ end
46
+
47
+ it "should store version" do
48
+ packet = TestPacket.new(1)
49
+ packet.send_version.should == RightScale::Packet::VERSION
50
+ packet.send_version = 5
51
+ packet.send_version.should == 5
52
+ lambda { packet.recv_version = 5 }.should raise_error
53
+ end
54
+
55
+ it "should convert to string with packet name in lower snake case" do
56
+ packet = TestPacket.new(1)
57
+ packet.name.should == "test_packet"
58
+ packet.to_s.should == "[test_packet]"
59
+ end
60
+
61
+ it "should convert to string including version if requested" do
62
+ packet = TestPacket.new(1)
63
+ packet.send_version = 5
64
+ packet.to_s(filter = nil, version = :recv_version).should == "[test_packet v#{RightScale::Packet::VERSION}]"
65
+ packet.to_s(filter = nil, version = :send_version).should == "[test_packet v5]"
66
+ end
67
+
68
+ it "should convert to string including duration if filtered and size is also known" do
69
+ packet = TestPacket.new(1, 0.042122, 323)
70
+ packet.to_s(filter = nil).should == "[test_packet] (323 bytes, 0.042 sec)"
71
+ packet.to_s(filter = []).should == "[test_packet] (323 bytes)"
72
+ packet.to_s(filter = [:duration]).should == "[test_packet] (323 bytes, 0.042 sec)"
73
+ packet = TestPacket.new(1, 0.042122)
74
+ packet.to_s(filter = [:duration]).should == "[test_packet]"
75
+ end
76
+
77
+ it "should convert floating point values to decimal digit string with at least two digit precision" do
78
+ packet = TestPacket.new(1)
79
+ packet.enough_precision(100.5).should == "101"
80
+ packet.enough_precision(100.4).should == "100"
81
+ packet.enough_precision(99.0).should == "99"
82
+ packet.enough_precision(10.5).should == "11"
83
+ packet.enough_precision(10.4).should == "10"
84
+ packet.enough_precision(9.15).should == "9.2"
85
+ packet.enough_precision(9.1).should == "9.1"
86
+ packet.enough_precision(1.05).should == "1.1"
87
+ packet.enough_precision(1.01).should == "1.0"
88
+ packet.enough_precision(1.0).should == "1.0"
89
+ packet.enough_precision(0.995).should == "1.00"
90
+ packet.enough_precision(0.991).should == "0.99"
91
+ packet.enough_precision(0.0995).should == "0.100"
92
+ packet.enough_precision(0.0991).should == "0.099"
93
+ packet.enough_precision(0.00995).should == "0.0100"
94
+ packet.enough_precision(0.00991).should == "0.0099"
95
+ packet.enough_precision(0.000995).should == "0.00100"
96
+ packet.enough_precision(0.000991).should == "0.00099"
97
+ packet.enough_precision(0.000005).should == "0.00001"
98
+ packet.enough_precision(0.000001).should == "0.00000"
99
+ packet.enough_precision(0.0).should == "0"
100
+ packet.enough_precision(55).should == "55"
101
+ end
102
+
103
+ it "should be one-way by default" do
104
+ TestPacket.new(1).one_way.should be_true
105
+ end
106
+
107
+ describe "using MessagePack" do
108
+ it "should know how to dump itself to MessagePack" do
109
+ packet = TestPacket.new(1)
110
+ packet.should respond_to(:to_msgpack)
111
+ end
112
+
113
+ it "should dump the class name in 'msgpack_class' key" do
114
+ packet = TestPacket.new(42)
115
+ packet.to_msgpack.should =~ /msgpack_class.*TestPacket/
116
+ end
117
+
118
+ it "should dump instance variables in 'data' key" do
119
+ packet = TestPacket.new(188)
120
+ packet.to_msgpack.should =~ /data.*attr1/
121
+ end
122
+
123
+ it "should not dump class variables" do
124
+ packet = TestPacket.new(382)
125
+ packet.to_msgpack.should_not =~ /cls_attr/
126
+ end
127
+
128
+ it "should remove '@' from instance variables" do
129
+ packet = TestPacket.new(2)
130
+ packet.to_msgpack.should_not =~ /@attr1/
131
+ packet.to_msgpack.should =~ /attr1/
132
+ end
133
+ end
134
+
135
+ describe "using JSON" do
136
+ it "should know how to dump itself to JSON" do
137
+ packet = TestPacket.new(1)
138
+ packet.should respond_to(:to_json)
139
+ end
140
+
141
+ it "should dump the class name in 'json_class' key" do
142
+ packet = TestPacket.new(42)
143
+ packet.to_json.should =~ /\"json_class\":\"TestPacket\"/
144
+ end
145
+
146
+ it "should dump instance variables in 'data' key" do
147
+ packet = TestPacket.new(188, nil, 323)
148
+ json = packet.to_json
149
+ json.should =~ /\"data\":\{.*\"attr1\":188.*\}/
150
+ json.should =~ /\"data\":\{.*\"duration\":null.*\}/
151
+ json.should =~ /\"data\":\{.*\"size\":323.*\}/
152
+ json.should =~ /\"data\":\{.*\"version\":\[\d*,\d*\].*\}/
153
+ end
154
+
155
+ it "should not dump class variables" do
156
+ packet = TestPacket.new(382)
157
+ packet.to_json.should_not =~ /cls_attr/
158
+ end
159
+
160
+ it "should remove '@' from instance variables" do
161
+ packet = TestPacket.new(2)
162
+ packet.to_json.should_not =~ /@attr1/
163
+ packet.to_json.should =~ /attr1/
164
+ end
165
+ end
166
+ end
167
+
168
+
169
+ describe "Packet: Request" do
170
+ it "should dump/load as MessagePack objects" do
171
+ packet = RightScale::Request.new('/some/foo', 'payload', :from => 'from', :token => '0xdeadbeef',
172
+ :reply_to => 'reply_to', :tries => ['try'])
173
+ packet2 = MessagePack.load(packet.to_msgpack)
174
+ packet.type.should == packet2.type
175
+ packet.payload.should == packet2.payload
176
+ packet.from.should == packet2.from
177
+ packet.scope.should == packet2.scope
178
+ packet.token.should == packet2.token
179
+ packet.reply_to.should == packet2.reply_to
180
+ packet.tries.should == packet2.tries
181
+ packet.expires_at.should == packet2.expires_at
182
+ packet.recv_version.should == packet2.recv_version
183
+ packet.send_version.should == packet2.send_version
184
+ end
185
+
186
+ it "should dump/load as JSON objects" do
187
+ packet = RightScale::Request.new('/some/foo', 'payload', :from => 'from', :token => '0xdeadbeef',
188
+ :reply_to => 'reply_to', :tries => ['try'])
189
+ packet2 = JSON.load(packet.to_json)
190
+ packet.type.should == packet2.type
191
+ packet.payload.should == packet2.payload
192
+ packet.from.should == packet2.from
193
+ packet.scope.should == packet2.scope
194
+ packet.token.should == packet2.token
195
+ packet.reply_to.should == packet2.reply_to
196
+ packet.tries.should == packet2.tries
197
+ packet.expires_at.should == packet2.expires_at
198
+ packet.recv_version.should == packet2.recv_version
199
+ packet.send_version.should == packet2.send_version
200
+ end
201
+
202
+ it "should default selector to :any" do
203
+ packet = RightScale::Request.new('/some/foo', 'payload')
204
+ packet.selector.should == :any
205
+ end
206
+
207
+ it "should convert selector from :least_loaded or :random to :any" do
208
+ packet = RightScale::Request.new('/some/foo', 'payload', :selector => :least_loaded)
209
+ packet.selector.should == :any
210
+ packet = RightScale::Request.new('/some/foo', 'payload', :selector => "least_loaded")
211
+ packet.selector.should == :any
212
+ packet = RightScale::Request.new('/some/foo', 'payload', :selector => :random)
213
+ packet.selector.should == :any
214
+ packet = RightScale::Request.new('/some/foo', 'payload', :selector => "random")
215
+ packet.selector.should == :any
216
+ packet = RightScale::Request.new('/some/foo', 'payload', :selector => :any)
217
+ packet.selector.should == :any
218
+ packet = RightScale::Request.new('/some/foo', 'payload')
219
+ packet.selector.should == :any
220
+ end
221
+
222
+ it "should distinguish fanout request" do
223
+ RightScale::Request.new('/some/foo', 'payload').fanout?.should be_false
224
+ RightScale::Request.new('/some/foo', 'payload', :selector => 'all').fanout?.should be_true
225
+ end
226
+
227
+ it "should convert created_at to expires_at" do
228
+ packet = RightScale::Request.new('/some/foo', 'payload', :expires_at => 100000)
229
+ packet2 = JSON.parse(packet.to_json.sub("expires_at", "created_at"))
230
+ packet2.expires_at.should == 100900
231
+ packet = RightScale::Request.new('/some/foo', 'payload', :expires_at => 0)
232
+ packet2 = JSON.parse(packet.to_json.sub("expires_at", "created_at"))
233
+ packet2.expires_at.should == 0
234
+ end
235
+
236
+ it "should not be one-way" do
237
+ RightScale::Request.new('/some/foo', 'payload').one_way.should be_false
238
+ end
239
+
240
+ it "should use current version by default when constructing" do
241
+ packet = RightScale::Request.new('/some/foo', 'payload', :from => 'from', :token => '0xdeadbeef',
242
+ :reply_to => 'reply_to', :tries => ['try'])
243
+ packet.recv_version.should == RightScale::Packet::VERSION
244
+ packet.send_version.should == RightScale::Packet::VERSION
245
+ end
246
+
247
+ it "should use default version if none supplied when unmarshalling" do
248
+ packet = RightScale::Request.new('/some/foo', 'payload', :from => 'from', :token => '0xdeadbeef',
249
+ :reply_to => 'reply_to', :tries => ['try'])
250
+ packet.instance_variable_set(:@version, nil)
251
+ MessagePack.load(packet.to_msgpack).send_version.should == RightScale::Packet::DEFAULT_VERSION
252
+ JSON.load(packet.to_json).send_version.should == RightScale::Packet::DEFAULT_VERSION
253
+ end
254
+ end
255
+
256
+
257
+ describe "Packet: Push" do
258
+ it "should dump/load as MessagePack objects" do
259
+ packet = RightScale::Push.new('/some/foo', 'payload', :from => 'from', :token => '0xdeadbeef', :tries => ['try'])
260
+ packet2 = MessagePack.load(packet.to_msgpack)
261
+ packet.type.should == packet2.type
262
+ packet.payload.should == packet2.payload
263
+ packet.from.should == packet2.from
264
+ packet.token.should == packet2.token
265
+ packet.tries.should == packet2.tries
266
+ packet.expires_at.should == packet2.expires_at
267
+ packet.recv_version.should == packet2.recv_version
268
+ packet.send_version.should == packet2.send_version
269
+ end
270
+
271
+ it "should dump/load as JSON objects" do
272
+ packet = RightScale::Push.new('/some/foo', 'payload', :from => 'from', :token => '0xdeadbeef', :tries => ['try'])
273
+ packet2 = JSON.load(packet.to_json)
274
+ packet.type.should == packet2.type
275
+ packet.payload.should == packet2.payload
276
+ packet.from.should == packet2.from
277
+ packet.token.should == packet2.token
278
+ packet.tries.should == packet2.tries
279
+ packet.expires_at.should == packet2.expires_at
280
+ packet.recv_version.should == packet2.recv_version
281
+ packet.send_version.should == packet2.send_version
282
+ end
283
+
284
+ it "should default selector to :any" do
285
+ packet = RightScale::Push.new('/some/foo', 'payload')
286
+ packet.selector.should == :any
287
+ end
288
+
289
+ it "should convert selector from :least_loaded or :random to :any" do
290
+ packet = RightScale::Push.new('/some/foo', 'payload', :selector => :least_loaded)
291
+ packet.selector.should == :any
292
+ packet = RightScale::Push.new('/some/foo', 'payload', :selector => "least_loaded")
293
+ packet.selector.should == :any
294
+ packet = RightScale::Push.new('/some/foo', 'payload', :selector => :random)
295
+ packet.selector.should == :any
296
+ packet = RightScale::Push.new('/some/foo', 'payload', :selector => "random")
297
+ packet.selector.should == :any
298
+ packet = RightScale::Push.new('/some/foo', 'payload', :selector => :any)
299
+ packet.selector.should == :any
300
+ end
301
+
302
+ it "should distinguish fanout request" do
303
+ RightScale::Push.new('/some/foo', 'payload').fanout?.should be_false
304
+ RightScale::Push.new('/some/foo', 'payload', :selector => 'all').fanout?.should be_true
305
+ end
306
+
307
+ it "should not convert created_at to expires_at" do
308
+ packet = RightScale::Push.new('/some/foo', 'payload', :expires_at => 100000)
309
+ packet2 = JSON.parse(packet.to_json.sub("expires_at", "created_at"))
310
+ packet2.expires_at.should == 0
311
+ packet = RightScale::Push.new('/some/foo', 'payload', :expires_at => 0)
312
+ packet2 = JSON.parse(packet.to_json.sub("expires_at", "created_at"))
313
+ packet2.expires_at.should == 0
314
+ end
315
+
316
+ it "should be one-way" do
317
+ RightScale::Push.new('/some/foo', 'payload').one_way.should be_true
318
+ end
319
+
320
+ it "should use current version by default when constructing" do
321
+ packet = RightScale::Push.new('/some/foo', 'payload', :from => 'from', :token => '0xdeadbeef', :tries => ['try'])
322
+ packet.recv_version.should == RightScale::Packet::VERSION
323
+ packet.send_version.should == RightScale::Packet::VERSION
324
+ end
325
+
326
+ it "should use default version if none supplied when unmarshalling" do
327
+ packet = RightScale::Push.new('/some/foo', 'payload', :from => 'from', :token => '0xdeadbeef', :tries => ['try'])
328
+ packet.instance_variable_set(:@version, nil)
329
+ MessagePack.load(packet.to_msgpack).send_version.should == RightScale::Packet::DEFAULT_VERSION
330
+ JSON.load(packet.to_json).send_version.should == RightScale::Packet::DEFAULT_VERSION
331
+ end
332
+ end
333
+
334
+
335
+ describe "Packet: Result" do
336
+ it "should dump/load as MessagePack objects" do
337
+ packet = RightScale::Result.new('0xdeadbeef', 'to', 'results', 'from', 'request_from', ['try'], true)
338
+ packet2 = MessagePack.load(packet.to_msgpack)
339
+ packet.token.should == packet2.token
340
+ packet.to.should == packet2.to
341
+ packet.results.should == packet2.results
342
+ packet.from.should == packet2.from
343
+ packet.request_from.should == packet2.request_from
344
+ packet.tries.should == packet2.tries
345
+ packet.persistent.should == packet2.persistent
346
+ packet.recv_version.should == packet2.recv_version
347
+ packet.send_version.should == packet2.send_version
348
+ end
349
+
350
+ it "should dump/load as JSON objects" do
351
+ packet = RightScale::Result.new('0xdeadbeef', 'to', 'results', 'from', 'request_from', ['try'], true)
352
+ packet2 = JSON.load(packet.to_json)
353
+ packet.token.should == packet2.token
354
+ packet.to.should == packet2.to
355
+ packet.results.should == packet2.results
356
+ packet.from.should == packet2.from
357
+ packet.request_from.should == packet2.request_from
358
+ packet.tries.should == packet2.tries
359
+ packet.persistent.should == packet2.persistent
360
+ packet.recv_version.should == packet2.recv_version
361
+ packet.send_version.should == packet2.send_version
362
+ end
363
+
364
+ it "should use current version by default when constructing" do
365
+ packet = RightScale::Result.new('0xdeadbeef', 'to', 'results', 'from', 'request_from', ['try'], true)
366
+ packet.recv_version.should == RightScale::Packet::VERSION
367
+ packet.send_version.should == RightScale::Packet::VERSION
368
+ end
369
+
370
+ it "should use default version if none supplied when unmarshalling" do
371
+ packet = RightScale::Result.new('0xdeadbeef', 'to', 'results', 'from', 'request_from', ['try'], true)
372
+ packet.instance_variable_set(:@version, nil)
373
+ MessagePack.load(packet.to_msgpack).send_version.should == RightScale::Packet::DEFAULT_VERSION
374
+ JSON.load(packet.to_json).send_version.should == RightScale::Packet::DEFAULT_VERSION
375
+ end
376
+
377
+ it "should be one-way" do
378
+ RightScale::Result.new('0xdeadbeef', 'to', 'results', 'from').one_way.should be_true
379
+ end
380
+ end
381
+
382
+
383
+ describe "Packet: Stats" do
384
+ it "should dump/load as MessagePack objects" do
385
+ packet = RightScale::Stats.new(['data'], 'from')
386
+ packet2 = MessagePack.load(packet.to_msgpack)
387
+ packet.data.should == packet2.data
388
+ packet.from.should == packet2.from
389
+ packet.recv_version.should == packet2.recv_version
390
+ packet.send_version.should == packet2.send_version
391
+ end
392
+
393
+ it "should dump/load as JSON objects" do
394
+ packet = RightScale::Stats.new(['data'], 'from')
395
+ packet2 = JSON.load(packet.to_json)
396
+ packet.data.should == packet2.data
397
+ packet.from.should == packet2.from
398
+ packet.recv_version.should == packet2.recv_version
399
+ packet.send_version.should == packet2.send_version
400
+ end
401
+
402
+ it "should use current version by default when constructing" do
403
+ packet = RightScale::Stats.new(['data'], 'from')
404
+ packet.recv_version.should == RightScale::Packet::VERSION
405
+ packet.send_version.should == RightScale::Packet::VERSION
406
+ end
407
+
408
+ it "should use default version if none supplied when unmarshalling" do
409
+ packet = RightScale::Stats.new(['data'], 'from')
410
+ packet.instance_variable_set(:@version, nil)
411
+ MessagePack.load(packet.to_msgpack).send_version.should == RightScale::Packet::DEFAULT_VERSION
412
+ JSON.load(packet.to_json).send_version.should == RightScale::Packet::DEFAULT_VERSION
413
+ end
414
+
415
+ it "should be one-way" do
416
+ RightScale::Stats.new(['data'], 'from').one_way.should be_true
417
+ end
418
+ end