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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 95c8aa6d9470c9eae1cc0f27b822e15b17d2bb61
4
- data.tar.gz: 90ace05ddc9bf40be16447f3880390a9168eb072
3
+ metadata.gz: eb7ae5cc912690b2cd5850c46fd364ced760b5dd
4
+ data.tar.gz: a1664c690b7940bc93f6ae58904ff111af531551
5
5
  SHA512:
6
- metadata.gz: b460b5736c090dd0345989d134068442d1589759e05f118e8e30b9a910d4e5acc80987640ae27f642ff536d872ae088c02383ad690b739dd9407ca6bec32246d
7
- data.tar.gz: d1a35778507e3d9379df0678aa78186ca3a079507c163e7ac8a752a5e39ec2f744eba576a34b9db27a41bae25074de4211cf59875f8dead74cadfd3d582e86e7
6
+ metadata.gz: b2554982045d10d24c5d054ae03dd51cd7745412d64eb5da06dca91d0b3b46e5391ef71725ff3f8407ac86c9a4564963e362e6f2f8c3819db0fde574dcd0fe26
7
+ data.tar.gz: eb9d432913d910285373520713a695ac5572303517de158a13921f5d8bad1739c8bcc0b505d7a349c1b58454350c4ede9992c04052115fdbcece902353dc4c1f
data/README.md CHANGED
@@ -13,6 +13,7 @@
13
13
  Use this tool to backup DigitalOcean droplet's via snapshot method, on the fly!
14
14
 
15
15
  ## API Changes:
16
+ - 20.08.17: Change `Barge` to `DropletKit`. Release `1.0.0`.
16
17
  - 03.08.16: DO now automagically keeps our droplets running when snapshot is processing, so:
17
18
  Added options `--shutdown`, `--no-shutdown`.
18
19
  `shutdown` now disabled by default, no downtime anymore, `YES`!
@@ -36,7 +37,13 @@ Here are some features:
36
37
 
37
38
  ## Compatibility
38
39
 
39
- Ruby versions 1.9.3 and higher. JRuby 1.7, 9.0.0.0 or later is also supported.
40
+ From `1.0.0`:
41
+ - Ruby version 2.0.0 or higher
42
+ - JRuby 9.1.0.0 or higher
43
+
44
+ Prior to `0.6.4`:
45
+ - Ruby version 1.9.3 or higher
46
+ - JRuby 1.7, 9.0.0.0 or higher
40
47
 
41
48
  <img src="https://raw.githubusercontent.com/merqlove/do_snapshot/master/assets/example.png" style="max-width:100%" alt="DoSnaphot example">
42
49
 
