cuboid 0.0.0 → 0.0.1alpha

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 (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +0 -0
  3. data/Gemfile +20 -5
  4. data/LICENSE.md +22 -0
  5. data/README.md +158 -19
  6. data/Rakefile +56 -3
  7. data/config/paths.yml +15 -0
  8. data/cuboid.gemspec +61 -23
  9. data/lib/cuboid.rb +96 -4
  10. data/lib/cuboid/application.rb +326 -0
  11. data/lib/cuboid/application/parts/data.rb +18 -0
  12. data/lib/cuboid/application/parts/report.rb +29 -0
  13. data/lib/cuboid/application/parts/state.rb +274 -0
  14. data/lib/cuboid/application/runtime.rb +25 -0
  15. data/lib/cuboid/banner.rb +13 -0
  16. data/lib/cuboid/data.rb +86 -0
  17. data/lib/cuboid/data/application.rb +52 -0
  18. data/lib/cuboid/error.rb +9 -0
  19. data/lib/cuboid/option_group.rb +129 -0
  20. data/lib/cuboid/option_groups.rb +8 -0
  21. data/lib/cuboid/option_groups/datastore.rb +23 -0
  22. data/lib/cuboid/option_groups/dispatcher.rb +38 -0
  23. data/lib/cuboid/option_groups/output.rb +14 -0
  24. data/lib/cuboid/option_groups/paths.rb +184 -0
  25. data/lib/cuboid/option_groups/report.rb +39 -0
  26. data/lib/cuboid/option_groups/rpc.rb +105 -0
  27. data/lib/cuboid/option_groups/scheduler.rb +27 -0
  28. data/lib/cuboid/option_groups/snapshot.rb +13 -0
  29. data/lib/cuboid/option_groups/system.rb +10 -0
  30. data/lib/cuboid/options.rb +254 -0
  31. data/lib/cuboid/processes.rb +13 -0
  32. data/lib/cuboid/processes/dispatchers.rb +140 -0
  33. data/lib/cuboid/processes/executables/base.rb +54 -0
  34. data/lib/cuboid/processes/executables/dispatcher.rb +5 -0
  35. data/lib/cuboid/processes/executables/instance.rb +12 -0
  36. data/lib/cuboid/processes/executables/rest_service.rb +13 -0
  37. data/lib/cuboid/processes/executables/scheduler.rb +5 -0
  38. data/lib/cuboid/processes/helpers.rb +4 -0
  39. data/lib/cuboid/processes/helpers/dispatchers.rb +23 -0
  40. data/lib/cuboid/processes/helpers/instances.rb +39 -0
  41. data/lib/cuboid/processes/helpers/processes.rb +23 -0
  42. data/lib/cuboid/processes/helpers/schedulers.rb +23 -0
  43. data/lib/cuboid/processes/instances.rb +203 -0
  44. data/lib/cuboid/processes/manager.rb +262 -0
  45. data/lib/cuboid/processes/schedulers.rb +128 -0
  46. data/lib/cuboid/report.rb +220 -0
  47. data/lib/cuboid/rest/server.rb +165 -0
  48. data/lib/cuboid/rest/server/instance_helpers.rb +99 -0
  49. data/lib/cuboid/rest/server/routes/dispatcher.rb +41 -0
  50. data/lib/cuboid/rest/server/routes/grid.rb +41 -0
  51. data/lib/cuboid/rest/server/routes/instances.rb +131 -0
  52. data/lib/cuboid/rest/server/routes/scheduler.rb +140 -0
  53. data/lib/cuboid/rpc/client.rb +3 -0
  54. data/lib/cuboid/rpc/client/base.rb +58 -0
  55. data/lib/cuboid/rpc/client/dispatcher.rb +58 -0
  56. data/lib/cuboid/rpc/client/instance.rb +100 -0
  57. data/lib/cuboid/rpc/client/instance/service.rb +37 -0
  58. data/lib/cuboid/rpc/client/scheduler.rb +46 -0
  59. data/lib/cuboid/rpc/serializer.rb +92 -0
  60. data/lib/cuboid/rpc/server/active_options.rb +38 -0
  61. data/lib/cuboid/rpc/server/application_wrapper.rb +138 -0
  62. data/lib/cuboid/rpc/server/base.rb +63 -0
  63. data/lib/cuboid/rpc/server/dispatcher.rb +317 -0
  64. data/lib/cuboid/rpc/server/dispatcher/node.rb +247 -0
  65. data/lib/cuboid/rpc/server/dispatcher/service.rb +145 -0
  66. data/lib/cuboid/rpc/server/instance.rb +338 -0
  67. data/lib/cuboid/rpc/server/output.rb +92 -0
  68. data/lib/cuboid/rpc/server/scheduler.rb +482 -0
  69. data/lib/cuboid/ruby.rb +4 -0
  70. data/lib/cuboid/ruby/array.rb +17 -0
  71. data/lib/cuboid/ruby/hash.rb +41 -0
  72. data/lib/cuboid/ruby/object.rb +32 -0
  73. data/lib/cuboid/snapshot.rb +186 -0
  74. data/lib/cuboid/state.rb +94 -0
  75. data/lib/cuboid/state/application.rb +309 -0
  76. data/lib/cuboid/state/options.rb +27 -0
  77. data/lib/cuboid/support.rb +11 -0
  78. data/lib/cuboid/support/buffer.rb +3 -0
  79. data/lib/cuboid/support/buffer/autoflush.rb +61 -0
  80. data/lib/cuboid/support/buffer/base.rb +91 -0
  81. data/lib/cuboid/support/cache.rb +7 -0
  82. data/lib/cuboid/support/cache/base.rb +226 -0
  83. data/lib/cuboid/support/cache/least_cost_replacement.rb +77 -0
  84. data/lib/cuboid/support/cache/least_recently_pushed.rb +21 -0
  85. data/lib/cuboid/support/cache/least_recently_used.rb +31 -0
  86. data/lib/cuboid/support/cache/preference.rb +31 -0
  87. data/lib/cuboid/support/cache/random_replacement.rb +20 -0
  88. data/lib/cuboid/support/crypto.rb +2 -0
  89. data/lib/cuboid/support/crypto/rsa_aes_cbc.rb +86 -0
  90. data/lib/cuboid/support/database.rb +5 -0
  91. data/lib/cuboid/support/database/base.rb +177 -0
  92. data/lib/cuboid/support/database/categorized_queue.rb +195 -0
  93. data/lib/cuboid/support/database/hash.rb +300 -0
  94. data/lib/cuboid/support/database/queue.rb +149 -0
  95. data/lib/cuboid/support/filter.rb +3 -0
  96. data/lib/cuboid/support/filter/base.rb +110 -0
  97. data/lib/cuboid/support/filter/set.rb +29 -0
  98. data/lib/cuboid/support/glob.rb +27 -0
  99. data/lib/cuboid/support/mixins.rb +8 -0
  100. data/lib/cuboid/support/mixins/observable.rb +99 -0
  101. data/lib/cuboid/support/mixins/parts.rb +20 -0
  102. data/lib/cuboid/support/mixins/profiler.rb +93 -0
  103. data/lib/cuboid/support/mixins/spec_instances.rb +65 -0
  104. data/lib/cuboid/support/mixins/terminal.rb +57 -0
  105. data/lib/cuboid/system.rb +119 -0
  106. data/lib/cuboid/system/platforms.rb +84 -0
  107. data/lib/cuboid/system/platforms/linux.rb +26 -0
  108. data/lib/cuboid/system/platforms/mixins/unix.rb +46 -0
  109. data/lib/cuboid/system/platforms/osx.rb +25 -0
  110. data/lib/cuboid/system/platforms/windows.rb +81 -0
  111. data/lib/cuboid/system/slots.rb +143 -0
  112. data/lib/cuboid/ui/output.rb +52 -0
  113. data/lib/cuboid/ui/output_interface.rb +43 -0
  114. data/lib/cuboid/ui/output_interface/abstract.rb +68 -0
  115. data/lib/cuboid/ui/output_interface/controls.rb +84 -0
  116. data/lib/cuboid/ui/output_interface/error_logging.rb +119 -0
  117. data/lib/cuboid/ui/output_interface/implemented.rb +58 -0
  118. data/lib/cuboid/ui/output_interface/personalization.rb +62 -0
  119. data/lib/cuboid/utilities.rb +155 -0
  120. data/lib/cuboid/version.rb +4 -3
  121. data/lib/version +1 -0
  122. data/logs/placeholder +0 -0
  123. data/spec/cuboid/application/parts/data_spec.rb +12 -0
  124. data/spec/cuboid/application/parts/report_spec.rb +6 -0
  125. data/spec/cuboid/application/parts/state_spec.rb +192 -0
  126. data/spec/cuboid/application/runtime_spec.rb +21 -0
  127. data/spec/cuboid/application_spec.rb +37 -0
  128. data/spec/cuboid/data/application_spec.rb +22 -0
  129. data/spec/cuboid/data_spec.rb +47 -0
  130. data/spec/cuboid/error_spec.rb +23 -0
  131. data/spec/cuboid/option_groups/datastore_spec.rb +54 -0
  132. data/spec/cuboid/option_groups/dispatcher_spec.rb +12 -0
  133. data/spec/cuboid/option_groups/output_spec.rb +11 -0
  134. data/spec/cuboid/option_groups/paths_spec.rb +184 -0
  135. data/spec/cuboid/option_groups/report_spec.rb +26 -0
  136. data/spec/cuboid/option_groups/rpc_spec.rb +53 -0
  137. data/spec/cuboid/option_groups/snapshot_spec.rb +26 -0
  138. data/spec/cuboid/option_groups/system.rb +12 -0
  139. data/spec/cuboid/options_spec.rb +218 -0
  140. data/spec/cuboid/report_spec.rb +221 -0
  141. data/spec/cuboid/rest/server_spec.rb +1205 -0
  142. data/spec/cuboid/rpc/client/base_spec.rb +151 -0
  143. data/spec/cuboid/rpc/client/dispatcher_spec.rb +13 -0
  144. data/spec/cuboid/rpc/client/instance_spec.rb +38 -0
  145. data/spec/cuboid/rpc/server/active_options_spec.rb +21 -0
  146. data/spec/cuboid/rpc/server/base_spec.rb +60 -0
  147. data/spec/cuboid/rpc/server/dispatcher/node_spec.rb +222 -0
  148. data/spec/cuboid/rpc/server/dispatcher/service_spec.rb +112 -0
  149. data/spec/cuboid/rpc/server/dispatcher_spec.rb +317 -0
  150. data/spec/cuboid/rpc/server/instance_spec.rb +307 -0
  151. data/spec/cuboid/rpc/server/output_spec.rb +32 -0
  152. data/spec/cuboid/rpc/server/scheduler_spec.rb +400 -0
  153. data/spec/cuboid/ruby/array_spec.rb +77 -0
  154. data/spec/cuboid/ruby/hash_spec.rb +63 -0
  155. data/spec/cuboid/ruby/object_spec.rb +22 -0
  156. data/spec/cuboid/snapshot_spec.rb +123 -0
  157. data/spec/cuboid/state/application_spec.rb +538 -0
  158. data/spec/cuboid/state/options_spec.rb +37 -0
  159. data/spec/cuboid/state_spec.rb +53 -0
  160. data/spec/cuboid/support/buffer/autoflush_spec.rb +78 -0
  161. data/spec/cuboid/support/buffer/base_spec.rb +193 -0
  162. data/spec/cuboid/support/cache/least_cost_replacement_spec.rb +61 -0
  163. data/spec/cuboid/support/cache/least_recently_pushed_spec.rb +90 -0
  164. data/spec/cuboid/support/cache/least_recently_used_spec.rb +80 -0
  165. data/spec/cuboid/support/cache/preference_spec.rb +37 -0
  166. data/spec/cuboid/support/cache/random_replacement_spec.rb +42 -0
  167. data/spec/cuboid/support/crypto/rsa_aes_cbc_spec.rb +28 -0
  168. data/spec/cuboid/support/database/categorized_queue_spec.rb +327 -0
  169. data/spec/cuboid/support/database/hash_spec.rb +204 -0
  170. data/spec/cuboid/support/database/scheduler_spec.rb +325 -0
  171. data/spec/cuboid/support/filter/set_spec.rb +19 -0
  172. data/spec/cuboid/support/glob_spec.rb +75 -0
  173. data/spec/cuboid/support/mixins/observable_spec.rb +95 -0
  174. data/spec/cuboid/system/platforms/linux_spec.rb +31 -0
  175. data/spec/cuboid/system/platforms/osx_spec.rb +32 -0
  176. data/spec/cuboid/system/platforms/windows_spec.rb +41 -0
  177. data/spec/cuboid/system/slots_spec.rb +202 -0
  178. data/spec/cuboid/system_spec.rb +105 -0
  179. data/spec/cuboid/utilities_spec.rb +131 -0
  180. data/spec/spec_helper.rb +46 -0
  181. data/spec/support/factories/placeholder +0 -0
  182. data/spec/support/factories/scan_report.rb +18 -0
  183. data/spec/support/fixtures/empty/placeholder +0 -0
  184. data/spec/support/fixtures/executables/node.rb +50 -0
  185. data/spec/support/fixtures/mock_app.rb +61 -0
  186. data/spec/support/fixtures/mock_app/test_service.rb +64 -0
  187. data/spec/support/fixtures/services/echo.rb +64 -0
  188. data/spec/support/helpers/framework.rb +3 -0
  189. data/spec/support/helpers/matchers.rb +5 -0
  190. data/spec/support/helpers/misc.rb +3 -0
  191. data/spec/support/helpers/paths.rb +15 -0
  192. data/spec/support/helpers/request_helpers.rb +38 -0
  193. data/spec/support/helpers/requires.rb +8 -0
  194. data/spec/support/helpers/resets.rb +52 -0
  195. data/spec/support/helpers/web_server.rb +15 -0
  196. data/spec/support/lib/factory.rb +107 -0
  197. data/spec/support/lib/web_server_client.rb +41 -0
  198. data/spec/support/lib/web_server_dispatcher.rb +25 -0
  199. data/spec/support/lib/web_server_manager.rb +118 -0
  200. data/spec/support/logs/placeholder +0 -0
  201. data/spec/support/pems/cacert.pem +37 -0
  202. data/spec/support/pems/client/cert.pem +37 -0
  203. data/spec/support/pems/client/foo-cert.pem +39 -0
  204. data/spec/support/pems/client/foo-key.pem +51 -0
  205. data/spec/support/pems/client/key.pem +51 -0
  206. data/spec/support/pems/server/cert.pem +37 -0
  207. data/spec/support/pems/server/key.pem +51 -0
  208. data/spec/support/reports/placeholder +0 -0
  209. data/spec/support/shared/application.rb +10 -0
  210. data/spec/support/shared/component.rb +31 -0
  211. data/spec/support/shared/component/options/base.rb +187 -0
  212. data/spec/support/shared/option_group.rb +98 -0
  213. data/spec/support/shared/support/cache.rb +419 -0
  214. data/spec/support/shared/support/filter.rb +143 -0
  215. data/spec/support/shared/system/platforms/base.rb +25 -0
  216. data/spec/support/shared/system/platforms/mixins/unix.rb +37 -0
  217. data/spec/support/snapshots/placeholder +0 -0
  218. metadata +566 -21
  219. data/.gitignore +0 -8
  220. data/bin/console +0 -15
  221. data/bin/setup +0 -8
@@ -0,0 +1,151 @@
1
+ require 'spec_helper'
2
+ require "#{Cuboid::Options.paths.lib}/rpc/server/base"
3
+
4
+ class Server
5
+ def initialize( opts, token = nil, &block )
6
+ @server = Cuboid::RPC::Server::Base.new( opts, token )
7
+ @server.add_handler( "foo", self )
8
+
9
+ if block_given?
10
+ start
11
+ block.call self
12
+ process_kill_reactor
13
+ end
14
+ end
15
+
16
+ def url
17
+ @server.url
18
+ end
19
+
20
+ def start
21
+ Arachni::Reactor.global.run_in_thread if !Arachni::Reactor.global.running?
22
+ @server.start
23
+ sleep( 0.1 ) while !@server.ready?
24
+ end
25
+
26
+ def bar
27
+ true
28
+ end
29
+ end
30
+
31
+ describe Cuboid::RPC::Client::Base do
32
+ let(:empty_options) do
33
+ {}
34
+ end
35
+
36
+ let(:options) do
37
+ {
38
+ host: Cuboid::Options.rpc.server_address,
39
+ port: available_port
40
+ }
41
+ end
42
+
43
+ let(:server_ssl_options) do
44
+ options.merge(
45
+ ssl_ca: support_path + 'pems/cacert.pem',
46
+ ssl_pkey: support_path + 'pems/server/key.pem',
47
+ ssl_cert: support_path + 'pems/server/cert.pem'
48
+ )
49
+ end
50
+
51
+ let(:client_ssl_options) do
52
+ {
53
+ ssl_ca: support_path + 'pems/cacert.pem',
54
+ ssl_pkey: support_path + 'pems/client/key.pem',
55
+ ssl_cert: support_path + 'pems/client/cert.pem'
56
+ }
57
+ end
58
+
59
+ describe '.new' do
60
+ context 'without SSL options' do
61
+ it 'connects to a server' do
62
+ Server.new( options ) do |server|
63
+ client = described_class.new( server.url, nil, options )
64
+ expect(client.call( "foo.bar" )).to eq(true)
65
+ end
66
+ end
67
+ end
68
+
69
+ context 'when trying to connect to an SSL-enabled server' do
70
+ context 'with valid SSL options' do
71
+ it 'connects successfully' do
72
+ Server.new( server_ssl_options ) do |server|
73
+ client = described_class.new( server.url, nil, client_ssl_options )
74
+ expect(client.call( "foo.bar" )).to be_truthy
75
+ end
76
+ end
77
+ end
78
+
79
+ context 'with invalid SSL options' do
80
+ it 'throws an exception' do
81
+ client_ssl_options.delete :ssl_pkey
82
+ client_ssl_options.delete :ssl_cert
83
+
84
+ Server.new( server_ssl_options ) do |server|
85
+ raised = false
86
+ begin
87
+ client = described_class.new( server.url, nil, client_ssl_options )
88
+ client.call( "foo.bar" )
89
+ rescue Arachni::RPC::Exceptions::ConnectionError
90
+ raised = true
91
+ end
92
+
93
+ expect(raised).to be_truthy
94
+ end
95
+ end
96
+ end
97
+
98
+ context 'with no SSL options' do
99
+ it 'throws an exception' do
100
+ Server.new( server_ssl_options ) do |server|
101
+ raised = false
102
+ begin
103
+ client = described_class.new( server.url, nil, empty_options )
104
+ client.call( "foo.bar" )
105
+ rescue Arachni::RPC::Exceptions::ConnectionError
106
+ raised = true
107
+ end
108
+
109
+ expect(raised).to be_truthy
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ context 'when a server requires a token' do
116
+ context 'with a valid token' do
117
+ it 'connects successfully' do
118
+ opts = options.dup
119
+ opts[:port] = available_port
120
+ token = 'secret!'
121
+
122
+ Server.new( opts, token ) do |server|
123
+ client = described_class.new( server.url, token, opts )
124
+ expect(client.call( "foo.bar" )).to be_truthy
125
+ end
126
+ end
127
+ end
128
+
129
+ context 'with invalid token' do
130
+ it 'throws an exception' do
131
+ opts = options.dup
132
+ opts[:port] = available_port
133
+ token = 'secret!'
134
+
135
+ Server.new( opts, token ) do |server|
136
+ raised = false
137
+ begin
138
+ client = described_class.new( server.url, nil, empty_options )
139
+ client.call( "foo.bar" )
140
+ rescue Arachni::RPC::Exceptions::InvalidToken
141
+ raised = true
142
+ end
143
+
144
+ expect(raised).to be_truthy
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ require 'fileutils'
3
+
4
+ describe Cuboid::RPC::Client::Dispatcher do
5
+ subject { dispatcher_spawn application: "#{fixtures_path}/mock_app.rb" }
6
+
7
+ describe '#node' do
8
+ it 'provides access to the node data' do
9
+ expect(subject.node.info.is_a?( Hash )).to be_truthy
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cuboid::RPC::Client::Instance do
4
+
5
+ let(:subject) { instance_spawn application: "#{fixtures_path}/mock_app.rb" }
6
+
7
+ context 'when connecting to an instance' do
8
+ context 'which requires a token' do
9
+ context 'with a valid token' do
10
+ it 'connects successfully' do
11
+ expect(subject.alive?).to be_truthy
12
+ end
13
+ end
14
+
15
+ context 'with an invalid token' do
16
+ it 'should fail to connect' do
17
+ expect do
18
+ described_class.new( subject.url, 'blah' ).alive?
19
+ end.to raise_error Arachni::RPC::Exceptions::InvalidToken
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ describe '#options' do
26
+ let(:options) { subject.options }
27
+
28
+ describe '#set' do
29
+ let(:authorized_by) { 'tasos.laskos@gmail.com' }
30
+
31
+ it 'allows batch assigning using a hash' do
32
+ expect(options.set( authorized_by: authorized_by )).to be_truthy
33
+ expect(options.authorized_by).to eq(authorized_by)
34
+ end
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ require Cuboid::Options.paths.lib + 'rpc/client/instance'
4
+ require Cuboid::Options.paths.lib + 'rpc/server/instance'
5
+
6
+ describe Cuboid::RPC::Server::ActiveOptions do
7
+ let(:instance) { instance_spawn application: "#{fixtures_path}/mock_app.rb" }
8
+
9
+ describe '#set' do
10
+ it 'sets options by hash' do
11
+ opts = {
12
+ 'datastore' => { 'key' => 'val' },
13
+ }
14
+
15
+ instance.options.set( opts )
16
+ h = instance.options.to_h
17
+
18
+ expect(h['datastore']['key']).to eq(opts['datastore']['key'])
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+ require "#{Cuboid::Options.paths.lib}/rpc/server/base"
3
+
4
+ describe Cuboid::RPC::Server::Base do
5
+ before( :each ) do
6
+ Arachni::Reactor.global.run_in_thread
7
+ end
8
+
9
+ let(:subject) { Cuboid::RPC::Server::Base.new(
10
+ host: 'localhost', port: port
11
+ ) }
12
+ let(:port) { available_port }
13
+
14
+ it 'supports UNIX sockets', if: Arachni::Reactor.supports_unix_sockets? do
15
+ server = Cuboid::RPC::Server::Base.new(
16
+ socket: "#{Dir.tmpdir}/cuboid-base-#{Cuboid::Utilities.generate_token}"
17
+ )
18
+
19
+ server.start
20
+
21
+ raised = false
22
+ begin
23
+ Timeout.timeout( 20 ){
24
+ sleep 0.1 while !server.ready?
25
+ }
26
+ rescue Exception => e
27
+ raised = true
28
+ end
29
+
30
+ expect(server.ready?).to be_truthy
31
+ expect(raised).to be_falsey
32
+ end
33
+
34
+ describe '#ready?' do
35
+ context 'when the server is not ready' do
36
+ it 'returns false' do
37
+ expect(subject.ready?).to be_falsey
38
+ end
39
+ end
40
+
41
+ context 'when the server is ready' do
42
+ it 'returns true' do
43
+ subject.start
44
+
45
+ raised = false
46
+ begin
47
+ Timeout.timeout( 20 ){
48
+ sleep 0.1 while !subject.ready?
49
+ }
50
+ rescue Exception => e
51
+ raised = true
52
+ end
53
+
54
+ expect(subject.ready?).to be_truthy
55
+ expect(raised).to be_falsey
56
+ end
57
+ end
58
+ end
59
+
60
+ end
@@ -0,0 +1,222 @@
1
+ require 'spec_helper'
2
+ require "#{Cuboid::Options.paths.lib}/rpc/server/dispatcher"
3
+
4
+ describe Cuboid::RPC::Server::Dispatcher::Node do
5
+
6
+ def get_node( port = available_port )
7
+ Cuboid::Options.rpc.server_port = port
8
+
9
+ Cuboid::Processes::Manager.spawn( :node )
10
+
11
+ c = Cuboid::RPC::Client::Base.new(
12
+ "#{Cuboid::Options.rpc.server_address}:#{port}"
13
+ )
14
+ c = Arachni::RPC::Proxy.new( c, 'node' )
15
+
16
+ begin
17
+ c.alive?
18
+ rescue Arachni::RPC::Exceptions::ConnectionError
19
+ sleep 0.1
20
+ retry
21
+ end
22
+
23
+ c
24
+ end
25
+
26
+ before( :each ) do
27
+ options.paths.executables = "#{fixtures_path}executables/"
28
+ options.dispatcher.ping_interval = 0.5
29
+ end
30
+ after( :each ) do
31
+ Cuboid::Processes::Manager.killall
32
+ end
33
+
34
+ let(:subject) { get_node }
35
+ let(:options) { Cuboid::Options }
36
+
37
+ describe '#grid_member?' do
38
+ context 'when the dispatcher is a grid member' do
39
+ it 'should return true' do
40
+ options.dispatcher.neighbour = subject.url
41
+
42
+ c = get_node
43
+ sleep 0.5
44
+
45
+ expect(c.grid_member?).to be_truthy
46
+ end
47
+ end
48
+
49
+ context 'when the dispatcher is not a grid member' do
50
+ it 'should return false' do
51
+ expect(subject.grid_member?).to be_falsey
52
+ end
53
+ end
54
+ end
55
+
56
+ context 'when a previously unreachable neighbour comes back to life' do
57
+ it 'gets re-added to the neighbours list' do
58
+ port = available_port
59
+ subject.add_neighbour( '127.0.0.1:' + port.to_s )
60
+
61
+ sleep 3
62
+ expect(subject.neighbours).to be_empty
63
+
64
+ c = get_node( port )
65
+
66
+ sleep 0.5
67
+ expect(subject.neighbours).to eq([c.url])
68
+ expect(c.neighbours).to eq([subject.url])
69
+ end
70
+ end
71
+
72
+ context 'when a neighbour becomes unreachable' do
73
+ it 'is removed' do
74
+ c = get_node
75
+
76
+ subject.add_neighbour( c.url )
77
+ sleep 0.5
78
+
79
+ expect(c.neighbours).to eq([subject.url])
80
+ expect(subject.neighbours).to eq([c.url])
81
+
82
+ subject.shutdown rescue break while sleep 0.1
83
+ sleep 0.5
84
+
85
+ expect(c.neighbours).to be_empty
86
+ end
87
+ end
88
+
89
+ context 'when initialised with a neighbour' do
90
+ it 'adds that neighbour and reach convergence' do
91
+ options.dispatcher.neighbour = subject.url
92
+
93
+ c = get_node
94
+ sleep 0.5
95
+ expect(c.neighbours).to eq([subject.url])
96
+ expect(subject.neighbours).to eq([c.url])
97
+
98
+ d = get_node
99
+ sleep 0.5
100
+ expect(d.neighbours.sort).to eq([subject.url, c.url].sort)
101
+ expect(c.neighbours.sort).to eq([subject.url, d.url].sort)
102
+ expect(subject.neighbours.sort).to eq([c.url, d.url].sort)
103
+
104
+ options.dispatcher.neighbour = d.url
105
+ e = get_node
106
+ sleep 0.5
107
+ expect(e.neighbours.sort).to eq([subject.url, c.url, d.url].sort)
108
+ expect(d.neighbours.sort).to eq([subject.url, c.url, e.url].sort)
109
+ expect(c.neighbours.sort).to eq([subject.url, d.url, e.url].sort)
110
+ expect(subject.neighbours.sort).to eq([c.url, d.url, e.url].sort)
111
+ end
112
+ end
113
+
114
+ describe '#unplug' do
115
+ it 'removes itself from the Grid' do
116
+ c = get_node
117
+
118
+ subject.add_neighbour( c.url )
119
+ sleep 0.5
120
+ expect(c.neighbours).to eq([subject.url])
121
+
122
+ c.unplug
123
+
124
+ expect(c.neighbours).to be_empty
125
+ expect(c.grid_member?).to be_falsey
126
+ end
127
+ end
128
+
129
+ describe '#add_neighbour' do
130
+ before(:each) do
131
+ subject.add_neighbour( other.url )
132
+ sleep 0.5
133
+ end
134
+
135
+ let( :other ) { get_node }
136
+
137
+ it 'adds a neighbour' do
138
+ expect(subject.neighbours).to eq([other.url])
139
+ expect(other.neighbours).to eq([subject.url])
140
+ end
141
+
142
+ context 'when propagate is set to true' do
143
+ it 'announces the new neighbour to the existing neighbours' do
144
+ n = get_node
145
+ subject.add_neighbour( n.url, true )
146
+ sleep 0.5
147
+
148
+ expect(subject.neighbours.sort).to eq([other.url, n.url].sort)
149
+ expect(other.neighbours.sort).to eq([subject.url, n.url].sort)
150
+
151
+ c = get_node
152
+ n.add_neighbour( c.url, true )
153
+ sleep 0.5
154
+
155
+ expect(subject.neighbours.sort).to eq([other.url, n.url, c.url].sort)
156
+ expect(other.neighbours.sort).to eq([subject.url, n.url, c.url].sort)
157
+ expect(c.neighbours.sort).to eq([subject.url, n.url, other.url].sort)
158
+
159
+ d = get_node
160
+ d.add_neighbour( c.url, true )
161
+ sleep 0.5
162
+
163
+ expect(subject.neighbours.sort).to eq([d.url, other.url, n.url, c.url].sort)
164
+ expect(other.neighbours.sort).to eq([d.url, subject.url, n.url, c.url].sort)
165
+ expect(c.neighbours.sort).to eq([d.url, subject.url, n.url, other.url].sort)
166
+ expect(d.neighbours.sort).to eq([c.url, subject.url, n.url, other.url].sort)
167
+ end
168
+ end
169
+ end
170
+
171
+ describe '#neighbours' do
172
+ it 'returns an array of neighbours' do
173
+ expect(subject.neighbours.is_a?( Array )).to be_truthy
174
+ end
175
+ end
176
+
177
+ describe '#neighbours_with_info' do
178
+ it 'returns all neighbours accompanied by their node info' do
179
+ subject.add_neighbour( get_node.url )
180
+ sleep 0.5
181
+
182
+ expect(subject.neighbours).to be_any
183
+ expect(subject.neighbours_with_info.size).to eq (subject.neighbours.size)
184
+
185
+ keys = subject.info.keys.sort
186
+ subject.neighbours_with_info.each do |i|
187
+ expect(i.keys.sort).to eq(keys)
188
+ end
189
+ end
190
+ end
191
+
192
+ describe '#info' do
193
+ it 'returns node info' do
194
+ options.dispatcher.name = 'blah'
195
+
196
+ c = get_node
197
+ subject.add_neighbour( c.url )
198
+ sleep 0.5
199
+
200
+ info = subject.info
201
+
202
+ expect(info['url']).to eq(subject.url)
203
+ expect(info['neighbours']).to eq(subject.neighbours)
204
+ expect(info['unreachable_neighbours']).to be_empty
205
+ expect(info['name']).to eq(options.dispatcher.name)
206
+ end
207
+
208
+ context 'when OptionGroups::RPC#server_external_address has been set' do
209
+ it 'advertises that address' do
210
+ options.rpc.server_external_address = '9.9.9.9'
211
+
212
+ expect(subject.info['url']).to start_with options.rpc.server_external_address
213
+ end
214
+ end
215
+ end
216
+
217
+ describe '#alive?' do
218
+ it 'returns true' do
219
+ expect(subject.alive?).to be_truthy
220
+ end
221
+ end
222
+ end