rundeck 0.0.3.pre → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -0
  3. data/.rubocop_todo.yml +0 -10
  4. data/.travis.yml +1 -1
  5. data/lib/rundeck/client.rb +61 -3
  6. data/lib/rundeck/client/execution.rb +194 -0
  7. data/lib/rundeck/client/{jobs.rb → job.rb} +19 -36
  8. data/lib/rundeck/client/{keys.rb → key.rb} +42 -20
  9. data/lib/rundeck/configuration.rb +5 -1
  10. data/lib/rundeck/objectified_hash.rb +13 -3
  11. data/lib/rundeck/request.rb +7 -1
  12. data/lib/rundeck/version.rb +1 -1
  13. data/rundeck.gemspec +2 -1
  14. data/spec/cassettes/12/abort_execution_not_running.yml +41 -0
  15. data/spec/cassettes/12/abort_execution_valid.yml +41 -0
  16. data/spec/cassettes/12/abort_executions_invalid.yml +41 -0
  17. data/spec/cassettes/12/bulk_delete_executions_invalid.yml +46 -0
  18. data/spec/cassettes/12/bulk_delete_executions_valid.yml +41 -0
  19. data/spec/cassettes/12/create_private_key.yml +64 -0
  20. data/spec/cassettes/12/create_public_key.yml +38 -0
  21. data/spec/cassettes/12/delete_execution_invalid.yml +41 -0
  22. data/spec/cassettes/12/delete_execution_valid.yml +32 -0
  23. data/spec/cassettes/12/delete_job_executions.yml +41 -0
  24. data/spec/cassettes/12/delete_job_executions_invalid.yml +41 -0
  25. data/spec/cassettes/12/delete_job_invalid.yml +41 -0
  26. data/spec/cassettes/12/delete_job_valid.yml +32 -0
  27. data/spec/cassettes/12/delete_key_invalid.yml +41 -0
  28. data/spec/cassettes/12/delete_key_private.yml +32 -0
  29. data/spec/cassettes/12/delete_key_public.yml +32 -0
  30. data/spec/cassettes/12/execution_invalid.yml +41 -0
  31. data/spec/cassettes/12/execution_query_invalid.yml +39 -0
  32. data/spec/cassettes/12/execution_query_no_params_valid.yml +124 -0
  33. data/spec/cassettes/12/execution_state_invalid.yml +41 -0
  34. data/spec/cassettes/12/execution_state_valid.yml +39 -0
  35. data/spec/cassettes/12/execution_valid.yml +60 -0
  36. data/spec/cassettes/12/export_job_xml.yml +234 -0
  37. data/spec/cassettes/12/export_job_yaml.yml +228 -0
  38. data/spec/cassettes/12/import_job_xml.yml +69 -0
  39. data/spec/cassettes/12/import_job_yaml.yml +63 -0
  40. data/spec/cassettes/12/job.yml +84 -0
  41. data/spec/cassettes/12/job_executions.yml +96 -0
  42. data/spec/cassettes/12/jobs.yml +76 -0
  43. data/spec/cassettes/12/key_contents_direct.yml +67 -0
  44. data/spec/cassettes/12/key_contents_multiple.yml +38 -0
  45. data/spec/cassettes/12/key_contents_private.yml +35 -0
  46. data/spec/cassettes/12/key_metadata_direct.yml +35 -0
  47. data/spec/cassettes/12/key_metadata_multiple.yml +38 -0
  48. data/spec/cassettes/12/keys_direct.yml +35 -0
  49. data/spec/cassettes/12/keys_multiple.yml +38 -0
  50. data/spec/cassettes/12/keys_none.yml +34 -0
  51. data/spec/cassettes/12/run_job_invalid.yml +44 -0
  52. data/spec/cassettes/12/run_job_valid.yml +77 -0
  53. data/spec/cassettes/12/running_jobs_multiple.yml +70 -0
  54. data/spec/cassettes/12/running_jobs_none.yml +39 -0
  55. data/spec/cassettes/12/running_jobs_single.yml +55 -0
  56. data/spec/cassettes/12/update_private_key.yml +96 -0
  57. data/spec/cassettes/12/update_public_key.yml +70 -0
  58. data/spec/rundeck/client/execution_spec.rb +346 -0
  59. data/spec/rundeck/client/job_spec.rb +175 -0
  60. data/spec/rundeck/client/key_spec.rb +223 -0
  61. data/spec/spec_helper.rb +15 -60
  62. data/spec/support/helpers.rb +136 -0
  63. metadata +118 -35
  64. data/spec/fixtures/empty.xml +0 -0
  65. data/spec/fixtures/job.xml +0 -17
  66. data/spec/fixtures/job_executions.xml +0 -31
  67. data/spec/fixtures/job_run.xml +0 -16
  68. data/spec/fixtures/jobs_import.xml +0 -23
  69. data/spec/fixtures/jobs_my_project.xml +0 -14
  70. data/spec/fixtures/jobs_xml.xml +0 -32
  71. data/spec/fixtures/jobs_yaml.xml +0 -22
  72. data/spec/fixtures/key_contents_public.xml +0 -1
  73. data/spec/fixtures/key_private.xml +0 -8
  74. data/spec/fixtures/key_public.xml +0 -7
  75. data/spec/fixtures/keys.xml +0 -27
  76. data/spec/rundeck/client/jobs_spec.rb +0 -181
  77. data/spec/rundeck/client/keys_spec.rb +0 -216
