do_snapshot 0.6.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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