appforce-spawn 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.
- checksums.yaml +7 -0
- data/.appforce.example +4 -0
- data/.gitignore +8 -0
- data/Gemfile +17 -0
- data/History +85 -0
- data/README.md +144 -0
- data/ansible/README.md +31 -0
- data/ansible/common.yml +6 -0
- data/ansible/roles/common/tasks/.keep +0 -0
- data/ansible/roles/common/tasks/active_users.yml +23 -0
- data/ansible/roles/common/tasks/groups.yml +28 -0
- data/ansible/roles/common/tasks/inactive_users.yml +26 -0
- data/ansible/roles/common/tasks/main.yml +5 -0
- data/ansible/roles/common/tasks/setup.yml +6 -0
- data/ansible/roles/scout/tasks/.keep +0 -0
- data/ansible/roles/scout/tasks/install.yml +28 -0
- data/ansible/roles/scout/tasks/main.yml +2 -0
- data/ansible/roles/scout/vars/.keep +0 -0
- data/ansible/rvm.yml +13 -0
- data/ansible/scout.yml +6 -0
- data/ansible/site.yml +4 -0
- data/appforce-spawn.gemspec +24 -0
- data/bin/appforce-spawn +161 -0
- data/lib/appforce-spawn.rb +1 -0
- data/lib/appforce/config.rb +50 -0
- data/lib/appforce/logger.rb +25 -0
- data/lib/appforce/spawn.rb +312 -0
- data/lib/appforce/spawn/api.rb +4 -0
- data/lib/appforce/spawn/api/call.rb +217 -0
- data/lib/appforce/spawn/exceptions.rb +30 -0
- data/lib/appforce/spawn/runner.rb +143 -0
- data/lib/appforce/spawn/template.rb +102 -0
- data/lib/appforce/spawn/version.rb +10 -0
- data/spec/api_call_spec.rb +380 -0
- data/spec/config_spec.rb +51 -0
- data/spec/fixtures/all_host_data.json +12 -0
- data/spec/fixtures/appforce_config.yml +4 -0
- data/spec/fixtures/fake_private_key.yml +2 -0
- data/spec/fixtures/host_scout_vars.yml +10 -0
- data/spec/fixtures/hosts +8 -0
- data/spec/fixtures/inactive_users.yml +3 -0
- data/spec/fixtures/malformed_appforce_config.yml +4 -0
- data/spec/fixtures/private_key_vars.yml +4 -0
- data/spec/fixtures/scout_main.yml +2 -0
- data/spec/fixtures/users.yml +6 -0
- data/spec/fixtures/vars.yml +4 -0
- data/spec/logger_spec.rb +85 -0
- data/spec/runner_spec.rb +308 -0
- data/spec/spec_helper.rb +53 -0
- data/spec/template_spec.rb +160 -0
- data/spec/version_spec.rb +9 -0
- data/tmp/.keep +0 -0
- metadata +151 -0
@@ -0,0 +1,380 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
2
|
+
|
3
|
+
RSpec.describe Appforce::Spawn::Api::Call do
|
4
|
+
before do
|
5
|
+
logger = Logger.new('/dev/null')
|
6
|
+
Appforce::Spawn.logger = logger
|
7
|
+
Appforce::Config.load_config(file_fixture_path('appforce_config.yml'))
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '.latest_version' do
|
11
|
+
before do
|
12
|
+
@last_modified = Date.new(2010, 1, 15).to_s
|
13
|
+
@content_length = '1024'
|
14
|
+
@request_object = HTTParty::Request.new Net::HTTP::Get, '/'
|
15
|
+
@response_object = Net::HTTPOK.new('1.1', 200, 'OK')
|
16
|
+
allow(@response_object).to receive_messages(body: '{"version":"0.1"}')
|
17
|
+
@response_object['last-modified'] = @last_modified
|
18
|
+
@response_object['content-length'] = @content_length
|
19
|
+
@parsed_response = lambda { {"version" => "0.1"} }
|
20
|
+
@response = HTTParty::Response.new(@request_object, @response_object, @parsed_response)
|
21
|
+
allow(HTTParty).to receive(:get).and_return(@response)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should return the latest version number from RubyGems' do
|
25
|
+
info = Appforce::Spawn::Api::Call.latest_version
|
26
|
+
expect(info).to be_a String
|
27
|
+
expect(info).to eq '0.1'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '.get_hosts' do
|
32
|
+
context 'missing parameters (Client API Name)' do
|
33
|
+
it 'should raise an exception' do
|
34
|
+
expect { Appforce::Spawn::Api::Call.get_hosts(*[nil, {}]) }.to raise_exception(Appforce::Spawn::MissingParameters)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'has Client API Name parameter' do
|
39
|
+
before do
|
40
|
+
resp = double('resp')
|
41
|
+
allow(resp).to receive(:code).and_return(200)
|
42
|
+
allow(resp).to receive(:value).and_return('good')
|
43
|
+
allow(HTTParty).to receive(:get).and_return(resp)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should return an API response' do
|
47
|
+
api_resp = Appforce::Spawn::Api::Call.get_hosts(*[nil, {:client_api_name => 'template_test'}])
|
48
|
+
expect(api_resp.value).to eq 'good'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '.get_vars' do
|
54
|
+
context 'missing parameters (Client API Name)' do
|
55
|
+
it 'should raise an exception' do
|
56
|
+
expect { Appforce::Spawn::Api::Call.get_vars(*[nil, {}]) }.to raise_exception(Appforce::Spawn::MissingParameters)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'has Client API Name parameter' do
|
61
|
+
before do
|
62
|
+
resp = double('resp')
|
63
|
+
allow(resp).to receive(:code).and_return(200)
|
64
|
+
allow(resp).to receive(:value).and_return('good')
|
65
|
+
allow(HTTParty).to receive(:get).and_return(resp)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should return an API response' do
|
69
|
+
api_resp = Appforce::Spawn::Api::Call.get_vars(*[nil, {:client_api_name => 'template_test'}])
|
70
|
+
expect(api_resp.value).to eq 'good'
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '.get_active_users' do
|
76
|
+
context 'missing parameters (Client API Name)' do
|
77
|
+
it 'should raise an exception' do
|
78
|
+
expect { Appforce::Spawn::Api::Call.get_active_users(*[nil, {}]) }.to raise_exception(Appforce::Spawn::MissingParameters)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'has Client API Name parameter' do
|
83
|
+
before do
|
84
|
+
resp = double('resp')
|
85
|
+
allow(resp).to receive(:code).and_return(200)
|
86
|
+
allow(resp).to receive(:value).and_return('good')
|
87
|
+
allow(HTTParty).to receive(:get).and_return(resp)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should return an API response' do
|
91
|
+
api_resp = Appforce::Spawn::Api::Call.get_active_users(*[nil, {:client_api_name => 'template_test'}])
|
92
|
+
expect(api_resp.value).to eq 'good'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '.get_inactive_users' do
|
98
|
+
context 'missing parameters (Client API Name)' do
|
99
|
+
it 'should raise an exception' do
|
100
|
+
expect { Appforce::Spawn::Api::Call.get_inactive_users(*[nil, {}]) }.to raise_exception(Appforce::Spawn::MissingParameters)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'has Client API Name parameter' do
|
105
|
+
before do
|
106
|
+
resp = double('resp')
|
107
|
+
allow(resp).to receive(:code).and_return(200)
|
108
|
+
allow(resp).to receive(:value).and_return('good')
|
109
|
+
allow(HTTParty).to receive(:get).and_return(resp)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should return an API response' do
|
113
|
+
api_resp = Appforce::Spawn::Api::Call.get_inactive_users(*[nil, {:client_api_name => 'template_test'}])
|
114
|
+
expect(api_resp.value).to eq 'good'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe '.get_private_key' do
|
120
|
+
context 'missing parameters (Client API Name)' do
|
121
|
+
it 'should raise an exception' do
|
122
|
+
expect { Appforce::Spawn::Api::Call.get_private_key(*[nil, {}]) }.to raise_exception(Appforce::Spawn::MissingParameters)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'has Client API Name parameter' do
|
127
|
+
before do
|
128
|
+
resp = double('resp')
|
129
|
+
allow(resp).to receive(:code).and_return(200)
|
130
|
+
allow(resp).to receive(:value).and_return('good')
|
131
|
+
allow(HTTParty).to receive(:get).and_return(resp)
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should return an API response' do
|
135
|
+
api_resp = Appforce::Spawn::Api::Call.get_private_key(*[nil, {:client_api_name => 'template_test'}])
|
136
|
+
expect(api_resp.value).to eq 'good'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '.ping' do
|
142
|
+
context 'Host is available' do
|
143
|
+
before do
|
144
|
+
resp = double('resp')
|
145
|
+
allow(resp).to receive(:code).and_return(200)
|
146
|
+
allow(resp).to receive(:value).and_return('good')
|
147
|
+
allow(HTTParty).to receive(:get).and_return(resp)
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'should return 200' do
|
151
|
+
ping = Appforce::Spawn::Api::Call.ping
|
152
|
+
expect(ping.code).to eq 200
|
153
|
+
expect(ping.value).to eq 'good'
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe '.get_clients' do
|
159
|
+
context 'Host is available' do
|
160
|
+
before do
|
161
|
+
resp = double('resp')
|
162
|
+
allow(resp).to receive(:code).and_return(200)
|
163
|
+
allow(resp).to receive(:value).and_return('good')
|
164
|
+
allow(HTTParty).to receive(:get).and_return(resp)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should return 200' do
|
168
|
+
ping = Appforce::Spawn::Api::Call.get_clients
|
169
|
+
expect(ping.code).to eq 200
|
170
|
+
expect(ping.value).to eq 'good'
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe '.get_all_host_data' do
|
176
|
+
context 'missing parameters (Client API Name)' do
|
177
|
+
it 'should raise an exception' do
|
178
|
+
expect { Appforce::Spawn::Api::Call.get_all_host_data(*[nil, {}]) }.to raise_exception(Appforce::Spawn::MissingParameters)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
context 'has Client API Name parameter' do
|
183
|
+
before do
|
184
|
+
resp = double('resp')
|
185
|
+
allow(resp).to receive(:code).and_return(200)
|
186
|
+
allow(resp).to receive(:value).and_return('good')
|
187
|
+
allow(HTTParty).to receive(:get).and_return(resp)
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'should return an API response' do
|
191
|
+
api_resp = Appforce::Spawn::Api::Call.get_all_host_data(*[nil, {:client_api_name => 'template_test'}])
|
192
|
+
expect(api_resp.value).to eq 'good'
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
describe '.get_main_scout' do
|
198
|
+
context 'missing parameters (Client API Name)' do
|
199
|
+
it 'should raise an exception' do
|
200
|
+
expect { Appforce::Spawn::Api::Call.get_main_scout(*[nil, {}]) }.to raise_exception(Appforce::Spawn::MissingParameters)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context 'has Client API Name parameter' do
|
205
|
+
before do
|
206
|
+
resp = double('resp')
|
207
|
+
allow(resp).to receive(:code).and_return(200)
|
208
|
+
allow(resp).to receive(:value).and_return('good')
|
209
|
+
allow(HTTParty).to receive(:get).and_return(resp)
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'should return an API response' do
|
213
|
+
api_resp = Appforce::Spawn::Api::Call.get_main_scout(*[nil, {:client_api_name => 'template_test'}])
|
214
|
+
expect(api_resp.value).to eq 'good'
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe '.get_host_scout_vars' do
|
220
|
+
context 'missing parameters (Host API Name)' do
|
221
|
+
it 'should raise an exception' do
|
222
|
+
expect { Appforce::Spawn::Api::Call.get_host_scout_vars(*[nil, {}]) }.to raise_exception(Appforce::Spawn::MissingParameters)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
context 'has Client API Name parameter' do
|
227
|
+
before do
|
228
|
+
resp = double('resp')
|
229
|
+
allow(resp).to receive(:code).and_return(200)
|
230
|
+
allow(resp).to receive(:value).and_return('good')
|
231
|
+
allow(HTTParty).to receive(:get).and_return(resp)
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'should return an API response' do
|
235
|
+
api_resp = Appforce::Spawn::Api::Call.get_host_scout_vars(*[nil, {:host_api_name => '1'}])
|
236
|
+
expect(api_resp.value).to eq 'good'
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe '.list_clients' do
|
242
|
+
context 'Host is available' do
|
243
|
+
before do
|
244
|
+
resp = Enumerator.new do |y|
|
245
|
+
1.times do |x|
|
246
|
+
y << {"name"=>"test", "api_name"=>"test"}
|
247
|
+
end
|
248
|
+
end
|
249
|
+
allow(resp).to receive(:value).and_return('good')
|
250
|
+
allow(resp).to receive(:code).and_return(200)
|
251
|
+
allow(HTTParty).to receive(:get).and_return(resp)
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'should return 200' do
|
255
|
+
expect { Appforce::Spawn::Api::Call.list_clients }.to output(" == Client List ==============================================================\n Client: test API Name: test\n =============================================================================\n").to_stdout
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
describe '.list_hosts' do
|
261
|
+
context 'Host is available' do
|
262
|
+
before do
|
263
|
+
allow(Appforce::Spawn::Api::Call).to receive(:get_all_host_data).and_return(file_fixture_to_json('all_host_data.json'))
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'should write a list of hosts to screen + return the JSON list of hosts' do
|
267
|
+
resp = nil
|
268
|
+
expect { resp = Appforce::Spawn::Api::Call.list_hosts }.to output(" == Host List ================================================================\n 1 - 'ubuntu-test01' host: ubuntu-test01 ip: 192.168.10.3\n =============================================================================\n").to_stdout
|
269
|
+
expect(resp).to eq file_fixture_to_json('all_host_data.json')
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
describe '.ssh_to_host' do
|
275
|
+
context 'Host is available' do
|
276
|
+
before do
|
277
|
+
allow(Appforce::Spawn::Api::Call).to receive(:get_all_host_data).and_return(file_fixture_to_json('all_host_data.json'))
|
278
|
+
allow(Appforce::Spawn::Api::Call).to receive(:ssh_cmd).and_return('touch tmp/fork')
|
279
|
+
allow(HighLine).to receive(:ask).and_return(1)
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'should execute the command returned by the ssh_cmd call based on the input from the user' do
|
283
|
+
expect { Appforce::Spawn::Api::Call.ssh_to_host }.to output(" == Host List ================================================================\n 1 - 'ubuntu-test01' host: ubuntu-test01 ip: 192.168.10.3\n =============================================================================\n").to_stdout
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
context 'private methods' do
|
289
|
+
describe '.ssh_cmd' do
|
290
|
+
it 'should return a valid ssh command' do
|
291
|
+
params = {'hostname' => 'test', 'username' => 'user', 'method' => 'hostname' }
|
292
|
+
expect(Appforce::Spawn::Api::Call.send(:ssh_cmd, params)).to eq 'ssh user@test'
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
describe '.base_api_url' do
|
297
|
+
it 'should return the API URL driven by the .appforce config' do
|
298
|
+
expect(Appforce::Spawn::Api::Call.send(:base_api_url)).to eq 'http://afuka.synctree.com/VERSION_STRING/'
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
describe '.client_url' do
|
303
|
+
it 'should return the API URL for the Client' do
|
304
|
+
expect(Appforce::Spawn::Api::Call.send(:client_url, 'test')).to eq 'http://afuka.synctree.com/VERSION_STRING/client/test'
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
describe '.token_param' do
|
309
|
+
it 'should return the token parameter string' do
|
310
|
+
expect(Appforce::Spawn::Api::Call.send(:token_param)).to eq 'token=INVALID_TOKEN'
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
describe '.make_api_call' do
|
315
|
+
context 'get a valid API response' do
|
316
|
+
before do
|
317
|
+
resp = double('resp')
|
318
|
+
allow(resp).to receive(:code).and_return(200)
|
319
|
+
allow(resp).to receive(:value).and_return('good')
|
320
|
+
allow(HTTParty).to receive(:get).and_return(resp)
|
321
|
+
end
|
322
|
+
|
323
|
+
it 'should return the response object' do
|
324
|
+
api_resp = Appforce::Spawn::Api::Call.send(:make_api_call, 'url')
|
325
|
+
expect(api_resp.value).to eq 'good'
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
context 'use an invalid token' do
|
330
|
+
before do
|
331
|
+
resp = double('resp')
|
332
|
+
allow(resp).to receive(:code).and_return(401)
|
333
|
+
allow(resp).to receive(:value).and_return('invalid')
|
334
|
+
allow(HTTParty).to receive(:get).and_return(resp)
|
335
|
+
end
|
336
|
+
|
337
|
+
it 'should raise an Appforce::Spawn::API::UnauthorizedAccess exception' do
|
338
|
+
expect { Appforce::Spawn::Api::Call.send(:make_api_call, 'url') }.to raise_exception(Appforce::Spawn::API::UnauthorizedAccess)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
context 'hit an invalid route' do
|
343
|
+
before do
|
344
|
+
resp = double('resp')
|
345
|
+
allow(resp).to receive(:code).and_return(404)
|
346
|
+
allow(resp).to receive(:value).and_return('invalid')
|
347
|
+
allow(HTTParty).to receive(:get).and_return(resp)
|
348
|
+
end
|
349
|
+
|
350
|
+
it 'should raise an Appforce::Spawn::API::NotFound exception' do
|
351
|
+
expect { Appforce::Spawn::Api::Call.send(:make_api_call, 'url') }.to raise_exception(Appforce::Spawn::API::NotFound)
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
context 'service is unavailable' do
|
356
|
+
before do
|
357
|
+
resp = double('resp')
|
358
|
+
allow(resp).to receive(:code).and_return(502)
|
359
|
+
allow(resp).to receive(:value).and_return('invalid')
|
360
|
+
allow(HTTParty).to receive(:get).and_return(resp)
|
361
|
+
end
|
362
|
+
|
363
|
+
it 'should raise an Appforce::Spawn::API::Unavailable exception' do
|
364
|
+
expect { Appforce::Spawn::Api::Call.send(:make_api_call, 'url') }.to raise_exception(Appforce::Spawn::API::Unavailable)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
context 'HTTParty raises an exception' do
|
369
|
+
before do
|
370
|
+
allow(HTTParty).to receive(:get).and_raise('BOOM')
|
371
|
+
end
|
372
|
+
|
373
|
+
it 'should raise an Appforce::Spawn::API::CallFailure exception' do
|
374
|
+
expect { Appforce::Spawn::Api::Call.send(:make_api_call, 'url') }.to raise_exception(Appforce::Spawn::API::CallFailure)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
2
|
+
|
3
|
+
RSpec.describe Appforce::Config do
|
4
|
+
before do
|
5
|
+
logger = Logger.new('/dev/null')
|
6
|
+
Appforce::Spawn.logger = logger
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'DEFAULT_CONFIG_PATH' do
|
10
|
+
it 'should have a default config path' do
|
11
|
+
expect(Appforce::Config::DEFAULT_CONFIG_PATH).to end_with '.appforce'
|
12
|
+
end
|
13
|
+
|
14
|
+
context '.load_config' do
|
15
|
+
it 'should load a config at a given path with method calls for keys in config' do
|
16
|
+
Appforce::Config.load_config(file_fixture_path('appforce_config.yml'))
|
17
|
+
@config = Appforce::Config.config
|
18
|
+
expect(@config.api_host).to eq 'http://afuka.synctree.com'
|
19
|
+
expect(@config.api_version).to eq 'VERSION_STRING'
|
20
|
+
expect(@config.api_token).to eq 'INVALID_TOKEN'
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should raise an excpetion with a malformed config file' do
|
24
|
+
expect { Appforce::Config.load_config(file_fixture_path('malformed_appforce_config.yml')) }.to raise_exception
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context '.dump_example_config' do
|
29
|
+
before do
|
30
|
+
allow(File).to receive(:expand_path).and_return("tmp")
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should write out a sample .appforce config file' do
|
34
|
+
Appforce::Config.dump_example_config
|
35
|
+
cfg = open_tmp_file('.appforce.example')
|
36
|
+
expect(cfg).to match /PUT_API_TOKEN_HERE/
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'errors while writing file' do
|
40
|
+
before do
|
41
|
+
allow(File).to receive(:open).and_raise(IOError)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should raise an IOError excpetion' do
|
45
|
+
expect { Appforce::Config.dump_example_config }.to raise_exception
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|