@@ -0,0 +1,175 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rundeck::Client do
4
+ describe '.jobs', vcr: { cassette_name: 'jobs' } do
5
+ before do
6
+ @jobs = Rundeck.jobs('anvils')
7
+ end
8
+ subject { @jobs }
9
+
10
+ it { is_expected.to be_an Array }
11
+ its(:length) { is_expected.to eq(6) }
12
+
13
+ # Only tests the first element, but it's just a sanity check
14
+ its('first') { is_expected.to respond_to(:name) }
15
+ its('first') { is_expected.to respond_to(:group) }
16
+ its('first') { is_expected.to respond_to(:project) }
17
+ its('first') { is_expected.to respond_to(:description) }
18
+
19
+ it 'expects a get to have been made' do
20
+ expect(a_get('/project/anvils/jobs')).to have_been_made
21
+ end
22
+ end
23
+
24
+ describe '.job', vcr: { cassette_name: 'job' } do
25
+ before do
26
+ @job = Rundeck.job('2')
27
+ end
28
+ subject { @job }
29
+
30
+ it { is_expected.to be_a Rundeck::ObjectifiedHash }
31
+ it { is_expected.to respond_to(:id) }
32
+ it { is_expected.to respond_to(:name) }
33
+ it { is_expected.to respond_to(:description) }
34
+ it { is_expected.to respond_to(:loglevel) }
35
+ it { is_expected.to respond_to(:sequence) }
36
+ its(:sequence) { is_expected.to respond_to(:command) }
37
+
38
+ it 'expects a get to have been made' do
39
+ expect(a_get('/job/2')).to have_been_made
40
+ end
41
+ end
42
+
43
+ describe '.delete_job' do
44
+ context 'when a job exists',
45
+ vcr: { cassette_name: 'delete_job_valid' } do
46
+ before do
47
+ @job = Rundeck.delete_job(job_id)
48
+ end
49
+ let(:job_id) { '3' }
50
+ subject { @job }
51
+
52
+ it { is_expected.to be_nil }
53
+
54
+ it 'expects a delete to have been made' do
55
+ expect(a_delete('/job/3')).to have_been_made
56
+ end
57
+ end
58
+
59
+ context 'when a job does not exist',
60
+ vcr: { cassette_name: 'delete_job_invalid' } do
61
+ specify do
62
+ expect do
63
+ Rundeck.delete_job('123456')
64
+ end.to raise_error(Rundeck::Error::NotFound,
65
+ /Job ID does not exist: 123456/)
66
+ end
67
+ end
68
+ end
69
+
70
+ describe '.import_job' do
71
+ context 'with valid format' do
72
+ before do
73
+ @import = Rundeck.import_jobs(content, format)
74
+ end
75
+ subject { @import }
76
+
77
+ context 'yaml', vcr: { cassette_name: 'import_job_yaml' } do
78
+ let(:format) { 'yaml' }
79
+ let(:content) { job_yaml }
80
+
81
+ it { is_expected.to be_a Rundeck::ObjectifiedHash }
82
+ its('succeeded.count') { is_expected.to eq('1') }
83
+ its('failed.count') { is_expected.to eq('0') }
84
+
85
+ its('succeeded') { is_expected.to respond_to(:job) }
86
+ its('succeeded.job') { is_expected.to respond_to(:id) }
87
+ its('succeeded.job') { is_expected.to respond_to(:name) }
88
+ its('succeeded.job') { is_expected.to respond_to(:group) }
89
+ its('succeeded.job') { is_expected.to respond_to(:project) }
90
+ its('succeeded.job') { is_expected.to respond_to(:url) }
91
+
92
+ it 'expects a post to have been made' do
93
+ expect(a_post('/jobs/import?format=yaml')).to have_been_made
94
+ end
95
+ end
96
+
97
+ context 'xml', vcr: { cassette_name: 'import_job_xml' } do
98
+ let(:format) { 'xml' }
99
+ let(:content) { job_xml }
100
+
101
+ it { is_expected.to be_a Rundeck::ObjectifiedHash }
102
+ its('succeeded.count') { is_expected.to eq('1') }
103
+ its('failed.count') { is_expected.to eq('0') }
104
+
105
+ its('succeeded') { is_expected.to respond_to(:job) }
106
+ its('succeeded.job') { is_expected.to respond_to(:id) }
107
+ its('succeeded.job') { is_expected.to respond_to(:name) }
108
+ its('succeeded.job') { is_expected.to respond_to(:group) }
109
+ its('succeeded.job') { is_expected.to respond_to(:project) }
110
+ its('succeeded.job') { is_expected.to respond_to(:url) }
111
+
112
+ it 'expects a post to have been made' do
113
+ expect(a_post('/jobs/import?format=xml')).to have_been_made
114
+ end
115
+ end
116
+ end
117
+
118
+ context 'with invalid format', vcr: { cassette_name: 'import_job_invalid' } do
119
+ specify do
120
+ expect do
121
+ Rundeck.import_jobs('content', 'invalid_format')
122
+ end.to raise_error(Rundeck::Error::InvalidAttributes,
123
+ 'format must be yaml or xml')
124
+ end
125
+ end
126
+ end
127
+
128
+ describe '.export_job' do
129
+ context 'with valid format' do
130
+ before do
131
+ @jobs = Rundeck.export_jobs('anvils', format)
132
+ end
133
+ subject { @jobs }
134
+
135
+ context 'yaml', vcr: { cassette_name: 'export_job_yaml' } do
136
+ let(:format) { 'yaml' }
137
+
138
+ it { is_expected.to be_a String }
139
+ it { is_expected.to include 'project: anvils' }
140
+ it { is_expected.to include 'loglevel: INFO' }
141
+ it { is_expected.to include 'sequence:' }
142
+
143
+ it 'expects a get to have been made' do
144
+ expect(
145
+ a_get('/jobs/export?project=anvils&format=yaml')
146
+ ).to have_been_made
147
+ end
148
+ end
149
+
150
+ context 'xml', vcr: { cassette_name: 'export_job_xml' } do
151
+ let(:format) { 'xml' }
152
+
153
+ it { is_expected.to be_a String }
154
+ it { is_expected.to include '<project>anvils</project>' }
155
+ it { is_expected.to include '<loglevel>INFO</loglevel>' }
156
+ it { is_expected.to include '<sequence' }
157
+
158
+ it 'expects a get to have been made' do
159
+ expect(
160
+ a_get('/jobs/export?project=anvils&format=xml')
161
+ ).to have_been_made
162
+ end
163
+ end
164
+ end
165
+
166
+ context 'with invalid format', vcr: { cassette_name: 'export_job_invalid' } do
167
+ specify do
168
+ expect do
169
+ Rundeck.export_jobs('anvils', 'invalid_format')
170
+ end.to raise_error(Rundeck::Error::InvalidAttributes,
171
+ 'format must be yaml or xml')
172
+ end
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,223 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rundeck::Client do
4
+ describe '.keys' do
5
+ # The anvils demo doesn't have any keys by default.
6
+ # Create a public key at path /path/to/key and a private key
7
+ # at /path/to/private_key using the data from the helper methods.
8
+ # Create the public key first.
9
+ context 'with a path containing multiple keys',
10
+ vcr: { cassette_name: 'keys_multiple' } do
11
+ before do
12
+ @keys = Rundeck.keys('path/to')
13
+ end
14
+ subject { @keys }
15
+
16
+ it { is_expected.to be_an Array }
17
+ its('first.name') { is_expected.to eq('key') }
18
+ its('first.resource_meta.rundeck_content_type') { is_expected.to eq('application/pgp-key') }
19
+
20
+ it 'expects a get to have been made' do
21
+ expect(a_get('/storage/keys/path/to')).to have_been_made
22
+ end
23
+ end
24
+
25
+ context 'with a path containing no keys',
26
+ vcr: { cassette_name: 'keys_none' } do
27
+ specify do
28
+ expect do
29
+ Rundeck.keys('path/to/nowhere')
30
+ end.to raise_error Rundeck::Error::NotFound
31
+ end
32
+ end
33
+
34
+ context 'with a direct path to a key',
35
+ vcr: { cassette_name: 'keys_direct' } do
36
+ specify do
37
+ expect do
38
+ Rundeck.keys('path/to/key')
39
+ end.to raise_error(Rundeck::Error::InvalidAttributes,
40
+ 'Please provide a key storage path that ' \
41
+ 'isn\'t a direct path to a key')
42
+ end
43
+ end
44
+ end
45
+
46
+ describe '.key_metadata' do
47
+ context 'with a direct path to a key',
48
+ vcr: { cassette_name: 'key_metadata_direct' } do
49
+ before do
50
+ @key = Rundeck.key_metadata('path/to/key')
51
+ end
52
+ subject { @key }
53
+
54
+ it { is_expected.to be_a Rundeck::ObjectifiedHash }
55
+ its(:rundeck_content_type) { is_expected.to eq('application/pgp-key') }
56
+
57
+ it 'expects a get to have been made' do
58
+ expect(a_get('/storage/keys/path/to/key')).to have_been_made
59
+ end
60
+ end
61
+
62
+ context 'with a path containing multiple keys',
63
+ vcr: { cassette_name: 'key_metadata_multiple' } do
64
+ specify do
65
+ expect do
66
+ Rundeck.key_metadata('path/to')
67
+ end.to raise_error(Rundeck::Error::InvalidAttributes,
68
+ 'Please provide a key storage path that ' \
69
+ 'is a direct path to a key')
70
+ end
71
+ end
72
+ end
73
+
74
+ describe '.key_contents' do
75
+ context 'with a direct path to a key',
76
+ vcr: { cassette_name: 'key_contents_direct' } do
77
+ before do
78
+ @key = Rundeck.key_contents('path/to/key')
79
+ end
80
+ subject { @key }
81
+
82
+ it { is_expected.to be_a Rundeck::ObjectifiedHash }
83
+ its(:public_key) { is_expected.to include('ssh-rsa') }
84
+
85
+ it 'expects a get to have been made' do
86
+ expect(a_get('/storage/keys/path/to/key')).to have_been_made
87
+ end
88
+ it 'expects a get to have been made' do
89
+ expect(a_get('/storage/keys/path/to/key', 'pgp-keys')).to have_been_made
90
+ end
91
+ end
92
+
93
+ context 'with a path containing multiple keys',
94
+ vcr: { cassette_name: 'key_contents_multiple' } do
95
+ specify do
96
+ expect do
97
+ Rundeck.key_contents('path/to')
98
+ end.to raise_error(Rundeck::Error::InvalidAttributes,
99
+ 'Please provide a key storage path that ' \
100
+ 'is a direct path to a key')
101
+ end
102
+ end
103
+
104
+ context 'with a path to a private key',
105
+ vcr: { cassette_name: 'key_contents_private' } do
106
+ specify do
107
+ expect do
108
+ Rundeck.key_contents('path/to/private_key')
109
+ end.to raise_error(Rundeck::Error::Unauthorized,
110
+ 'You are not allowed to retrieve the contents ' \
111
+ 'of a private key')
112
+ end
113
+ end
114
+ end
115
+
116
+ describe '.create_private_key',
117
+ vcr: { cassette_name: 'create_private_key' } do
118
+ before do
119
+ @key = Rundeck.create_private_key('path/to/private_key2', private_key)
120
+ end
121
+ subject { @key }
122
+
123
+ it { is_expected.to be_a Rundeck::ObjectifiedHash }
124
+ its(:rundeck_key_type) { is_expected.to eq('private') }
125
+
126
+ it 'expects a post to have been made' do
127
+ expect(
128
+ a_post('/storage/keys/path/to/private_key2')
129
+ ).to have_been_made
130
+ end
131
+ end
132
+
133
+ describe '.update_private_key',
134
+ vcr: { cassette_name: 'update_private_key' } do
135
+ before do
136
+ @key = Rundeck.update_private_key('path/to/private_key2', private_key)
137
+ end
138
+ subject { @key }
139
+
140
+ it { is_expected.to be_a Rundeck::ObjectifiedHash }
141
+ its(:rundeck_key_type) { is_expected.to eq('private') }
142
+
143
+ it 'expects a get to have been made' do
144
+ expect(a_get('/storage/keys/path/to/private_key2')).to have_been_made
145
+ end
146
+ it 'expects a put to have been made' do
147
+ expect(a_put('/storage/keys/path/to/private_key2')).to have_been_made
148
+ end
149
+ end
150
+
151
+ describe '.create_public_key',
152
+ vcr: { cassette_name: 'create_public_key' } do
153
+ before do
154
+ @key = Rundeck.create_public_key('path/to/public_key2', public_key)
155
+ end
156
+ subject { @key }
157
+
158
+ it { is_expected.to be_a Rundeck::ObjectifiedHash }
159
+ its(:rundeck_content_type) { is_expected.to eq('application/pgp-key') }
160
+
161
+ it 'expects a post to have been made' do
162
+ expect(
163
+ a_post('/storage/keys/path/to/public_key2')
164
+ ).to have_been_made
165
+ end
166
+ end
167
+
168
+ describe '.update_public_key',
169
+ vcr: { cassette_name: 'update_public_key' } do
170
+ before do
171
+ @key = Rundeck.update_public_key('path/to/public_key2', public_key)
172
+ end
173
+ subject { @key }
174
+
175
+ it { is_expected.to be_a Rundeck::ObjectifiedHash }
176
+ its(:rundeck_content_type) { is_expected.to eq('application/pgp-key') }
177
+
178
+ it 'expects a get to have been made' do
179
+ expect(a_get('/storage/keys/path/to/public_key2')).to have_been_made
180
+ end
181
+ it 'expects a put to have been made' do
182
+ expect(a_put('/storage/keys/path/to/public_key2')).to have_been_made
183
+ end
184
+ end
185
+
186
+ describe '.delete_key' do
187
+ context 'with a valid' do
188
+ before do
189
+ @key = Rundeck.delete_key(path)
190
+ end
191
+ subject { @key }
192
+
193
+ context 'public key path',
194
+ vcr: { cassette_name: 'delete_key_public' } do
195
+ let(:path) { 'path/to/public_key2' }
196
+
197
+ it { is_expected.to be_nil }
198
+ it 'expects a delete to have been made' do
199
+ expect(a_delete('/storage/keys/path/to/public_key2')).to have_been_made
200
+ end
201
+ end
202
+
203
+ context 'private key path',
204
+ vcr: { cassette_name: 'delete_key_private' } do
205
+ let(:path) { 'path/to/private_key2' }
206
+
207
+ it { is_expected.to be_nil }
208
+ it 'expects a delete to have been made' do
209
+ expect(a_delete('/storage/keys/path/to/private_key2')).to have_been_made
210
+ end
211
+ end
212
+ end
213
+
214
+ context 'with a bad path',
215
+ vcr: { cassette_name: 'delete_key_invalid' } do
216
+ specify do
217
+ expect do
218
+ Rundeck.delete_key('path/to/nowhere')
219
+ end.to raise_error Rundeck::Error::NotFound
220
+ end
221
+ end
222
+ end
223
+ end
@@ -1,77 +1,32 @@
1
1
  require 'rspec'
