do_snapshot 0.6.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -2
  3. data/bin/do_snapshot +1 -0
  4. data/lib/do_snapshot.rb +1 -0
  5. data/lib/do_snapshot/adapter.rb +10 -7
  6. data/lib/do_snapshot/adapter/abstract.rb +2 -1
  7. data/lib/do_snapshot/adapter/{digitalocean_v2.rb → droplet_kit.rb} +50 -33
  8. data/lib/do_snapshot/cli.rb +1 -0
  9. data/lib/do_snapshot/command.rb +1 -0
  10. data/lib/do_snapshot/configuration.rb +1 -0
  11. data/lib/do_snapshot/core_ext/hash.rb +1 -0
  12. data/lib/do_snapshot/distribution.rb +1 -0
  13. data/lib/do_snapshot/gem_ext/resource_kit.rb +30 -0
  14. data/lib/do_snapshot/helpers.rb +1 -0
  15. data/lib/do_snapshot/log.rb +1 -0
  16. data/lib/do_snapshot/mail.rb +1 -0
  17. data/lib/do_snapshot/rspec.rb +12 -0
  18. data/lib/do_snapshot/rspec/adapter.rb +265 -0
  19. data/lib/do_snapshot/rspec/api_helpers.rb +45 -0
  20. data/lib/do_snapshot/rspec/api_v2_helpers.rb +157 -0
  21. data/lib/do_snapshot/rspec/environment.rb +120 -0
  22. data/lib/do_snapshot/rspec/uri_helpers.rb +17 -0
  23. data/lib/do_snapshot/runner.rb +1 -0
  24. data/lib/do_snapshot/version.rb +2 -1
  25. data/spec/do_snapshot/adapter/abstract_spec.rb +2 -1
  26. data/spec/do_snapshot/adapter/droplet_kit_spec.rb +9 -0
  27. data/spec/do_snapshot/adapter_spec.rb +3 -2
  28. data/spec/do_snapshot/cli_spec.rb +4 -3
  29. data/spec/do_snapshot/command_spec.rb +4 -3
  30. data/spec/do_snapshot/configuration_spec.rb +1 -0
  31. data/spec/do_snapshot/log_spec.rb +2 -1
  32. data/spec/do_snapshot/mail_spec.rb +2 -1
  33. data/spec/do_snapshot/runner_spec.rb +3 -2
  34. data/spec/do_snapshot_spec.rb +2 -1
  35. data/spec/spec_helper.rb +2 -4
  36. data/spec/support/aruba.rb +1 -0
  37. data/spec/support/matchers.rb +1 -0
  38. metadata +47 -20
  39. data/spec/do_snapshot/adapter/digitalocean_v2_spec.rb +0 -264
  40. data/spec/shared/api_helpers.rb +0 -41
  41. data/spec/shared/api_v2_helpers.rb +0 -153
  42. data/spec/shared/environment.rb +0 -116
  43. data/spec/shared/uri_helpers.rb +0 -13
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+ module DoSnapshot
3
+ module RSpec
4
+ module ApiHelpers # rubocop:disable Style/Documentation
5
+ extend ::RSpec::Core::SharedContext
6
+
7
+ # Stub helpers
8
+ #
9
+ def stub_with_id(request, id, fixture, status = 200)
10
+ return unless request && fixture && id
11
+ stub_request(:get, url_with_id(request, id))
12
+ .to_return(status: status, body: fixture(fixture))
13
+ end
14
+
15
+ def stub_without_id(request, fixture, status = 200)
16
+ return unless request && fixture
17
+ stub_request(:get, request)
18
+ .to_return(status: status, body: fixture(fixture))
19
+ end
20
+
21
+ def stub_with_id_name(request, id, name, fixture, status = 200)
22
+ return unless request && fixture && id && name
23
+ stub_request(:get, url_with_id_name(request, id, name))
24
+ .to_return(status: status, body: fixture(fixture))
25
+ end
26
+
27
+ # Url helpers
28
+ #
29
+ def url_with_id(request, id)
30
+ return unless request && id
31
+ request.sub('[id]', id.to_s)
32
+ end
33
+
34
+ def url_with_event_id(request, droplet_id, id)
35
+ return unless request && id && droplet_id
36
+ request.sub('[id]', id.to_s).sub('[droplet_id]', droplet_id.to_s)
37
+ end
38
+
39
+ def url_with_id_name(request, id, name)
40
+ return unless request && id && name
41
+ request.sub('[id]', id.to_s).sub('[name]', name)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+ module DoSnapshot
3
+ module RSpec
4
+ module ApiV2Helpers # rubocop:disable Style/Documentation,Metrics/ModuleLength
5
+ extend ::RSpec::Core::SharedContext
6
+
7
+ let(:api_base) { 'https://api.digitalocean.com/v2' }
8
+ let(:droplets_api_base) { "#{api_base}/droplets" }
9
+ let(:api_access_token) { "Bearer #{access_token}" }
10
+ let(:events_api_base) { "#{api_base}/droplets/[droplet_id]/actions" }
11
+ let(:actions_api_base) { "#{api_base}/actions" }
12
+ let(:images_api_base) { "#{api_base}/images" }
13
+ let(:image_destroy_uri) { "#{images_api_base}/[id]" }
14
+ let(:droplets_uri) { "#{droplets_api_base}?page=1&per_page=1000" }
15
+ let(:droplet_find_uri) { "#{droplets_api_base}/[id]" }
16
+ let(:droplet_stop_uri) { "#{droplets_api_base}/[id]/actions" }
17
+ let(:droplet_start_uri) { "#{droplets_api_base}/[id]/actions" }
18
+ let(:snapshot_uri) { "#{droplets_api_base}/[id]/actions" }
19
+ let(:event_find_uri) { "#{events_api_base}/[id]" }
20
+ let(:action_find_uri) { "#{actions_api_base}/[id]" }
21
+
22
+ # List of droplets
23
+ #
24
+ def stub_droplets
25
+ stub_without_id(droplets_uri, 'v2/show_droplets')
26
+ end
27
+
28
+ def stub_droplets_empty
29
+ stub_without_id(droplets_uri, 'v2/show_droplets_empty')
30
+ end
31
+
32
+ def stub_droplets_fail
33
+ stub_without_id(droplets_uri, 'v2/error_message')
34
+ end
35
+
36
+ # Droplet data
37
+ #
38
+ def stub_droplet(id)
39
+ stub_with_id(droplet_find_uri, id, 'v2/show_droplet')
40
+ end
41
+
42
+ def stub_droplet_fail(id)
43
+ stub_with_id(droplet_find_uri, id, 'v2/error_message')
44
+ end
45
+
46
+ def stub_droplet_inactive(id)
47
+ stub_with_id(droplet_find_uri, id, 'v2/show_droplet_inactive')
48
+ end
49
+
50
+ # Droplet actions
51
+ #
52
+ def stub_droplet_stop(id)
53
+ stub_with_id(droplet_stop_uri, id, 'v2/show_event_power_off_start', :post,
54
+ type: 'power_off'
55
+ )
56
+ end
57
+
58
+ def stub_droplet_stop_fail(id)
59
+ stub_with_id(droplet_stop_uri, id, 'v2/error_message', :post,
60
+ {
61
+ type: 'power_off'
62
+ },
63
+ 404
64
+ )
65
+ end
66
+
67
+ def stub_droplet_start(id)
68
+ stub_with_id(droplet_start_uri, id, 'v2/show_event_power_on_start', :post,
69
+ type: 'power_on'
70
+ )
71
+ end
72
+
73
+ def stub_droplet_start_done(id)
74
+ stub_with_id(droplet_start_uri, id, 'v2/show_event_power_on_done', :post,
75
+ type: 'power_on'
76
+ )
77
+ end
78
+
79
+ def stub_droplet_start_fail(id)
80
+ stub_with_id(droplet_start_uri, id, 'v2/error_message', :post,
81
+ type: 'power_on'
82
+ )
83
+ end
84
+
85
+ # Snapshot
86
+ #
87
+ def stub_droplet_snapshot(id, name)
88
+ stub_with_id_name(snapshot_uri, id, name, 'v2/response_event', :post,
89
+ type: 'snapshot',
90
+ name: name
91
+ )
92
+ end
93
+
94
+ def stub_droplet_snapshot_fail(id, name)
95
+ stub_with_id_name(snapshot_uri, id, name, 'v2/error_message', :post,
96
+ {
97
+ type: 'snapshot',
98
+ name: name
99
+ },
100
+ 404
101
+ )
102
+ end
103
+
104
+ # Event status
105
+ #
106
+ def stub_event_done(id)
107
+ stub_with_id(action_find_uri, id, 'v2/show_event_done')
108
+ end
109
+
110
+ def stub_event_fail(id)
111
+ stub_with_id(action_find_uri, id, 'v2/error_message')
112
+ end
113
+
114
+ def stub_event_running(id)
115
+ stub_with_id(action_find_uri, id, 'v2/show_event_start')
116
+ end
117
+
118
+ # Image actions
119
+ #
120
+ def stub_image_destroy(id)
121
+ stub_with_id(image_destroy_uri, id, 'v2/empty', :delete, nil, 204)
122
+ end
123
+
124
+ def stub_image_destroy_fail(id)
125
+ stub_with_id(image_destroy_uri, id, 'v2/error_message', :delete, nil, 404)
126
+ end
127
+
128
+ # Stub helpers
129
+ #
130
+ def stub_with_id(request, id, fixture, type = :get, body = nil, status = 200) # rubocop:disable Metrics/ParameterLists
131
+ return unless request && fixture && id
132
+ stub_request_body(type, url_with_id(request, id), body)
133
+ .to_return(status: status, body: fixture(fixture))
134
+ end
135
+
136
+ def stub_without_id(request, fixture, type = :get, body = nil, status = 200)
137
+ return unless request && fixture
138
+ stub_request_body(type, request, body)
139
+ .to_return(status: status, body: fixture(fixture))
140
+ end
141
+
142
+ def stub_with_id_name(request, id, name, fixture, type = :get, body = nil, status = 200) # rubocop:disable Metrics/ParameterLists
143
+ return unless request && fixture && id && name
144
+ stub_request_body(type, url_with_id_name(request, id, name), body)
145
+ .to_return(status: status, body: fixture(fixture))
146
+ end
147
+
148
+ # Body Helpers
149
+ #
150
+ def stub_request_body(type, request, body)
151
+ stub_response = stub_request(type, request).with(headers: { 'Authorization' => api_access_token })
152
+ return stub_response.with(body: body) if body
153
+ stub_response
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+ module DoSnapshot
3
+ module RSpec
4
+ module Environment # rubocop:disable Style/Documentation
5
+ extend ::RSpec::Core::SharedContext
6
+
7
+ include ApiHelpers
8
+
9
+ def do_not_send_email
10
+ allow(Pony).to receive(:deliver) { |mail| mail }
11
+ end
12
+
13
+ let(:client_key) { 'foo' }
14
+ let(:api_key) { 'bar' }
15
+ let(:access_token) { 'sometoken' }
16
+ let(:event_id) { '7499' }
17
+ let(:droplet_id) { '100823' }
18
+ let(:image_id) { '5019770' }
19
+ let(:image_id2) { '5019903' }
20
+ let(:cli_env_nil) { Hash['DIGITAL_OCEAN_CLIENT_ID' => nil, 'DIGITAL_OCEAN_API_KEY' => nil, 'DIGITAL_OCEAN_ACCESS_TOKEN' => nil] }
21
+ let(:cli_keys) { Thor::CoreExt::HashWithIndifferentAccess.new(digital_ocean_access_token: access_token) }
22
+ let(:cli_keys_other) { Thor::CoreExt::HashWithIndifferentAccess.new(digital_ocean_access_token: 'NOTTOK') }
23
+ let(:snapshot_name) { "example.com_#{DateTime.now.strftime('%Y_%m_%d')}" }
24
+ let(:default_options) { Hash[protocol: 2, only: %w( 100823 ), exclude: %w(), keep: 3, stop: false, trace: true, clean: true, delay: 0, shutdown: true, timeout: 600] }
25
+ let(:default_options_cli) { default_options.reject { |key, _| %w( droplets threads ).include?(key.to_s) } }
26
+ let(:no_exclude) { [] }
27
+ let(:exclude) { %w( 100824 100825 ) }
28
+ let(:no_only) { [] }
29
+ let(:only) { %w( 100823 100824 ) }
30
+ let(:stop) { true }
31
+ let(:no_stop) { false }
32
+ let(:quiet) { true }
33
+ let(:no_quiet) { false }
34
+ let(:clean) { true }
35
+ let(:no_clean) { false }
36
+ let(:shutdown) { true }
37
+ let(:timeout) { 600 }
38
+ let(:delay) { 0 }
39
+ let(:log_path) { "#{project_path}/log/test.log" }
40
+ let(:mail_options) { Thor::CoreExt::HashWithIndifferentAccess.new(to: 'mail@somehost.com', from: 'from@host.com') }
41
+ let(:smtp_options) { Thor::CoreExt::HashWithIndifferentAccess.new(address: 'smtp.gmail.com', port: '25', user_name: 'someuser', password: 'somepassword') }
42
+ let(:log) { Thor::CoreExt::HashWithIndifferentAccess.new(log: log_path) }
43
+
44
+ def stub_all_api(droplets = nil, active = false)
45
+ drops = []
46
+ droplets ||= [droplet_id]
47
+ droplets.each do |droplet|
48
+ drops.push Hash[
49
+ stub_droplet: (active ? stub_droplet(droplet) : stub_droplet_inactive(droplet))
50
+ ].merge(stub_droplet_api(droplet))
51
+ end
52
+ stubs = Hash[drops: drops]
53
+ @stubs = stubs.merge(default_stub_api)
54
+ end
55
+
56
+ def stub_droplet_api(droplet)
57
+ {
58
+ stub_droplet_stop: stub_droplet_stop(droplet),
59
+ stub_droplet_start: stub_droplet_start(droplet),
60
+ stub_droplet_snapshot: stub_droplet_snapshot(droplet, snapshot_name)
61
+ }
62
+ end
63
+
64
+ def default_stub_api
65
+ {
66
+ stub_event_done: stub_event_done(event_id),
67
+ stub_droplets: stub_droplets,
68
+ stub_image_destroy1: stub_image_destroy(image_id),
69
+ stub_image_destroy2: stub_image_destroy(image_id2)
70
+ }
71
+ end
72
+
73
+ def stub_cleanup
74
+ @stubs ||= {}
75
+ @stubs.each_pair do |_k, v|
76
+ remove_request_stub(v) if v.class == WebMock::RequestStub
77
+ next unless v.class == Array
78
+
79
+ v.each do |d|
80
+ d.each_pair do |_dk, dv|
81
+ remove_request_stub(dv) if v.class == WebMock::RequestStub
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ def reset_api_keys
88
+ ENV['DIGITAL_OCEAN_API_KEY'] = nil
89
+ ENV['DIGITAL_OCEAN_CLIENT_ID'] = nil
90
+ ENV['DIGITAL_OCEAN_ACCESS_TOKEN'] = nil
91
+ end
92
+
93
+ def set_api_keys
94
+ ENV['DIGITAL_OCEAN_API_KEY'] = api_key
95
+ ENV['DIGITAL_OCEAN_CLIENT_ID'] = client_key
96
+ ENV['DIGITAL_OCEAN_ACCESS_TOKEN'] = access_token
97
+ end
98
+
99
+ def reset_singletons
100
+ DoSnapshot.configure do |config|
101
+ # config.logger = Logger.new($stdout)
102
+ config.verbose = false
103
+ config.quiet = true
104
+ end
105
+ DoSnapshot.logger = DoSnapshot::Log.new
106
+ DoSnapshot.mailer = DoSnapshot.config.mailer
107
+ end
108
+
109
+ before(:all) do
110
+ WebMock.reset!
111
+ end
112
+
113
+ before(:each) do
114
+ do_not_send_email
115
+ set_api_keys
116
+ reset_singletons
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ module DoSnapshot
3
+ module RSpec
4
+ module UriHelpers # rubocop:disable Style/Documentation
5
+ extend ::RSpec::Core::SharedContext
6
+
7
+ let(:droplet_url) { url_with_id(droplet_find_uri, droplet_id) }
8
+ let(:droplet_stop_url) { url_with_id(droplet_stop_uri, droplet_id) }
9
+ let(:droplet_start_url) { url_with_id(droplet_start_uri, droplet_id) }
10
+ let(:event_find_url) { url_with_id(event_find_uri, event_id) }
11
+ let(:image_destroy_url) { url_with_id(image_destroy_uri, image_id) }
12
+ let(:image_destroy2_url) { url_with_id(image_destroy_uri, image_id2) }
13
+ let(:action_find_url) { url_with_id(action_find_uri, event_id) }
14
+ let(:droplet_snapshot_url) { url_with_id_name(snapshot_uri, droplet_id, snapshot_name) }
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'do_snapshot/cli'
2
3
 
