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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +0 -0
- data/Gemfile +20 -5
- data/LICENSE.md +22 -0
- data/README.md +158 -19
- data/Rakefile +56 -3
- data/config/paths.yml +15 -0
- data/cuboid.gemspec +61 -23
- data/lib/cuboid.rb +96 -4
- data/lib/cuboid/application.rb +326 -0
- data/lib/cuboid/application/parts/data.rb +18 -0
- data/lib/cuboid/application/parts/report.rb +29 -0
- data/lib/cuboid/application/parts/state.rb +274 -0
- data/lib/cuboid/application/runtime.rb +25 -0
- data/lib/cuboid/banner.rb +13 -0
- data/lib/cuboid/data.rb +86 -0
- data/lib/cuboid/data/application.rb +52 -0
- data/lib/cuboid/error.rb +9 -0
- data/lib/cuboid/option_group.rb +129 -0
- data/lib/cuboid/option_groups.rb +8 -0
- data/lib/cuboid/option_groups/datastore.rb +23 -0
- data/lib/cuboid/option_groups/dispatcher.rb +38 -0
- data/lib/cuboid/option_groups/output.rb +14 -0
- data/lib/cuboid/option_groups/paths.rb +184 -0
- data/lib/cuboid/option_groups/report.rb +39 -0
- data/lib/cuboid/option_groups/rpc.rb +105 -0
- data/lib/cuboid/option_groups/scheduler.rb +27 -0
- data/lib/cuboid/option_groups/snapshot.rb +13 -0
- data/lib/cuboid/option_groups/system.rb +10 -0
- data/lib/cuboid/options.rb +254 -0
- data/lib/cuboid/processes.rb +13 -0
- data/lib/cuboid/processes/dispatchers.rb +140 -0
- data/lib/cuboid/processes/executables/base.rb +54 -0
- data/lib/cuboid/processes/executables/dispatcher.rb +5 -0
- data/lib/cuboid/processes/executables/instance.rb +12 -0
- data/lib/cuboid/processes/executables/rest_service.rb +13 -0
- data/lib/cuboid/processes/executables/scheduler.rb +5 -0
- data/lib/cuboid/processes/helpers.rb +4 -0
- data/lib/cuboid/processes/helpers/dispatchers.rb +23 -0
- data/lib/cuboid/processes/helpers/instances.rb +39 -0
- data/lib/cuboid/processes/helpers/processes.rb +23 -0
- data/lib/cuboid/processes/helpers/schedulers.rb +23 -0
- data/lib/cuboid/processes/instances.rb +203 -0
- data/lib/cuboid/processes/manager.rb +262 -0
- data/lib/cuboid/processes/schedulers.rb +128 -0
- data/lib/cuboid/report.rb +220 -0
- data/lib/cuboid/rest/server.rb +165 -0
- data/lib/cuboid/rest/server/instance_helpers.rb +99 -0
- data/lib/cuboid/rest/server/routes/dispatcher.rb +41 -0
- data/lib/cuboid/rest/server/routes/grid.rb +41 -0
- data/lib/cuboid/rest/server/routes/instances.rb +131 -0
- data/lib/cuboid/rest/server/routes/scheduler.rb +140 -0
- data/lib/cuboid/rpc/client.rb +3 -0
- data/lib/cuboid/rpc/client/base.rb +58 -0
- data/lib/cuboid/rpc/client/dispatcher.rb +58 -0
- data/lib/cuboid/rpc/client/instance.rb +100 -0
- data/lib/cuboid/rpc/client/instance/service.rb +37 -0
- data/lib/cuboid/rpc/client/scheduler.rb +46 -0
- data/lib/cuboid/rpc/serializer.rb +92 -0
- data/lib/cuboid/rpc/server/active_options.rb +38 -0
- data/lib/cuboid/rpc/server/application_wrapper.rb +138 -0
- data/lib/cuboid/rpc/server/base.rb +63 -0
- data/lib/cuboid/rpc/server/dispatcher.rb +317 -0
- data/lib/cuboid/rpc/server/dispatcher/node.rb +247 -0
- data/lib/cuboid/rpc/server/dispatcher/service.rb +145 -0
- data/lib/cuboid/rpc/server/instance.rb +338 -0
- data/lib/cuboid/rpc/server/output.rb +92 -0
- data/lib/cuboid/rpc/server/scheduler.rb +482 -0
- data/lib/cuboid/ruby.rb +4 -0
- data/lib/cuboid/ruby/array.rb +17 -0
- data/lib/cuboid/ruby/hash.rb +41 -0
- data/lib/cuboid/ruby/object.rb +32 -0
- data/lib/cuboid/snapshot.rb +186 -0
- data/lib/cuboid/state.rb +94 -0
- data/lib/cuboid/state/application.rb +309 -0
- data/lib/cuboid/state/options.rb +27 -0
- data/lib/cuboid/support.rb +11 -0
- data/lib/cuboid/support/buffer.rb +3 -0
- data/lib/cuboid/support/buffer/autoflush.rb +61 -0
- data/lib/cuboid/support/buffer/base.rb +91 -0
- data/lib/cuboid/support/cache.rb +7 -0
- data/lib/cuboid/support/cache/base.rb +226 -0
- data/lib/cuboid/support/cache/least_cost_replacement.rb +77 -0
- data/lib/cuboid/support/cache/least_recently_pushed.rb +21 -0
- data/lib/cuboid/support/cache/least_recently_used.rb +31 -0
- data/lib/cuboid/support/cache/preference.rb +31 -0
- data/lib/cuboid/support/cache/random_replacement.rb +20 -0
- data/lib/cuboid/support/crypto.rb +2 -0
- data/lib/cuboid/support/crypto/rsa_aes_cbc.rb +86 -0
- data/lib/cuboid/support/database.rb +5 -0
- data/lib/cuboid/support/database/base.rb +177 -0
- data/lib/cuboid/support/database/categorized_queue.rb +195 -0
- data/lib/cuboid/support/database/hash.rb +300 -0
- data/lib/cuboid/support/database/queue.rb +149 -0
- data/lib/cuboid/support/filter.rb +3 -0
- data/lib/cuboid/support/filter/base.rb +110 -0
- data/lib/cuboid/support/filter/set.rb +29 -0
- data/lib/cuboid/support/glob.rb +27 -0
- data/lib/cuboid/support/mixins.rb +8 -0
- data/lib/cuboid/support/mixins/observable.rb +99 -0
- data/lib/cuboid/support/mixins/parts.rb +20 -0
- data/lib/cuboid/support/mixins/profiler.rb +93 -0
- data/lib/cuboid/support/mixins/spec_instances.rb +65 -0
- data/lib/cuboid/support/mixins/terminal.rb +57 -0
- data/lib/cuboid/system.rb +119 -0
- data/lib/cuboid/system/platforms.rb +84 -0
- data/lib/cuboid/system/platforms/linux.rb +26 -0
- data/lib/cuboid/system/platforms/mixins/unix.rb +46 -0
- data/lib/cuboid/system/platforms/osx.rb +25 -0
- data/lib/cuboid/system/platforms/windows.rb +81 -0
- data/lib/cuboid/system/slots.rb +143 -0
- data/lib/cuboid/ui/output.rb +52 -0
- data/lib/cuboid/ui/output_interface.rb +43 -0
- data/lib/cuboid/ui/output_interface/abstract.rb +68 -0
- data/lib/cuboid/ui/output_interface/controls.rb +84 -0
- data/lib/cuboid/ui/output_interface/error_logging.rb +119 -0
- data/lib/cuboid/ui/output_interface/implemented.rb +58 -0
- data/lib/cuboid/ui/output_interface/personalization.rb +62 -0
- data/lib/cuboid/utilities.rb +155 -0
- data/lib/cuboid/version.rb +4 -3
- data/lib/version +1 -0
- data/logs/placeholder +0 -0
- data/spec/cuboid/application/parts/data_spec.rb +12 -0
- data/spec/cuboid/application/parts/report_spec.rb +6 -0
- data/spec/cuboid/application/parts/state_spec.rb +192 -0
- data/spec/cuboid/application/runtime_spec.rb +21 -0
- data/spec/cuboid/application_spec.rb +37 -0
- data/spec/cuboid/data/application_spec.rb +22 -0
- data/spec/cuboid/data_spec.rb +47 -0
- data/spec/cuboid/error_spec.rb +23 -0
- data/spec/cuboid/option_groups/datastore_spec.rb +54 -0
- data/spec/cuboid/option_groups/dispatcher_spec.rb +12 -0
- data/spec/cuboid/option_groups/output_spec.rb +11 -0
- data/spec/cuboid/option_groups/paths_spec.rb +184 -0
- data/spec/cuboid/option_groups/report_spec.rb +26 -0
- data/spec/cuboid/option_groups/rpc_spec.rb +53 -0
- data/spec/cuboid/option_groups/snapshot_spec.rb +26 -0
- data/spec/cuboid/option_groups/system.rb +12 -0
- data/spec/cuboid/options_spec.rb +218 -0
- data/spec/cuboid/report_spec.rb +221 -0
- data/spec/cuboid/rest/server_spec.rb +1205 -0
- data/spec/cuboid/rpc/client/base_spec.rb +151 -0
- data/spec/cuboid/rpc/client/dispatcher_spec.rb +13 -0
- data/spec/cuboid/rpc/client/instance_spec.rb +38 -0
- data/spec/cuboid/rpc/server/active_options_spec.rb +21 -0
- data/spec/cuboid/rpc/server/base_spec.rb +60 -0
- data/spec/cuboid/rpc/server/dispatcher/node_spec.rb +222 -0
- data/spec/cuboid/rpc/server/dispatcher/service_spec.rb +112 -0
- data/spec/cuboid/rpc/server/dispatcher_spec.rb +317 -0
- data/spec/cuboid/rpc/server/instance_spec.rb +307 -0
- data/spec/cuboid/rpc/server/output_spec.rb +32 -0
- data/spec/cuboid/rpc/server/scheduler_spec.rb +400 -0
- data/spec/cuboid/ruby/array_spec.rb +77 -0
- data/spec/cuboid/ruby/hash_spec.rb +63 -0
- data/spec/cuboid/ruby/object_spec.rb +22 -0
- data/spec/cuboid/snapshot_spec.rb +123 -0
- data/spec/cuboid/state/application_spec.rb +538 -0
- data/spec/cuboid/state/options_spec.rb +37 -0
- data/spec/cuboid/state_spec.rb +53 -0
- data/spec/cuboid/support/buffer/autoflush_spec.rb +78 -0
- data/spec/cuboid/support/buffer/base_spec.rb +193 -0
- data/spec/cuboid/support/cache/least_cost_replacement_spec.rb +61 -0
- data/spec/cuboid/support/cache/least_recently_pushed_spec.rb +90 -0
- data/spec/cuboid/support/cache/least_recently_used_spec.rb +80 -0
- data/spec/cuboid/support/cache/preference_spec.rb +37 -0
- data/spec/cuboid/support/cache/random_replacement_spec.rb +42 -0
- data/spec/cuboid/support/crypto/rsa_aes_cbc_spec.rb +28 -0
- data/spec/cuboid/support/database/categorized_queue_spec.rb +327 -0
- data/spec/cuboid/support/database/hash_spec.rb +204 -0
- data/spec/cuboid/support/database/scheduler_spec.rb +325 -0
- data/spec/cuboid/support/filter/set_spec.rb +19 -0
- data/spec/cuboid/support/glob_spec.rb +75 -0
- data/spec/cuboid/support/mixins/observable_spec.rb +95 -0
- data/spec/cuboid/system/platforms/linux_spec.rb +31 -0
- data/spec/cuboid/system/platforms/osx_spec.rb +32 -0
- data/spec/cuboid/system/platforms/windows_spec.rb +41 -0
- data/spec/cuboid/system/slots_spec.rb +202 -0
- data/spec/cuboid/system_spec.rb +105 -0
- data/spec/cuboid/utilities_spec.rb +131 -0
- data/spec/spec_helper.rb +46 -0
- data/spec/support/factories/placeholder +0 -0
- data/spec/support/factories/scan_report.rb +18 -0
- data/spec/support/fixtures/empty/placeholder +0 -0
- data/spec/support/fixtures/executables/node.rb +50 -0
- data/spec/support/fixtures/mock_app.rb +61 -0
- data/spec/support/fixtures/mock_app/test_service.rb +64 -0
- data/spec/support/fixtures/services/echo.rb +64 -0
- data/spec/support/helpers/framework.rb +3 -0
- data/spec/support/helpers/matchers.rb +5 -0
- data/spec/support/helpers/misc.rb +3 -0
- data/spec/support/helpers/paths.rb +15 -0
- data/spec/support/helpers/request_helpers.rb +38 -0
- data/spec/support/helpers/requires.rb +8 -0
- data/spec/support/helpers/resets.rb +52 -0
- data/spec/support/helpers/web_server.rb +15 -0
- data/spec/support/lib/factory.rb +107 -0
- data/spec/support/lib/web_server_client.rb +41 -0
- data/spec/support/lib/web_server_dispatcher.rb +25 -0
- data/spec/support/lib/web_server_manager.rb +118 -0
- data/spec/support/logs/placeholder +0 -0
- data/spec/support/pems/cacert.pem +37 -0
- data/spec/support/pems/client/cert.pem +37 -0
- data/spec/support/pems/client/foo-cert.pem +39 -0
- data/spec/support/pems/client/foo-key.pem +51 -0
- data/spec/support/pems/client/key.pem +51 -0
- data/spec/support/pems/server/cert.pem +37 -0
- data/spec/support/pems/server/key.pem +51 -0
- data/spec/support/reports/placeholder +0 -0
- data/spec/support/shared/application.rb +10 -0
- data/spec/support/shared/component.rb +31 -0
- data/spec/support/shared/component/options/base.rb +187 -0
- data/spec/support/shared/option_group.rb +98 -0
- data/spec/support/shared/support/cache.rb +419 -0
- data/spec/support/shared/support/filter.rb +143 -0
- data/spec/support/shared/system/platforms/base.rb +25 -0
- data/spec/support/shared/system/platforms/mixins/unix.rb +37 -0
- data/spec/support/snapshots/placeholder +0 -0
- metadata +566 -21
- data/.gitignore +0 -8
- data/bin/console +0 -15
- data/bin/setup +0 -8
@@ -0,0 +1,1205 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require "#{Cuboid::Options.paths.lib}/rest/server"
|
3
|
+
|
4
|
+
describe Cuboid::Rest::Server do
|
5
|
+
include RequestHelpers
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
app.reset
|
9
|
+
Cuboid::Options.system.max_slots = 10
|
10
|
+
Cuboid::Options.paths.application = "#{fixtures_path}/mock_app.rb"
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:options) {{}}
|
14
|
+
let(:url) { tpl_url % id }
|
15
|
+
let(:id) { @id }
|
16
|
+
let(:non_existent_id) { 'stuff' }
|
17
|
+
|
18
|
+
let(:dispatcher) { Cuboid::Processes::Dispatchers.spawn }
|
19
|
+
let(:scheduler) { Cuboid::Processes::Schedulers.spawn }
|
20
|
+
|
21
|
+
def create_instance
|
22
|
+
post '/instances', options
|
23
|
+
response_data['id']
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'supports compressing as' do
|
27
|
+
['gzip'].each do |compression_method|
|
28
|
+
|
29
|
+
it compression_method do
|
30
|
+
get '/', {}, { 'HTTP_ACCEPT_ENCODING' => compression_method }
|
31
|
+
expect( response.headers['Content-Encoding'] ).to eq compression_method.split( ',' ).first
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when the client does not support compression' do
|
38
|
+
it 'does not compress the response' do
|
39
|
+
get '/'
|
40
|
+
expect(response.headers['Content-Encoding']).to be_nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when authentication' do
|
45
|
+
let(:username) { nil }
|
46
|
+
let(:password) { nil }
|
47
|
+
let(:userpwd) { "#{username}:#{password}" }
|
48
|
+
let(:url) { "http://localhost:#{Cuboid::Options.rpc.server_port}/instances" }
|
49
|
+
|
50
|
+
before do
|
51
|
+
Cuboid::Options.datastore['username'] = username
|
52
|
+
Cuboid::Options.datastore['password'] = password
|
53
|
+
|
54
|
+
Cuboid::Options.rpc.server_port = Cuboid::Utilities.available_port
|
55
|
+
Cuboid::Processes::Manager.spawn( :rest_service )
|
56
|
+
|
57
|
+
sleep 0.1 while Typhoeus.get( url ).code == 0
|
58
|
+
end
|
59
|
+
|
60
|
+
after do
|
61
|
+
Cuboid::Processes::Manager.killall
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'username' do
|
65
|
+
let(:username) { 'username' }
|
66
|
+
|
67
|
+
context 'is configured' do
|
68
|
+
it 'requires authentication' do
|
69
|
+
expect(Typhoeus.get( url ).code).to eq 401
|
70
|
+
expect(Typhoeus.get( url, userpwd: userpwd ).code).to eq 200
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'password' do
|
76
|
+
let(:password) { 'password' }
|
77
|
+
|
78
|
+
context 'is configured' do
|
79
|
+
it 'requires authentication' do
|
80
|
+
expect(Typhoeus.get( url ).code).to eq 401
|
81
|
+
expect(Typhoeus.get( url, userpwd: userpwd ).code).to eq 200
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'SSL options', if: !Cuboid.windows? do
|
88
|
+
let(:ssl_key) { nil }
|
89
|
+
let(:ssl_cert) { nil }
|
90
|
+
let(:ssl_ca) { nil }
|
91
|
+
let(:url) { "http://localhost:#{Cuboid::Options.rpc.server_port}/instances" }
|
92
|
+
let(:https_url) { "https://localhost:#{Cuboid::Options.rpc.server_port}/instances" }
|
93
|
+
|
94
|
+
before do
|
95
|
+
Cuboid::Options.rpc.ssl_ca = ssl_ca
|
96
|
+
Cuboid::Options.rpc.server_ssl_private_key = ssl_key
|
97
|
+
Cuboid::Options.rpc.server_ssl_certificate = ssl_cert
|
98
|
+
|
99
|
+
Cuboid::Options.rpc.server_port = Cuboid::Utilities.available_port
|
100
|
+
Cuboid::Processes::Manager.spawn( :rest_service )
|
101
|
+
|
102
|
+
sleep 0.1 while Typhoeus.get( url ).return_code == :couldnt_connect
|
103
|
+
end
|
104
|
+
|
105
|
+
after do
|
106
|
+
Cuboid::Processes::Manager.killall
|
107
|
+
end
|
108
|
+
|
109
|
+
describe 'when key and certificate is given' do
|
110
|
+
let(:ssl_key) { "#{support_path}/pems/server/key.pem" }
|
111
|
+
let(:ssl_cert) { "#{support_path}/pems/server/cert.pem" }
|
112
|
+
|
113
|
+
describe 'when no CA is given' do
|
114
|
+
it 'disables peer verification' do
|
115
|
+
expect(Typhoeus.get( https_url, ssl_verifypeer: false ).code).to eq 200
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe 'a CA is given' do
|
120
|
+
let(:ssl_ca) { "#{support_path}/pems/cacert.pem" }
|
121
|
+
|
122
|
+
it 'enables peer verification' do
|
123
|
+
expect(Typhoeus.get( https_url, ssl_verifypeer: false ).code).to eq 0
|
124
|
+
|
125
|
+
expect(Typhoeus.get(
|
126
|
+
https_url,
|
127
|
+
ssl_verifypeer: true,
|
128
|
+
sslcert: "#{support_path}/pems/client/cert.pem",
|
129
|
+
sslkey: "#{support_path}/pems/client/key.pem",
|
130
|
+
cainfo: ssl_ca
|
131
|
+
).code).to eq 200
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe 'when only key is given' do
|
137
|
+
let(:ssl_key) { "#{support_path}/pems/server/key.pem" }
|
138
|
+
|
139
|
+
it 'does not enable SSL' do
|
140
|
+
expect(Typhoeus.get( url ).code).to eq 200
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe 'when only cert is given' do
|
145
|
+
let(:ssl_cert) { "#{support_path}/pems/server/cert.pem" }
|
146
|
+
|
147
|
+
it 'does not enable SSL' do
|
148
|
+
expect(Typhoeus.get( url ).code).to eq 200
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe 'GET /instances' do
|
154
|
+
let(:tpl_url) { '/instances' }
|
155
|
+
|
156
|
+
it 'lists ids for all instances' do
|
157
|
+
ids = []
|
158
|
+
2.times do
|
159
|
+
ids << create_instance
|
160
|
+
end
|
161
|
+
|
162
|
+
get url
|
163
|
+
|
164
|
+
ids.each do |id|
|
165
|
+
expect(response_data[id]).to eq({})
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context 'when there is a Scheduler' do
|
170
|
+
before do
|
171
|
+
put '/scheduler/url', scheduler.url
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'includes its running instances' do
|
175
|
+
id = scheduler.push( options )
|
176
|
+
sleep 0.1 while scheduler.running.empty?
|
177
|
+
|
178
|
+
get url
|
179
|
+
expect(response_data).to include id
|
180
|
+
end
|
181
|
+
|
182
|
+
context 'when a running instance completes' do
|
183
|
+
it 'is removed' do
|
184
|
+
scheduler.push( options )
|
185
|
+
sleep 0.1 while scheduler.completed.empty?
|
186
|
+
|
187
|
+
get url
|
188
|
+
expect(response_data).to be_empty
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe 'POST /instances' do
|
195
|
+
let(:tpl_url) { '/instances' }
|
196
|
+
|
197
|
+
it 'creates an instance' do
|
198
|
+
post url, options
|
199
|
+
expect(response_code).to eq 200
|
200
|
+
end
|
201
|
+
|
202
|
+
context 'when given invalid options' do
|
203
|
+
it 'returns a 500' do
|
204
|
+
post url, invalid: 'blah'
|
205
|
+
|
206
|
+
expect(response_code).to eq 500
|
207
|
+
expect(response_data['error']).to eq 'Arachni::RPC::Exceptions::RemoteException'
|
208
|
+
expect(response_data).to include 'backtrace'
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'does not list the instance on the index' do
|
212
|
+
get '/instances'
|
213
|
+
ids = response_data.keys
|
214
|
+
|
215
|
+
post url, invalid: 'blah'
|
216
|
+
|
217
|
+
get '/instances'
|
218
|
+
expect(response_data.keys - ids).to be_empty
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
context 'when the system is at max utilization' do
|
223
|
+
it 'returns a 503' do
|
224
|
+
Cuboid::Options.system.max_slots = 1
|
225
|
+
|
226
|
+
post url, options
|
227
|
+
expect(response_code).to eq 200
|
228
|
+
|
229
|
+
sleep 1
|
230
|
+
|
231
|
+
post url, options
|
232
|
+
expect(response_code).to eq 503
|
233
|
+
expect(response_data['error']).to eq 'Service unavailable: System is at maximum ' +
|
234
|
+
'utilization, slot limit reached.'
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
context 'when a Dispatcher has been set' do
|
239
|
+
|
240
|
+
it 'uses it' do
|
241
|
+
put '/dispatcher/url', dispatcher.url
|
242
|
+
|
243
|
+
get "/grid/#{dispatcher.url}"
|
244
|
+
expect(response_data['running_instances']).to be_empty
|
245
|
+
|
246
|
+
create_instance
|
247
|
+
|
248
|
+
get "/grid/#{dispatcher.url}"
|
249
|
+
expect(response_data['running_instances'].size).to eq 1
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe 'GET /instances/:instance' do
|
255
|
+
let(:tpl_url) { '/instances/%s' }
|
256
|
+
|
257
|
+
before do
|
258
|
+
@id = create_instance
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'gets progress info' do
|
262
|
+
loop do
|
263
|
+
get url
|
264
|
+
break if !response_data['busy']
|
265
|
+
sleep 0.5
|
266
|
+
end
|
267
|
+
|
268
|
+
%w(errors status busy messages statistics).each do |key|
|
269
|
+
expect(response_data).to include key
|
270
|
+
end
|
271
|
+
|
272
|
+
%w(statistics).each do |key|
|
273
|
+
expect(response_data.any?).to be_truthy
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
context 'when a session is maintained' do
|
278
|
+
it 'only returns new errors'
|
279
|
+
end
|
280
|
+
|
281
|
+
context 'when a session is not maintained' do
|
282
|
+
it 'always returns all errors'
|
283
|
+
end
|
284
|
+
|
285
|
+
context 'when passed a non-existent id' do
|
286
|
+
let(:id) { non_existent_id }
|
287
|
+
|
288
|
+
it 'returns 404' do
|
289
|
+
get url
|
290
|
+
expect(response_code).to eq 404
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
context 'when the instance is from the Scheduler' do
|
295
|
+
before do
|
296
|
+
put '/scheduler/url', scheduler.url
|
297
|
+
end
|
298
|
+
|
299
|
+
it 'includes it' do
|
300
|
+
@id = scheduler.push( options )
|
301
|
+
sleep 0.1 while scheduler.running.empty?
|
302
|
+
|
303
|
+
get url
|
304
|
+
expect(response_data).to include 'busy'
|
305
|
+
end
|
306
|
+
|
307
|
+
context 'when the instance completes' do
|
308
|
+
it 'is removed' do
|
309
|
+
@id = scheduler.push( options )
|
310
|
+
sleep 0.1 while scheduler.completed.empty?
|
311
|
+
|
312
|
+
get url
|
313
|
+
expect(response_code).to be 404
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
describe 'PUT /instances/:instance/scheduler' do
|
320
|
+
let(:tpl_url) { '/instances/%s/scheduler' }
|
321
|
+
|
322
|
+
before do
|
323
|
+
@id = create_instance
|
324
|
+
end
|
325
|
+
|
326
|
+
context 'when there is a Scheduler' do
|
327
|
+
before do
|
328
|
+
put '/scheduler/url', scheduler.url
|
329
|
+
end
|
330
|
+
|
331
|
+
it 'moves the instance to the Scheduler' do
|
332
|
+
expect(scheduler.running).to be_empty
|
333
|
+
|
334
|
+
put url
|
335
|
+
expect(response_code).to be 200
|
336
|
+
expect(scheduler.running).to include @id
|
337
|
+
end
|
338
|
+
|
339
|
+
context 'but the instance could not be found' do
|
340
|
+
it 'returns 404' do
|
341
|
+
@id = 'ss'
|
342
|
+
|
343
|
+
put url
|
344
|
+
expect(response_code).to be 404
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
context 'when there is no Scheduler' do
|
350
|
+
it 'returns 501' do
|
351
|
+
put url
|
352
|
+
expect(response_code).to be 501
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
describe 'GET /instances/:instance/summary' do
|
358
|
+
let(:tpl_url) { '/instances/%s/summary' }
|
359
|
+
|
360
|
+
before do
|
361
|
+
@id = create_instance
|
362
|
+
end
|
363
|
+
|
364
|
+
context 'when passed a non-existent id' do
|
365
|
+
let(:id) { non_existent_id }
|
366
|
+
|
367
|
+
it 'returns 404' do
|
368
|
+
get url
|
369
|
+
expect(response_code).to eq 404
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
context 'when the instance is from the Scheduler' do
|
374
|
+
before do
|
375
|
+
put '/scheduler/url', scheduler.url
|
376
|
+
end
|
377
|
+
|
378
|
+
it 'includes it' do
|
379
|
+
@id = scheduler.push( options )
|
380
|
+
sleep 0.1 while scheduler.running.empty?
|
381
|
+
|
382
|
+
get url
|
383
|
+
expect(response_data).to include 'busy'
|
384
|
+
end
|
385
|
+
|
386
|
+
context 'when the instance completes' do
|
387
|
+
it 'is removed' do
|
388
|
+
@id = scheduler.push( options )
|
389
|
+
sleep 0.1 while scheduler.completed.empty?
|
390
|
+
|
391
|
+
get url
|
392
|
+
expect(response_code).to be 404
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
describe 'GET /instances/:instance/report.crf' do
|
399
|
+
let(:tpl_url) { "/instances/%s/report.crf" }
|
400
|
+
|
401
|
+
before do
|
402
|
+
@id = create_instance
|
403
|
+
end
|
404
|
+
|
405
|
+
it 'returns instance report' do
|
406
|
+
get url
|
407
|
+
|
408
|
+
file = Tempfile.new( "#{Dir.tmpdir}/report-#{Process.pid}.crf" )
|
409
|
+
file.write last_response.body
|
410
|
+
file.close
|
411
|
+
|
412
|
+
expect(Cuboid::Report.load( file.path ).data).to eq 'My results.'
|
413
|
+
end
|
414
|
+
|
415
|
+
it 'has content-type application/octet-stream' do
|
416
|
+
get url
|
417
|
+
expect(last_response.headers['content-type']).to eq 'application/octet-stream'
|
418
|
+
end
|
419
|
+
|
420
|
+
context 'when passed a non-existent id' do
|
421
|
+
let(:id) { non_existent_id }
|
422
|
+
|
423
|
+
it 'returns 404' do
|
424
|
+
get url
|
425
|
+
expect(response_code).to eq 404
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
describe 'GET /instances/:instance/report.json' do
|
431
|
+
let(:tpl_url) { "/instances/%s/report.json" }
|
432
|
+
|
433
|
+
before do
|
434
|
+
@id = create_instance
|
435
|
+
end
|
436
|
+
|
437
|
+
it 'returns instance report' do
|
438
|
+
get url
|
439
|
+
|
440
|
+
report = JSON.load( last_response.body )
|
441
|
+
expect(MockApp.serializer.load report['data']).to eq 'My results.'
|
442
|
+
end
|
443
|
+
|
444
|
+
it 'has content-type application/json' do
|
445
|
+
get url
|
446
|
+
expect(last_response.headers['content-type']).to eq 'application/json'
|
447
|
+
end
|
448
|
+
|
449
|
+
context 'when passed a non-existent id' do
|
450
|
+
let(:id) { non_existent_id }
|
451
|
+
|
452
|
+
it 'returns 404' do
|
453
|
+
get url
|
454
|
+
expect(response_code).to eq 404
|
455
|
+
end
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
describe 'PUT /instances/:instance/pause' do
|
460
|
+
let(:tpl_url) { '/instances/%s/pause' }
|
461
|
+
|
462
|
+
before do
|
463
|
+
@id = create_instance
|
464
|
+
end
|
465
|
+
|
466
|
+
it 'pauses the instance' do
|
467
|
+
put url
|
468
|
+
expect(response_code).to eq 200
|
469
|
+
|
470
|
+
get "/instances/#{id}"
|
471
|
+
expect(['pausing', 'paused']).to include response_data['status']
|
472
|
+
end
|
473
|
+
|
474
|
+
context 'when passed a non-existent id' do
|
475
|
+
let(:id) { non_existent_id }
|
476
|
+
|
477
|
+
it 'returns 404' do
|
478
|
+
put url
|
479
|
+
expect(response_code).to eq 404
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
context 'when the instance is from the Scheduler' do
|
484
|
+
before do
|
485
|
+
put '/scheduler/url', scheduler.url
|
486
|
+
end
|
487
|
+
|
488
|
+
it 'includes it' do
|
489
|
+
@id = scheduler.push( options )
|
490
|
+
sleep 0.1 while scheduler.running.empty?
|
491
|
+
|
492
|
+
put url
|
493
|
+
expect(response_code).to eq 200
|
494
|
+
|
495
|
+
get "/instances/#{id}"
|
496
|
+
expect(['pausing', 'paused']).to include response_data['status']
|
497
|
+
end
|
498
|
+
|
499
|
+
context 'when the instance completes' do
|
500
|
+
it 'is removed' do
|
501
|
+
@id = scheduler.push( options )
|
502
|
+
sleep 0.1 while scheduler.completed.empty?
|
503
|
+
|
504
|
+
put url
|
505
|
+
expect(response_code).to be 404
|
506
|
+
end
|
507
|
+
end
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
describe 'PUT /instances/:instance/resume' do
|
512
|
+
let(:tpl_url) { '/instances/%s/resume' }
|
513
|
+
|
514
|
+
before do
|
515
|
+
@id = create_instance
|
516
|
+
end
|
517
|
+
|
518
|
+
it 'resumes the instance' do
|
519
|
+
put "/instances/#{id}/pause"
|
520
|
+
get "/instances/#{id}"
|
521
|
+
|
522
|
+
expect(['pausing', 'paused']).to include response_data['status']
|
523
|
+
|
524
|
+
put url
|
525
|
+
get "/instances/#{id}"
|
526
|
+
|
527
|
+
expect(['pausing', 'paused']).to_not include response_data['status']
|
528
|
+
end
|
529
|
+
|
530
|
+
context 'when passed a non-existent id' do
|
531
|
+
let(:id) { non_existent_id }
|
532
|
+
|
533
|
+
it 'returns 404' do
|
534
|
+
put url
|
535
|
+
expect(response_code).to eq 404
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
context 'when the instance is from the Scheduler' do
|
540
|
+
before do
|
541
|
+
put '/scheduler/url', scheduler.url
|
542
|
+
end
|
543
|
+
|
544
|
+
it 'includes it' do
|
545
|
+
@id = scheduler.push( options )
|
546
|
+
sleep 0.1 while scheduler.running.empty?
|
547
|
+
|
548
|
+
put "/instances/#{id}/pause"
|
549
|
+
get "/instances/#{id}"
|
550
|
+
|
551
|
+
expect(['pausing', 'paused']).to include response_data['status']
|
552
|
+
|
553
|
+
put url
|
554
|
+
get "/instances/#{id}"
|
555
|
+
|
556
|
+
expect(['running', 'done']).to include response_data['status']
|
557
|
+
end
|
558
|
+
|
559
|
+
context 'when the instance completes' do
|
560
|
+
it 'is removed' do
|
561
|
+
@id = scheduler.push( options )
|
562
|
+
sleep 0.1 while scheduler.completed.empty?
|
563
|
+
|
564
|
+
put url
|
565
|
+
expect(response_code).to be 404
|
566
|
+
end
|
567
|
+
end
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
describe 'DELETE /instances/:instance' do
|
572
|
+
let(:tpl_url) { '/instances/%s' }
|
573
|
+
|
574
|
+
before do
|
575
|
+
@id = create_instance
|
576
|
+
end
|
577
|
+
|
578
|
+
it 'aborts the instance' do
|
579
|
+
get url
|
580
|
+
expect(response_code).to eq 200
|
581
|
+
|
582
|
+
delete url
|
583
|
+
|
584
|
+
get "/instances/#{id}"
|
585
|
+
expect(response_code).to eq 404
|
586
|
+
end
|
587
|
+
|
588
|
+
context 'when passed a non-existent id' do
|
589
|
+
let(:id) { non_existent_id }
|
590
|
+
|
591
|
+
it 'returns 404' do
|
592
|
+
delete url
|
593
|
+
expect(response_code).to eq 404
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
context 'when the instance is from the Scheduler' do
|
598
|
+
before do
|
599
|
+
put '/scheduler/url', scheduler.url
|
600
|
+
end
|
601
|
+
|
602
|
+
it 'includes it' do
|
603
|
+
@id = scheduler.push( options )
|
604
|
+
sleep 0.1 while scheduler.running.empty?
|
605
|
+
|
606
|
+
delete url
|
607
|
+
expect(response_code).to eq 200
|
608
|
+
|
609
|
+
sleep 0.1 while scheduler.failed.empty?
|
610
|
+
|
611
|
+
expect(scheduler.failed).to include @id
|
612
|
+
end
|
613
|
+
|
614
|
+
context 'when the instance completes' do
|
615
|
+
it 'is removed' do
|
616
|
+
@id = scheduler.push( options )
|
617
|
+
sleep 0.1 while scheduler.completed.empty?
|
618
|
+
|
619
|
+
delete url
|
620
|
+
expect(response_code).to be 404
|
621
|
+
end
|
622
|
+
end
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
626
|
+
describe 'GET /dispatcher/url' do
|
627
|
+
let(:tpl_url) { '/dispatcher/url' }
|
628
|
+
|
629
|
+
it 'returns the Dispatcher' do
|
630
|
+
put url, dispatcher.url
|
631
|
+
expect(response_code).to eq 200
|
632
|
+
|
633
|
+
get url
|
634
|
+
expect(response_code).to eq 200
|
635
|
+
expect(response_data).to eq dispatcher.url
|
636
|
+
end
|
637
|
+
|
638
|
+
context 'when no Dispatcher has been set' do
|
639
|
+
it 'returns 501' do
|
640
|
+
get url
|
641
|
+
expect(response_code).to eq 501
|
642
|
+
expect(response_data).to eq 'No Dispatcher has been set.'
|
643
|
+
end
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
describe 'PUT /dispatcher/url' do
|
648
|
+
let(:tpl_url) { '/dispatcher/url' }
|
649
|
+
|
650
|
+
it 'sets the Dispatcher' do
|
651
|
+
put url, dispatcher.url
|
652
|
+
expect(response_code).to eq 200
|
653
|
+
end
|
654
|
+
|
655
|
+
context 'when passed a non-existent URL' do
|
656
|
+
let(:id) { non_existent_id }
|
657
|
+
|
658
|
+
it 'returns 500' do
|
659
|
+
put url, 'localhost:383838'
|
660
|
+
expect(response_code).to eq 500
|
661
|
+
expect(response_data['error']).to eq 'Arachni::RPC::Exceptions::ConnectionError'
|
662
|
+
end
|
663
|
+
end
|
664
|
+
end
|
665
|
+
|
666
|
+
describe 'DELETE /dispatcher/url' do
|
667
|
+
let(:tpl_url) { '/dispatcher/url' }
|
668
|
+
|
669
|
+
it 'removes the the Dispatcher' do
|
670
|
+
put url, dispatcher.url
|
671
|
+
expect(response_code).to eq 200
|
672
|
+
|
673
|
+
delete url
|
674
|
+
expect(response_code).to eq 200
|
675
|
+
|
676
|
+
get url, dispatcher.url
|
677
|
+
expect(response_code).to eq 501
|
678
|
+
end
|
679
|
+
|
680
|
+
context 'when no Dispatcher has been set' do
|
681
|
+
it 'returns 501' do
|
682
|
+
delete url
|
683
|
+
expect(response_code).to eq 501
|
684
|
+
expect(response_data).to eq 'No Dispatcher has been set.'
|
685
|
+
end
|
686
|
+
end
|
687
|
+
end
|
688
|
+
|
689
|
+
describe 'GET /grid' do
|
690
|
+
let(:dispatcher) { Cuboid::Processes::Dispatchers.grid_spawn }
|
691
|
+
let(:tpl_url) { '/grid' }
|
692
|
+
|
693
|
+
it 'returns Grid info' do
|
694
|
+
put '/dispatcher/url', dispatcher.url
|
695
|
+
expect(response_code).to eq 200
|
696
|
+
|
697
|
+
get url
|
698
|
+
expect(response_code).to eq 200
|
699
|
+
expect(response_data.sort).to eq ([dispatcher.url] + dispatcher.node.neighbours).sort
|
700
|
+
end
|
701
|
+
|
702
|
+
context 'when no Dispatcher has been set' do
|
703
|
+
it 'returns 501' do
|
704
|
+
get url
|
705
|
+
expect(response_code).to eq 501
|
706
|
+
expect(response_data).to eq 'No Dispatcher has been set.'
|
707
|
+
end
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
711
|
+
describe 'GET /grid/:dispatcher' do
|
712
|
+
let(:dispatcher) { Cuboid::Processes::Dispatchers.grid_spawn }
|
713
|
+
let(:tpl_url) { '/grid/%s' }
|
714
|
+
|
715
|
+
it 'returns Dispatcher info' do
|
716
|
+
put '/dispatcher/url', dispatcher.url
|
717
|
+
expect(response_code).to eq 200
|
718
|
+
|
719
|
+
@id = dispatcher.url
|
720
|
+
|
721
|
+
get url
|
722
|
+
expect(response_code).to eq 200
|
723
|
+
expect(response_data).to eq dispatcher.statistics
|
724
|
+
end
|
725
|
+
|
726
|
+
context 'when no Dispatcher has been set' do
|
727
|
+
it 'returns 501' do
|
728
|
+
@id = 'localhost:2222'
|
729
|
+
|
730
|
+
get url
|
731
|
+
expect(response_code).to eq 501
|
732
|
+
expect(response_data).to eq 'No Dispatcher has been set.'
|
733
|
+
end
|
734
|
+
end
|
735
|
+
end
|
736
|
+
|
737
|
+
describe 'DELETE /grid/:dispatcher' do
|
738
|
+
let(:dispatcher) { Cuboid::Processes::Dispatchers.grid_spawn }
|
739
|
+
let(:tpl_url) { '/grid/%s' }
|
740
|
+
|
741
|
+
it 'unplugs the Dispatcher from the Grid' do
|
742
|
+
put '/dispatcher/url', dispatcher.url
|
743
|
+
expect(response_code).to eq 200
|
744
|
+
|
745
|
+
@id = dispatcher.url
|
746
|
+
|
747
|
+
expect(dispatcher.node.grid_member?).to be_truthy
|
748
|
+
|
749
|
+
delete url
|
750
|
+
expect(response_code).to eq 200
|
751
|
+
expect(dispatcher.node.grid_member?).to be_falsey
|
752
|
+
end
|
753
|
+
|
754
|
+
context 'when no Dispatcher has been set' do
|
755
|
+
it 'returns 501' do
|
756
|
+
@id = 'localhost:2222'
|
757
|
+
|
758
|
+
delete url
|
759
|
+
expect(response_code).to eq 501
|
760
|
+
expect(response_data).to eq 'No Dispatcher has been set.'
|
761
|
+
end
|
762
|
+
end
|
763
|
+
end
|
764
|
+
|
765
|
+
describe 'GET /scheduler' do
|
766
|
+
let(:tpl_url) { '/scheduler' }
|
767
|
+
|
768
|
+
context 'when a Scheduler has been set' do
|
769
|
+
before do
|
770
|
+
put '/scheduler/url', scheduler.url
|
771
|
+
end
|
772
|
+
|
773
|
+
it 'lists schedulerd instances grouped by priority' do
|
774
|
+
low = scheduler.push( options, priority: -1 )
|
775
|
+
high = scheduler.push( options, priority: 1 )
|
776
|
+
medium = scheduler.push( options, priority: 0 )
|
777
|
+
|
778
|
+
get url
|
779
|
+
expect(response_code).to eq 200
|
780
|
+
expect(response_data.to_a).to eq({
|
781
|
+
'1' => [high],
|
782
|
+
'0' => [medium],
|
783
|
+
'-1' => [low]
|
784
|
+
}.to_a)
|
785
|
+
end
|
786
|
+
end
|
787
|
+
|
788
|
+
context 'when no Scheduler has been set' do
|
789
|
+
it 'returns 501' do
|
790
|
+
get url
|
791
|
+
|
792
|
+
expect(response_code).to eq 501
|
793
|
+
expect(response_data).to eq 'No Scheduler has been set.'
|
794
|
+
end
|
795
|
+
end
|
796
|
+
end
|
797
|
+
|
798
|
+
describe 'POST /scheduler' do
|
799
|
+
let(:tpl_url) { '/scheduler' }
|
800
|
+
|
801
|
+
context 'when a Scheduler has been set' do
|
802
|
+
before do
|
803
|
+
put '/scheduler/url', scheduler.url
|
804
|
+
end
|
805
|
+
|
806
|
+
it 'pushes the instance to the Scheduler' do
|
807
|
+
post url, [options, priority: 9]
|
808
|
+
|
809
|
+
expect(response_code).to eq 200
|
810
|
+
|
811
|
+
id = response_data['id']
|
812
|
+
|
813
|
+
expect(scheduler.get(id)).to eq(
|
814
|
+
'options' => options,
|
815
|
+
'priority' => 9
|
816
|
+
)
|
817
|
+
end
|
818
|
+
|
819
|
+
context 'when given invalid options' do
|
820
|
+
it 'returns a 500' do
|
821
|
+
post url, invalid: 'blah'
|
822
|
+
|
823
|
+
expect(response_code).to eq 500
|
824
|
+
expect(response_data['error']).to eq 'Arachni::RPC::Exceptions::RemoteException'
|
825
|
+
expect(response_data).to include 'backtrace'
|
826
|
+
end
|
827
|
+
end
|
828
|
+
end
|
829
|
+
|
830
|
+
context 'when no Scheduler has been set' do
|
831
|
+
it 'returns 501' do
|
832
|
+
get url
|
833
|
+
|
834
|
+
expect(response_code).to eq 501
|
835
|
+
expect(response_data).to eq 'No Scheduler has been set.'
|
836
|
+
end
|
837
|
+
end
|
838
|
+
end
|
839
|
+
|
840
|
+
describe 'GET /scheduler/url' do
|
841
|
+
let(:tpl_url) { '/scheduler/url' }
|
842
|
+
|
843
|
+
context 'when a Scheduler has been set' do
|
844
|
+
before do
|
845
|
+
put '/scheduler/url', scheduler.url
|
846
|
+
end
|
847
|
+
|
848
|
+
it 'returns its URL' do
|
849
|
+
get url
|
850
|
+
expect(response_code).to eq 200
|
851
|
+
expect(response_data).to eq scheduler.url
|
852
|
+
end
|
853
|
+
end
|
854
|
+
|
855
|
+
context 'when no Scheduler has been set' do
|
856
|
+
it 'returns 501' do
|
857
|
+
get url
|
858
|
+
|
859
|
+
expect(response_code).to eq 501
|
860
|
+
expect(response_data).to eq 'No Scheduler has been set.'
|
861
|
+
end
|
862
|
+
end
|
863
|
+
end
|
864
|
+
|
865
|
+
describe 'PUT /scheduler/url' do
|
866
|
+
let(:tpl_url) { '/scheduler/url' }
|
867
|
+
|
868
|
+
|
869
|
+
it 'sets the Scheduler URL' do
|
870
|
+
put url, scheduler.url
|
871
|
+
expect(response_code).to eq 200
|
872
|
+
end
|
873
|
+
|
874
|
+
context 'when given an invalid URL' do
|
875
|
+
it 'returns 500' do
|
876
|
+
put url, 'localhost:393939'
|
877
|
+
|
878
|
+
expect(response_code).to eq 500
|
879
|
+
expect(response_data['error']).to eq 'Arachni::RPC::Exceptions::ConnectionError'
|
880
|
+
expect(response_data['description']).to include 'Connection closed'
|
881
|
+
end
|
882
|
+
end
|
883
|
+
end
|
884
|
+
|
885
|
+
describe 'DELETE /scheduler/url' do
|
886
|
+
let(:tpl_url) { '/scheduler/url' }
|
887
|
+
|
888
|
+
context 'when a Scheduler has been set' do
|
889
|
+
before do
|
890
|
+
put '/scheduler/url', scheduler.url
|
891
|
+
end
|
892
|
+
|
893
|
+
it 'removes it' do
|
894
|
+
delete url
|
895
|
+
expect(response_code).to eq 200
|
896
|
+
|
897
|
+
get '/scheduler/url'
|
898
|
+
expect(response_code).to eq 501
|
899
|
+
end
|
900
|
+
end
|
901
|
+
|
902
|
+
context 'when no Scheduler has been set' do
|
903
|
+
it 'returns 501' do
|
904
|
+
get url
|
905
|
+
|
906
|
+
expect(response_code).to eq 501
|
907
|
+
expect(response_data).to eq 'No Scheduler has been set.'
|
908
|
+
end
|
909
|
+
end
|
910
|
+
end
|
911
|
+
|
912
|
+
describe 'GET /scheduler/running' do
|
913
|
+
let(:tpl_url) { '/scheduler/running' }
|
914
|
+
|
915
|
+
context 'when a Scheduler has been set' do
|
916
|
+
before do
|
917
|
+
put '/scheduler/url', scheduler.url
|
918
|
+
end
|
919
|
+
|
920
|
+
it 'returns running instances' do
|
921
|
+
get url
|
922
|
+
expect(response_data.empty?).to be_truthy
|
923
|
+
|
924
|
+
@id = scheduler.push( options )
|
925
|
+
sleep 0.1 while scheduler.running.empty?
|
926
|
+
|
927
|
+
get url
|
928
|
+
expect(response_data.size).to be 1
|
929
|
+
expect(response_data[@id]).to include 'url'
|
930
|
+
expect(response_data[@id]).to include 'token'
|
931
|
+
expect(response_data[@id]).to include 'pid'
|
932
|
+
end
|
933
|
+
end
|
934
|
+
|
935
|
+
context 'when no Scheduler has been set' do
|
936
|
+
it 'returns 501' do
|
937
|
+
get url
|
938
|
+
|
939
|
+
expect(response_code).to eq 501
|
940
|
+
expect(response_data).to eq 'No Scheduler has been set.'
|
941
|
+
end
|
942
|
+
end
|
943
|
+
end
|
944
|
+
|
945
|
+
describe 'GET /scheduler/completed' do
|
946
|
+
let(:tpl_url) { '/scheduler/completed' }
|
947
|
+
|
948
|
+
context 'when a Scheduler has been set' do
|
949
|
+
before do
|
950
|
+
put '/scheduler/url', scheduler.url
|
951
|
+
end
|
952
|
+
|
953
|
+
it 'returns completed instances' do
|
954
|
+
get url
|
955
|
+
expect(response_data.empty?).to be_truthy
|
956
|
+
|
957
|
+
@id = scheduler.push( options )
|
958
|
+
sleep 0.1 while scheduler.completed.empty?
|
959
|
+
|
960
|
+
get url
|
961
|
+
expect(response_data.size).to be 1
|
962
|
+
expect(File.exists? response_data[@id]).to be true
|
963
|
+
end
|
964
|
+
end
|
965
|
+
|
966
|
+
context 'when no Scheduler has been set' do
|
967
|
+
it 'returns 501' do
|
968
|
+
get url
|
969
|
+
|
970
|
+
expect(response_code).to eq 501
|
971
|
+
expect(response_data).to eq 'No Scheduler has been set.'
|
972
|
+
end
|
973
|
+
end
|
974
|
+
end
|
975
|
+
|
976
|
+
describe 'GET /scheduler/failed' do
|
977
|
+
let(:tpl_url) { '/scheduler/failed' }
|
978
|
+
|
979
|
+
context 'when a Scheduler has been set' do
|
980
|
+
before do
|
981
|
+
put '/scheduler/url', scheduler.url
|
982
|
+
end
|
983
|
+
|
984
|
+
it 'returns failed instances' do
|
985
|
+
get url
|
986
|
+
expect(response_data.empty?).to be_truthy
|
987
|
+
|
988
|
+
@id = scheduler.push( options )
|
989
|
+
sleep 0.1 while scheduler.running.empty?
|
990
|
+
Cuboid::Processes::Manager.kill scheduler.running.values.first['pid']
|
991
|
+
sleep 0.1 while scheduler.failed.empty?
|
992
|
+
|
993
|
+
get url
|
994
|
+
expect(response_data.size).to be 1
|
995
|
+
expect(response_data[@id]['error']).to eq 'Arachni::RPC::Exceptions::ConnectionError'
|
996
|
+
expect(response_data[@id]['description']).to include 'Connection closed [Connection refused - connect(2) for'
|
997
|
+
end
|
998
|
+
end
|
999
|
+
|
1000
|
+
context 'when no Scheduler has been set' do
|
1001
|
+
it 'returns 501' do
|
1002
|
+
get url
|
1003
|
+
|
1004
|
+
expect(response_code).to eq 501
|
1005
|
+
expect(response_data).to eq 'No Scheduler has been set.'
|
1006
|
+
end
|
1007
|
+
end
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
describe 'GET /scheduler/size' do
|
1011
|
+
let(:tpl_url) { '/scheduler/size' }
|
1012
|
+
|
1013
|
+
context 'when a Scheduler has been set' do
|
1014
|
+
before do
|
1015
|
+
put '/scheduler/url', scheduler.url
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
it 'returns the scheduler size' do
|
1019
|
+
get url
|
1020
|
+
expect(response_data).to eq 0
|
1021
|
+
|
1022
|
+
10.times do
|
1023
|
+
scheduler.push( options )
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
get url
|
1027
|
+
expect(response_data).to be 10
|
1028
|
+
end
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
context 'when no Scheduler has been set' do
|
1032
|
+
it 'returns 501' do
|
1033
|
+
get url
|
1034
|
+
|
1035
|
+
expect(response_code).to eq 501
|
1036
|
+
expect(response_data).to eq 'No Scheduler has been set.'
|
1037
|
+
end
|
1038
|
+
end
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
describe 'DELETE /scheduler' do
|
1042
|
+
let(:tpl_url) { '/scheduler' }
|
1043
|
+
|
1044
|
+
context 'when a Scheduler has been set' do
|
1045
|
+
before do
|
1046
|
+
put '/scheduler/url', scheduler.url
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
it 'empties the scheduler' do
|
1050
|
+
expect(scheduler.empty?).to be_truthy
|
1051
|
+
|
1052
|
+
10.times do
|
1053
|
+
scheduler.push( options )
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
expect(scheduler.any?).to be_truthy
|
1057
|
+
|
1058
|
+
delete url
|
1059
|
+
expect(scheduler.empty?).to be_truthy
|
1060
|
+
end
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
context 'when no Scheduler has been set' do
|
1064
|
+
it 'returns 501' do
|
1065
|
+
get url
|
1066
|
+
|
1067
|
+
expect(response_code).to eq 501
|
1068
|
+
expect(response_data).to eq 'No Scheduler has been set.'
|
1069
|
+
end
|
1070
|
+
end
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
describe 'GET /scheduler/:instance' do
|
1074
|
+
let(:tpl_url) { '/scheduler/%s' }
|
1075
|
+
|
1076
|
+
context 'when a Scheduler has been set' do
|
1077
|
+
before do
|
1078
|
+
put '/scheduler/url', scheduler.url
|
1079
|
+
end
|
1080
|
+
|
1081
|
+
it 'returns info for the Queued instance' do
|
1082
|
+
@id = scheduler.push( options )
|
1083
|
+
|
1084
|
+
get url
|
1085
|
+
expect(response_code).to be 200
|
1086
|
+
expect(response_data).to eq({
|
1087
|
+
'options' => options,
|
1088
|
+
'priority' => 0
|
1089
|
+
})
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
context 'when the instance could not be found' do
|
1093
|
+
let(:id) { non_existent_id }
|
1094
|
+
|
1095
|
+
it 'returns 404' do
|
1096
|
+
get url
|
1097
|
+
|
1098
|
+
expect(response_code).to eq 404
|
1099
|
+
expect(response_data).to eq 'Instance not in Scheduler.'
|
1100
|
+
end
|
1101
|
+
end
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
context 'when no Scheduler has been set' do
|
1105
|
+
let(:id) { non_existent_id }
|
1106
|
+
|
1107
|
+
it 'returns 501' do
|
1108
|
+
get url
|
1109
|
+
|
1110
|
+
expect(response_code).to eq 501
|
1111
|
+
expect(response_data).to eq 'No Scheduler has been set.'
|
1112
|
+
end
|
1113
|
+
end
|
1114
|
+
end
|
1115
|
+
|
1116
|
+
describe 'PUT /scheduler/:instance/detach' do
|
1117
|
+
let(:tpl_url) { '/scheduler/%s/detach' }
|
1118
|
+
|
1119
|
+
context 'when a Scheduler has been set' do
|
1120
|
+
before do
|
1121
|
+
put '/scheduler/url', scheduler.url
|
1122
|
+
end
|
1123
|
+
|
1124
|
+
it 'detaches the instance from the Scheduler' do
|
1125
|
+
@id = scheduler.push( options )
|
1126
|
+
sleep 0.1 while scheduler.running.empty?
|
1127
|
+
|
1128
|
+
put url
|
1129
|
+
expect(response_code).to be 200
|
1130
|
+
expect(scheduler.running).to be_empty
|
1131
|
+
expect(scheduler.completed).to be_empty
|
1132
|
+
expect(scheduler.failed).to be_empty
|
1133
|
+
|
1134
|
+
get '/instances'
|
1135
|
+
expect(response_code).to be 200
|
1136
|
+
expect(response_data.keys).to eq [@id]
|
1137
|
+
end
|
1138
|
+
|
1139
|
+
context 'when the instance could not be found' do
|
1140
|
+
let(:id) { non_existent_id }
|
1141
|
+
|
1142
|
+
it 'returns 404' do
|
1143
|
+
put url
|
1144
|
+
|
1145
|
+
expect(response_code).to eq 404
|
1146
|
+
expect(response_data).to eq 'Instance not in Scheduler.'
|
1147
|
+
end
|
1148
|
+
end
|
1149
|
+
end
|
1150
|
+
|
1151
|
+
context 'when no Scheduler has been set' do
|
1152
|
+
let(:id) { non_existent_id }
|
1153
|
+
|
1154
|
+
it 'returns 501' do
|
1155
|
+
put url
|
1156
|
+
|
1157
|
+
expect(response_code).to eq 501
|
1158
|
+
expect(response_data).to eq 'No Scheduler has been set.'
|
1159
|
+
end
|
1160
|
+
end
|
1161
|
+
end
|
1162
|
+
|
1163
|
+
describe 'DELETE /scheduler/:instance' do
|
1164
|
+
let(:tpl_url) { '/scheduler/%s' }
|
1165
|
+
|
1166
|
+
context 'when a Scheduler has been set' do
|
1167
|
+
before do
|
1168
|
+
put '/scheduler/url', scheduler.url
|
1169
|
+
end
|
1170
|
+
|
1171
|
+
it 'removes the instance from the Scheduler' do
|
1172
|
+
@id = scheduler.push( options )
|
1173
|
+
|
1174
|
+
expect(scheduler.any?).to be_truthy
|
1175
|
+
|
1176
|
+
delete url
|
1177
|
+
|
1178
|
+
expect(response_code).to be 200
|
1179
|
+
expect(scheduler.empty?).to be_truthy
|
1180
|
+
end
|
1181
|
+
|
1182
|
+
context 'when the instance could not be found' do
|
1183
|
+
let(:id) { non_existent_id }
|
1184
|
+
|
1185
|
+
it 'returns 404' do
|
1186
|
+
delete url
|
1187
|
+
|
1188
|
+
expect(response_code).to eq 404
|
1189
|
+
expect(response_data).to eq 'Instance not in Scheduler.'
|
1190
|
+
end
|
1191
|
+
end
|
1192
|
+
end
|
1193
|
+
|
1194
|
+
context 'when no Scheduler has been set' do
|
1195
|
+
let(:id) { non_existent_id }
|
1196
|
+
|
1197
|
+
it 'returns 501' do
|
1198
|
+
delete url
|
1199
|
+
|
1200
|
+
expect(response_code).to eq 501
|
1201
|
+
expect(response_data).to eq 'No Scheduler has been set.'
|
1202
|
+
end
|
1203
|
+
end
|
1204
|
+
end
|
1205
|
+
end
|