2
2
  require 'rspec/its'
3
3
  require 'webmock/rspec'
4
+ require 'vcr'
4
5
  require 'codeclimate-test-reporter'
5
6
 
7
+ # Must be called before code is included/required!
6
8
  CodeClimate::TestReporter.start
7
9
 
8
- WebMock.disable_net_connect!(allow: 'codeclimate.com')
10
+ require 'support/helpers'
9
11
 
10
12
  require File.expand_path('../../lib/rundeck', __FILE__)
11
13
 
12
- def load_fixture(name)
13
- File.new(File.dirname(__FILE__) + "/fixtures/#{name}.xml")
14
- end
14
+ WebMock.disable_net_connect!(allow: 'codeclimate.com')
15
15
 
16
16
  RSpec.configure do |config|
17
+ config.include Helpers
18
+
17
19
  config.before(:each) do
18
- Rundeck.endpoint = 'https://api.example.com'
19
- Rundeck.api_token = 'secret'
20
+ # Configuration for Anvils Demo Vagrant Box. API token might change.
21
+ Rundeck.endpoint = 'http://192.168.50.2:4440'
22
+ Rundeck.api_token = 'cmJQYoy9EAsSd0905yNjKDNGs0ESIwEd'
23
+ WebMock.reset!
20
24
  end