3
4
  module DoSnapshot
@@ -1,6 +1,7 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  # Current version
3
4
  #
4
5
  module DoSnapshot
5
- VERSION = '0.6.4'
6
+ VERSION = '1.0.0'
6
7
  end
@@ -1,8 +1,9 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require 'spec_helper'
3
4
 
4
5
  RSpec.describe DoSnapshot::Adapter::Abstract do
5
- include_context 'environment'
6
+ include DoSnapshot::RSpec::Environment
6
7
 
7
8
  subject(:api) { described_class }
8
9
 
@@ -0,0 +1,9 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe DoSnapshot::Adapter::DropletKit do
6
+ include DoSnapshot::RSpec::Environment
7
+ include DoSnapshot::RSpec::ApiV2Helpers
8
+ include DoSnapshot::RSpec::Adapter
9
+ end
@@ -1,8 +1,9 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require 'spec_helper'
3
4
 
4
5
  RSpec.describe DoSnapshot::Adapter do
5
- include_context 'environment'
6
+ include DoSnapshot::RSpec::Environment
6
7
 
7
8
  module DoSnapshot
8
9
  module Adapter
@@ -17,7 +18,7 @@ RSpec.describe DoSnapshot::Adapter do
17
18
  describe '#api' do
18
19
  it 'when adapter' do