@@ -195,7 +202,7 @@ Support this project and others by [merqlove](https://gratipay.com/~merqlove/) v
195
202
  ## Dependencies:
196
203
 
197
204
  - [Thor](https://github.com/erikhuda/thor) for CLI.
198
- - [Barge](https://github.com/blom/barge) for API V2 requests.
205
+ - [DropletKit](https://github.com/digitalocean/droplet_kit) for API V2 requests.
199
206
  - [Pony](https://github.com/benprew/pony) for mail notifications.
200
207
 
201
208
  ## Contributing
data/bin/do_snapshot CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # -*- encoding : utf-8 -*-
3
+ # frozen_string_literal: true
3
4
 
4
5
  Signal.trap('INT') { exit 1 }
5
6
 
data/lib/do_snapshot.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require_relative 'do_snapshot/version'
3
4
  require_relative 'do_snapshot/configuration'
4
5
 
@@ -1,29 +1,32 @@
1
+ # frozen_string_literal: true
1
2
  module DoSnapshot
2
3
  # Adapter interface for API connections
3
4
  # Ability to select DigitalOcean API versions.
4
5
  #
5
6
  module Adapter
6
7
  autoload :Abstract, 'do_snapshot/adapter/abstract'
7
- autoload :DigitaloceanV2, 'do_snapshot/adapter/digitalocean_v2'
8
+ autoload :DropletKit, 'do_snapshot/adapter/droplet_kit'
8
9
 
9
10
  class << self
10
11
  def api(protocol, options = {})
11
12
  konst = find_protocol(protocol)
12
- fail DoSnapshot::NoProtocolError, "Not existing protocol: #{protocol}." unless
13
- DoSnapshot::Adapter.const_defined?(konst)
13
+ error_protocol(protocol) unless DoSnapshot::Adapter.const_defined?(konst)
14
14
  obj = DoSnapshot::Adapter.const_get(konst)
15
15
  obj.new(options)
16
16
  end
17
17
 
18
18
  private
19
19
 
20
+ def error_protocol(protocol)
21
+ fail DoSnapshot::NoProtocolError, "Not existing protocol: #{protocol}."
22
+ end
23
+
20
24
  def find_protocol(protocol)
21
- if protocol.is_a?(Integer)
22
- "DigitaloceanV#{protocol}"
23
- elsif protocol.is_a?(String)
25
+ if protocol.is_a?(String)
24
26
  protocol
25
27
  else
26
- 'DigitaloceanV2'
28
+ error_protocol(protocol) if protocol.is_a?(Integer) && protocol < 2
29
+ 'DropletKit'
27
30
  end
28
31
  end
29
32
  end
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
 
3
4
  module DoSnapshot
4
5
  module Adapter
@@ -25,7 +26,7 @@ module DoSnapshot
25
26
  # noinspection RubyResolve
26
27
  instance = droplet(id)
27
28
 
28
- return power_on(id) unless instance.status.include?('active')
29
+ return power_on(id) if instance.respond_to?(:status) && !instance.status.include?('active')
29
30
 
30
31
  logger.error "Droplet #{id} is still running. Skipping."
31
32
  end
@@ -1,73 +1,86 @@
1
1
  # -*- encoding : utf-8 -*-
2
- require 'barge' unless defined?(::Barge)
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../gem_ext/resource_kit'
5
+ require 'droplet_kit' unless defined?(::DropletKit)
3
6
 
4
7
  module DoSnapshot
5
8
  module Adapter
6
9
  # API for CLI commands
7
10
  # Operating with Digital Ocean.
8
11
  #
9
- class DigitaloceanV2 < Abstract
10
- attr_reader :client
12
+ class DropletKit < Abstract
13
+ attr_reader :client, :per_page, :page
14
+
15
+ def initialize(*args)
16
+ @per_page = 1000
17
+ @page = 1
18
+ super(*args)
19
+ end
11
20
 
12
21
  # Get single droplet from DigitalOcean
13
22
  #
14
23
  def droplet(id)
15
24
  # noinspection RubyResolve
16
- response = client.droplet.show(id)
17
- fail DropletFindError.new(id), response.message unless response.respond_to?(:droplet)
18
- response.droplet
25
+ result = client.droplets.find(id: id)
26
+ fail DropletFindError, id unless result
27
+ result
28
+ rescue ::DropletKit::Error => e
29
+ raise DropletFindError, id unless e.message
19
30
  end
20
31
 
21
32
  # Get droplets list from DigitalOcean
22
33
  #
23
34
  def droplets
24
35
  # noinspection RubyResolve
25
- response = client.droplet.all
26
- fail DropletListError, response.message unless response.respond_to?(:droplets)
27
- response.droplets
36
+ response = client.droplets.all(page: page, per_page: per_page)
37
+ response.many?
38
+ response
39
+ rescue ::NoMethodError => e
40
+ fail DropletListError, e
28
41
  end
29
42
 
30
43
  def snapshots(instance)
31
- instance.snapshot_ids
44
+ instance.snapshot_ids if instance.respond_to?(:snapshot_ids)
32
45
  end
33
46
 
34
47
  # Request Power On for droplet
35
48
  #
36
49
  def power_on(id)
37
50
  # noinspection RubyResolve
38
- response = client.droplet.power_on(id)
51
+ response = client.droplet_actions.power_on(droplet_id: id)
39
52
 
40
- fail DoSnapshot::EventError.new(id), response.message unless response.respond_to?(:action)
41
-
42
- if response.action.status.include?('in-progress')
53
+ if response.status.include?('in-progress')
43
54
  logger.info "Droplet id: #{id} is requested for Power On."
44
55
  else
45
56
  logger.error "Droplet id: #{id} is failed to request for Power On."
46
57
  end
58
+ rescue ::DropletKit::Error => e
59
+ fail DoSnapshot::EventError.new(id), e.message
47
60
  end
48
61
 
49
62
  # Power Off request for Droplet
50
63
  #
51
64
  def stop_droplet(id)
52
65
  # noinspection RubyResolve,RubyResolve
53
- response = client.droplet.power_off(id)
54
-
55
- fail DropletShutdownError.new(id), response.message unless response.respond_to?(:action)
66
+ response = client.droplet_actions.power_off(droplet_id: id)
56
67
 
57
68
  # noinspection RubyResolve
58
- wait_shutdown(id, response.action.id)
69
+ wait_shutdown(id, response.id)
70
+ rescue ::DropletKit::Error => e
71
+ fail DropletShutdownError.new(id), e.message
59
72
  end
60
73
 
61
74
  # Sending event to create snapshot via DigitalOcean API and wait for success
62
75
  #
63
76
  def create_snapshot(id, name)
64
77
  # noinspection RubyResolve,RubyResolve
65
- response = client.droplet.snapshot(id, name: name)
66
-
67
- fail DoSnapshot::SnapshotCreateError.new(id), response.message unless response.respond_to?(:action)
78
+ response = client.droplet_actions.snapshot(droplet_id: id, name: name)
68
79
 
69
80
  # noinspection RubyResolve
70
- wait_event(response.action.id)
81
+ wait_event(response.id)
82
+ rescue ::DropletKit::Error => e
83
+ fail DoSnapshot::SnapshotCreateError.new(id), e.message
71
84
  end
72
85
 
73
86
  # Checking if droplet is powered off.
@@ -75,7 +88,7 @@ module DoSnapshot
75
88
  def inactive?(id)
76
89
  instance = droplet(id)
77
90
 
78
- instance.status.include?('off')
91
+ instance.status.include?('off') if instance.respond_to?(:status)
79
92
  end
80
93
 
81
94
  # Cleanup our snapshots.
@@ -83,12 +96,8 @@ module DoSnapshot
83
96
  def cleanup_snapshots(instance, size)
84
97
  (0..size).each do |i|
85
98
  # noinspection RubyResolve
86
- snapshot = instance.snapshot_ids[i]
87
- action = client.image.destroy(snapshot)
88
-
89
- logger.debug action unless action.success?
90
-
91
- after_cleanup(instance.id, instance.name, snapshot, action)
99
+ snapshot = snapshots(instance)[i]
100
+ delete_image(instance, snapshot)
92
101
  end
93
102
  end
94
103
 
@@ -103,13 +112,21 @@ module DoSnapshot
103
112
  #
104
113
  def set_id
105
114
  logger.debug 'Setting DigitalOcean Access Token.'
106
- @client = ::Barge::Client.new(access_token: ENV['DIGITAL_OCEAN_ACCESS_TOKEN'], timeout: 15, open_timeout: 15)
115
+ @client = ::DropletKit::Client.new(access_token: ENV['DIGITAL_OCEAN_ACCESS_TOKEN'])
107
116
  end
108
117
 
109
118
  protected
110
119
 
120
+ def delete_image(instance, snapshot) # rubocop:disable Metrics/AbcSize
121
+ action = client.images.delete(id: snapshot)
122
+ after_cleanup(instance.id, instance.name, snapshot, action)
123
+ rescue ::DropletKit::Error => e
124
+ logger.debug "#{snapshot} #{e.message}"
125
+ after_cleanup(instance.id, instance.name, snapshot, false)
126
+ end
127
+
111
128
  def after_cleanup(droplet_id, droplet_name, snapshot, action)
112
- if !action.success?
129
+ if !action
113
130
  logger.error "Destroy of snapshot #{snapshot} for droplet id: #{droplet_id} name: #{droplet_name} is failed."
114
131
  else
115
132
  logger.debug "Snapshot: #{snapshot} delete requested."
@@ -121,9 +138,9 @@ module DoSnapshot
121
138
  def get_event_status(id, time)
122
139
  return true if timeout?(id, time)
123
140
 
124
- response = client.action.show(id)
141
+ response = client.actions.find(id: id)
125
142
 
126
- fail DoSnapshot::EventError.new(id), response.message unless response.respond_to?(:action)
143
+ fail DoSnapshot::EventError.new(id), response.message unless response.respond_to?(:status)
127
144
 
128
145
  # noinspection RubyResolve,RubyResolve
129
146
  response.action.status.include?('completed') ? true : false
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require 'thor'
3
4
  require 'do_snapshot'
4
5
  require_relative 'log'
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require_relative 'adapter'
3
4
 
4
5
  module DoSnapshot
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module DoSnapshot
2
3
  # Configuration class. Used to share config across application.
3
4
  #
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  # Rails symbolize keys methods for Hash
3
4
  #
4
5
  class Hash
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  module DoSnapshot
3
4
  # Distributive files
4
5
  # Used part of Heroku script https://github.com/heroku/heroku
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ require 'resource_kit'
3
+
4
+ # TODO: Remove after `resource_kit` gem update.
5
+ ResourceKit::Action.class_eval do
6
+ def handler(*response_codes, &block)
7
+ if response_codes.empty?
8
+ handlers[:any] = block
9
+ else
10
+ response_codes.each do |code|
11
+ code = ResourceKit::StatusCodeMapper.code_for(code) unless code.is_a?(Integer)
12
+ handlers[code] = block
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ # TODO: Remove after `resource_kit` gem update.
19
+ ResourceKit::ResourceCollection.class_eval do
20
+ def default_handler(*response_codes, &block)
21
+ if response_codes.empty?
22
+ default_handlers[:any] = block
23
+ else
24
+ response_codes.each do |code|
25
+ code = ResourceKit::StatusCodeMapper.code_for(code) unless code.is_a?(Integer)
26
+ default_handlers[code] = block
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_relative 'log'
2
3
  require_relative 'mail'
3
4
 
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require 'logger'
3
4
  require 'hashie'
4
5
 
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require 'date'
3
4
  require 'pony'
4
5
  require_relative 'core_ext/hash'
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ require 'rspec/core/shared_context'
3
+
4
+ module DoSnapshot
5
+ module RSpec # rubocop:disable Style/Documentation
6
+ autoload :Adapter, 'do_snapshot/rspec/adapter'
7
+ autoload :ApiHelpers, 'do_snapshot/rspec/api_helpers'
8
+ autoload :ApiV2Helpers, 'do_snapshot/rspec/api_v2_helpers'
9
+ autoload :Environment, 'do_snapshot/rspec/environment'
10
+ autoload :UriHelpers, 'do_snapshot/rspec/uri_helpers'
11
+ end
12
+ end
@@ -0,0 +1,265 @@
1
+ # frozen_string_literal: true
2
+ module DoSnapshot
3
+ module RSpec
4
+ module Adapter # rubocop:disable Style/Documentation,Metrics/ModuleLength
5
+ extend ::RSpec::Core::SharedContext
6
+
7
+ subject(:api) { described_class }
8
+ subject(:log) { DoSnapshot::Log }
9
+
10
+ describe '.initialize' do
11
+ describe '#delay' do
12
+ let(:delay) { 5 }
13
+ let(:instance) { api.new(delay: delay) }
14
+ it('with custom delay') { expect(instance.delay).to eq delay }
15
+ end
16
+
17
+ describe '#timeout' do
18
+ let(:timeout) { 5 }
19
+ let(:instance) { api.new(timeout: timeout) }
20
+ it('with custom timeout') { expect(instance.timeout).to eq timeout }
21
+ end
22
+ end
23
+
24
+ describe 'droplets' do
25
+ let(:instance) { api.new(delay: delay, timeout: timeout) }
26
+ include UriHelpers
27
+
28
+ describe '.droplet' do
29
+ it 'with droplet' do
30
+ stub_droplet(droplet_id)
31
+
32
+ instance.droplet(droplet_id)
33
+
34
+ expect(a_request(:get, droplet_url))
35
+ .to have_been_made
36
+ end
37
+
38
+ it 'with error' do
39
+ stub_droplet_fail(droplet_id)
40
+
41
+ expect { instance.droplet(droplet_id) }
42
+ .to raise_error(DoSnapshot::DropletFindError)
43
+ expect(DoSnapshot.logger.buffer)
44
+ .to include "Droplet id: #{droplet_id} Not Found"
45
+
46
+ expect(a_request(:get, droplet_url))
47
+ .to have_been_made
48
+ end
49
+ end
50
+
51
+ describe '.droplets' do
52
+ it 'with droplets' do
53
+ stub_droplets
54
+
55
+ expect(instance.droplets.many?).to be_truthy
56
+
57
+ expect(a_request(:get, droplets_uri))
58
+ .to have_been_made
59
+ end
60
+
61
+ it 'with error' do
62
+ stub_droplets_fail
63
+
64
+ expect { instance.droplets }.to raise_error(DoSnapshot::DropletListError)
65
+ expect(DoSnapshot.logger.buffer)
66
+ .to include 'Droplet Listing is failed to retrieve'
67
+
68
+ expect(a_request(:get, droplets_uri))
69
+ .to have_been_made
70
+ end
71
+ end
72
+
73
+ describe '.start_droplet' do
74
+ it 'with event' do
75
+ stub_droplet_inactive(droplet_id)
76
+ stub_droplet_start(droplet_id)
77
+
78
+ instance.start_droplet(droplet_id)
79
+ expect(DoSnapshot.logger.buffer).to include "Droplet id: #{droplet_id} is requested for Power On."
80
+
81
+ expect(a_request(:post, droplet_start_url))
82
+ .to have_been_made
83
+ expect(a_request(:get, droplet_url))
84
+ .to have_been_made
85
+ end
86
+
87
+ it 'with warning message' do
88
+ stub_droplet(droplet_id)
89
+
90
+ expect { instance.start_droplet(droplet_id) }
91
+ .not_to raise_error
92
+ expect(DoSnapshot.logger.buffer)
93
+ .to include "Droplet #{droplet_id} is still running. Skipping."
94
+
95
+ expect(a_request(:get, droplet_url))
96
+ .to have_been_made
97
+ end
98
+
99
+ it 'with error' do
100
+ stub_droplet_fail(droplet_id)
101
+
102
+ expect { instance.start_droplet(droplet_id) }
103
+ .to raise_error(DoSnapshot::DropletFindError)
104
+
105
+ expect(a_request(:get, droplet_url))
106
+ .to have_been_made
107
+ end
108
+ end
109
+
110
+ describe '.stop_droplet by power status' do
111
+ let(:instance) { api.new(delay: delay, timeout: timeout, stop_by: :power_status) }
112
+
113
+ it 'with success' do
114
+ stub_event_done(event_id)
115
+ stub_droplet_stop(droplet_id)
116
+ stub_droplet_inactive(droplet_id)
117
+
118
+ instance.stop_droplet(droplet_id)
119
+
120
+ expect(a_request(:post, droplet_stop_url))
121
+ .to have_been_made
122
+ expect(a_request(:get, droplet_url))
123
+ .to have_been_made
124
+ end
125
+
126
+ it 'with error' do
127
+ stub_droplet_stop_fail(droplet_id)
128
+ stub_droplet(droplet_id)
129
+ instance.timeout = 1
130
+ expect { instance.stop_droplet(droplet_id) }
131
+ .to raise_error(DoSnapshot::DropletShutdownError)
132
+ instance.timeout = timeout
133
+ expect(DoSnapshot.logger.buffer)
134
+ .to include 'Droplet id: 100823 is Failed to Power Off.'
135
+
136
+ expect(a_request(:post, droplet_stop_url))
137
+ .to have_been_made
138
+ end
139
+ end
140
+
141
+ describe '.stop_droplet by event' do
142
+ it 'with success' do
143
+ stub_event_done(event_id)
144
+ stub_droplet_stop(droplet_id)
145
+
146
+ instance.stop_droplet(droplet_id)
147
+
148
+ expect(a_request(:post, droplet_stop_url))
149
+ .to have_been_made
150
+ expect(a_request(:get, action_find_url))
151
+ .to have_been_made
152
+ end
153
+
154
+ it 'with error' do
155
+ stub_droplet_stop_fail(droplet_id)
156
+
157
+ expect { instance.stop_droplet(droplet_id) }
158
+ .to raise_error(DoSnapshot::DropletShutdownError)
159
+ expect(DoSnapshot.logger.buffer)
160
+ .to include 'Droplet id: 100823 is Failed to Power Off.'
161
+
162
+ expect(a_request(:post, droplet_stop_url))
163
+ .to have_been_made
164
+ end
165
+ end
166
+
167
+ describe '.create_snapshot' do
168
+ it 'with success' do
169
+ stub_event_done(event_id)
170
+ stub_droplet_snapshot(droplet_id, snapshot_name)
171
+
172
+ expect { instance.create_snapshot(droplet_id, snapshot_name) }
173
+ .not_to raise_error
174
+
175
+ expect(a_request(:post, droplet_snapshot_url))
176
+ .to have_been_made
177
+ expect(a_request(:get, action_find_url))
178
+ .to have_been_made
179
+ end
180
+
181
+ it 'with error' do
182
+ stub_droplet_snapshot_fail(droplet_id, snapshot_name)
183
+
184
+ expect { instance.create_snapshot(droplet_id, snapshot_name) }
185
+ .to raise_error(DoSnapshot::SnapshotCreateError)
186
+
187
+ expect(a_request(:post, droplet_snapshot_url))
188
+ .to have_been_made
189
+ end
190
+
191
+ it 'with event error' do
192
+ stub_droplet_snapshot(droplet_id, snapshot_name)
193
+ stub_event_fail(event_id)
194
+
195
+ expect { instance.create_snapshot(droplet_id, snapshot_name) }
196
+ .not_to raise_error
197
+ expect(DoSnapshot.logger.buffer)
198
+ .to include "Event id: #{event_id} is failed!"
199
+
200
+ expect(a_request(:post, droplet_snapshot_url))
201
+ .to have_been_made
202
+ expect(a_request(:get, action_find_url))
203
+ .to have_been_made
204
+ end
205
+ end
206
+
207
+ describe '.inactive?' do
208
+ it 'when inactive' do
209
+ stub_droplet_inactive(droplet_id)
210
+
211
+ expect(instance.inactive?(droplet_id))
212
+ .to be_truthy
213
+ end
214
+
215
+ it 'when active' do
216
+ stub_droplet(droplet_id)
217
+
218
+ expect(instance.inactive?(droplet_id))
219
+ .to be_falsey
220
+ end
221
+ end
222
+
223
+ describe '.cleanup_snapshots' do
224
+ it 'with success' do
225
+ stub_droplet(droplet_id)
226
+ stub_image_destroy(image_id)
227
+ stub_image_destroy(image_id2)
228
+
229
+ droplet = instance.droplet(droplet_id)
230
+ expect { instance.cleanup_snapshots(droplet, 1) }
231
+ .not_to raise_error
232
+ expect(DoSnapshot.logger.buffer)
233
+ .to include 'Snapshot: 5019770 delete requested.'
234
+
235
+ expect(a_request(:get, droplet_url))
236
+ .to have_been_made
237
+ expect(a_request(:delete, image_destroy_url))
238
+ .to have_been_made
239
+ expect(a_request(:delete, image_destroy2_url))
240
+ .to have_been_made
241
+ end
242
+
243
+ it 'with warning message' do
244
+ stub_droplet(droplet_id)
245
+ stub_image_destroy_fail(image_id)
246
+ stub_image_destroy_fail(image_id2)
247
+
248
+ droplet = instance.droplet(droplet_id)
249
+ expect { instance.cleanup_snapshots(droplet, 1) }
250
+ .not_to raise_error
251
+ expect(DoSnapshot.logger.buffer)
252
+ .to include 'Destroy of snapshot 5019903 for droplet id: 100823 name: example.com is failed.'
253
+
254
+ expect(a_request(:get, droplet_url))
255
+ .to have_been_made
256
+ expect(a_request(:delete, image_destroy_url))
257
+ .to have_been_made
258
+ expect(a_request(:delete, image_destroy2_url))
259
+ .to have_been_made
260
+ end
261
+ end
262
+ end
263
+ end
264
+ end
265
+ end