21
25
  end
22
26
 
23
- # GET
24
- def stub_get(path, fixture, accept = 'xml')
25
- stub_request(:get, "#{Rundeck.endpoint}#{path}")
26
- .with(headers: { 'Accept' => "application/#{accept}",
27
- 'X-Rundeck-Auth-Token' => Rundeck.api_token })
28
- .to_return(body: load_fixture(fixture))
29
- end
30
-
31
- def a_get(path, accept = 'xml')
32
- a_request(:get, "#{Rundeck.endpoint}#{path}")
33
- .with(headers: { 'Accept' => "application/#{accept}",
34
- 'X-Rundeck-Auth-Token' => Rundeck.api_token })
35
- end
36
-
37
- # POST
38
- def stub_post(path, fixture, status_code = 200, accept = 'xml')
39
- stub_request(:post, "#{Rundeck.endpoint}#{path}")
40
- .with(headers: { 'Accept' => "application/#{accept}",
41
- 'X-Rundeck-Auth-Token' => Rundeck.api_token })
42
- .to_return(body: load_fixture(fixture), status: status_code)
43
- end
44
-
45
- def a_post(path, accept = 'xml')
46
- a_request(:post, "#{Rundeck.endpoint}#{path}")
47
- .with(headers: { 'Accept' => "application/#{accept}",
48
- 'X-Rundeck-Auth-Token' => Rundeck.api_token })
49
- end
50
-
51
- # PUT
52
- def stub_put(path, fixture, accept = 'xml')
53
- stub_request(:put, "#{Rundeck.endpoint}#{path}")
54
- .with(headers: { 'Accept' => "application/#{accept}",
55
- 'X-Rundeck-Auth-Token' => Rundeck.api_token })
56
- .to_return(body: load_fixture(fixture))
57
- end
58
-
59
- def a_put(path, accept = 'xml')
60
- a_request(:put, "#{Rundeck.endpoint}#{path}")
61
- .with(headers: { 'Accept' => "application/#{accept}",
62
- 'X-Rundeck-Auth-Token' => Rundeck.api_token })
63
- end
64
-
65
- # DELETE
66
- def stub_delete(path, fixture, accept = 'xml')
67
- stub_request(:delete, "#{Rundeck.endpoint}#{path}")
68
- .with(headers: { 'Accept' => "application/#{accept}",
69
- 'X-Rundeck-Auth-Token' => Rundeck.api_token })
70
- .to_return(body: load_fixture(fixture))
71
- end
72
-
73
- def a_delete(path, accept = 'xml')
74
- a_request(:delete, "#{Rundeck.endpoint}#{path}")
75
- .with(headers: { 'Accept' => "application/#{accept}",
76
- 'X-Rundeck-Auth-Token' => Rundeck.api_token })
27
+ VCR.configure do |config|
28
+ config.cassette_library_dir = "spec/cassettes/#{Rundeck.api_version}"
29
+ config.hook_into :webmock
30
+ config.allow_http_connections_when_no_cassette = true
31
+ config.configure_rspec_metadata!
77
32
  end