19
20
  api = adapter.api(2)
20
- expect(api).to be_a_kind_of(DoSnapshot::Adapter::DigitaloceanV2)
21
+ expect(api).to be_a_kind_of(DoSnapshot::Adapter::DropletKit)
21
22
  end
22
23
 
23
24
  it 'when custom adapter' do
@@ -1,12 +1,13 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require 'spec_helper'
3
4
 
4
5
  RSpec.describe DoSnapshot::CLI do
5
- include_context 'environment'
6
- include_context 'api_v2_helpers'
6
+ include DoSnapshot::RSpec::Environment
7
+ include DoSnapshot::RSpec::ApiV2Helpers
7
8
 
8
9
  subject(:cli) { described_class }
9
- subject(:api) { DoSnapshot::Adapter::DigitaloceanV2 }
10
+ subject(:api) { DoSnapshot::Adapter::DropletKit }
10
11
 
11
12
  describe '.initialize' do
12
13
  it 'with args & options' do
@@ -1,15 +1,16 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require 'spec_helper'
3
4
 
4
5
  RSpec.describe DoSnapshot::Command do
5
- include_context 'environment'
6
- include_context 'uri_helpers'
6
+ include DoSnapshot::RSpec::Environment
7
+ include DoSnapshot::RSpec::UriHelpers
7
8
 
8
9
  subject(:cmd) { DoSnapshot::Command.new }
9
10
  subject(:log) { DoSnapshot::Log }
10
11
 
11
12
  describe 'V2' do
12
- include_context 'api_v2_helpers'
13
+ include DoSnapshot::RSpec::ApiV2Helpers
13
14
 
14
15
  describe '.snap' do
15
16
  context 'when success' do
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'spec_helper'
2
3
 
3
4
  RSpec.describe DoSnapshot::Configuration do