backup 3.0.20 → 3.0.21

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 (178) hide show
  1. data/Gemfile +1 -5
  2. data/Gemfile.lock +46 -50
  3. data/README.md +54 -27
  4. data/lib/backup.rb +16 -39
  5. data/lib/backup/archive.rb +42 -18
  6. data/lib/backup/cleaner.rb +110 -25
  7. data/lib/backup/cli/helpers.rb +17 -32
  8. data/lib/backup/cli/utility.rb +46 -107
  9. data/lib/backup/compressor/base.rb +14 -2
  10. data/lib/backup/compressor/bzip2.rb +10 -24
  11. data/lib/backup/compressor/gzip.rb +10 -24
  12. data/lib/backup/compressor/lzma.rb +10 -23
  13. data/lib/backup/compressor/pbzip2.rb +12 -32
  14. data/lib/backup/config.rb +171 -0
  15. data/lib/backup/configuration/compressor/base.rb +1 -2
  16. data/lib/backup/configuration/compressor/pbzip2.rb +4 -4
  17. data/lib/backup/configuration/database/base.rb +2 -1
  18. data/lib/backup/configuration/database/mongodb.rb +8 -0
  19. data/lib/backup/configuration/database/mysql.rb +4 -0
  20. data/lib/backup/configuration/database/postgresql.rb +4 -0
  21. data/lib/backup/configuration/database/redis.rb +4 -0
  22. data/lib/backup/configuration/database/riak.rb +5 -1
  23. data/lib/backup/configuration/encryptor/base.rb +1 -2
  24. data/lib/backup/configuration/encryptor/open_ssl.rb +1 -1
  25. data/lib/backup/configuration/helpers.rb +7 -2
  26. data/lib/backup/configuration/notifier/base.rb +4 -28
  27. data/lib/backup/configuration/storage/base.rb +1 -1
  28. data/lib/backup/configuration/storage/dropbox.rb +14 -4
  29. data/lib/backup/configuration/syncer/base.rb +10 -0
  30. data/lib/backup/configuration/syncer/rsync/base.rb +28 -0
  31. data/lib/backup/configuration/syncer/rsync/local.rb +11 -0
  32. data/lib/backup/configuration/syncer/rsync/pull.rb +11 -0
  33. data/lib/backup/configuration/syncer/rsync/push.rb +31 -0
  34. data/lib/backup/configuration/syncer/s3.rb +0 -4
  35. data/lib/backup/database/base.rb +25 -7
  36. data/lib/backup/database/mongodb.rb +112 -75
  37. data/lib/backup/database/mysql.rb +54 -29
  38. data/lib/backup/database/postgresql.rb +60 -42
  39. data/lib/backup/database/redis.rb +61 -39
  40. data/lib/backup/database/riak.rb +35 -11
  41. data/lib/backup/dependency.rb +4 -5
  42. data/lib/backup/encryptor/base.rb +13 -1
  43. data/lib/backup/encryptor/gpg.rb +39 -39
  44. data/lib/backup/encryptor/open_ssl.rb +28 -38
  45. data/lib/backup/logger.rb +20 -11
  46. data/lib/backup/model.rb +206 -163
  47. data/lib/backup/notifier/base.rb +27 -25
  48. data/lib/backup/notifier/campfire.rb +7 -13
  49. data/lib/backup/notifier/hipchat.rb +28 -28
  50. data/lib/backup/notifier/mail.rb +24 -26
  51. data/lib/backup/notifier/presently.rb +10 -18
  52. data/lib/backup/notifier/prowl.rb +9 -17
  53. data/lib/backup/notifier/twitter.rb +11 -18
  54. data/lib/backup/package.rb +47 -0
  55. data/lib/backup/packager.rb +81 -16
  56. data/lib/backup/splitter.rb +48 -35
  57. data/lib/backup/storage/base.rb +44 -172
  58. data/lib/backup/storage/cloudfiles.rb +31 -46
  59. data/lib/backup/storage/cycler.rb +117 -0
  60. data/lib/backup/storage/dropbox.rb +92 -76
  61. data/lib/backup/storage/ftp.rb +30 -40
  62. data/lib/backup/storage/local.rb +44 -45
  63. data/lib/backup/storage/ninefold.rb +55 -49
  64. data/lib/backup/storage/rsync.rb +49 -56
  65. data/lib/backup/storage/s3.rb +33 -44
  66. data/lib/backup/storage/scp.rb +21 -48
  67. data/lib/backup/storage/sftp.rb +26 -40
  68. data/lib/backup/syncer/base.rb +7 -0
  69. data/lib/backup/syncer/rsync/base.rb +78 -0
  70. data/lib/backup/syncer/rsync/local.rb +53 -0
  71. data/lib/backup/syncer/rsync/pull.rb +38 -0
  72. data/lib/backup/syncer/rsync/push.rb +113 -0
  73. data/lib/backup/syncer/s3.rb +42 -32
  74. data/lib/backup/version.rb +1 -1
  75. data/spec/archive_spec.rb +235 -69
  76. data/spec/cleaner_spec.rb +304 -0
  77. data/spec/cli/helpers_spec.rb +142 -1
  78. data/spec/cli/utility_spec.rb +338 -13
  79. data/spec/compressor/base_spec.rb +31 -0
  80. data/spec/compressor/bzip2_spec.rb +60 -35
  81. data/spec/compressor/gzip_spec.rb +60 -35
  82. data/spec/compressor/lzma_spec.rb +60 -35
  83. data/spec/compressor/pbzip2_spec.rb +98 -37
  84. data/spec/config_spec.rb +321 -0
  85. data/spec/configuration/base_spec.rb +4 -4
  86. data/spec/configuration/compressor/bzip2_spec.rb +1 -0
  87. data/spec/configuration/compressor/gzip_spec.rb +1 -0
  88. data/spec/configuration/compressor/lzma_spec.rb +1 -0
  89. data/spec/configuration/compressor/pbzip2_spec.rb +32 -0
  90. data/spec/configuration/database/base_spec.rb +2 -1
  91. data/spec/configuration/database/mongodb_spec.rb +26 -16
  92. data/spec/configuration/database/mysql_spec.rb +4 -0
  93. data/spec/configuration/database/postgresql_spec.rb +4 -0
  94. data/spec/configuration/database/redis_spec.rb +4 -0
  95. data/spec/configuration/database/riak_spec.rb +4 -0
  96. data/spec/configuration/encryptor/gpg_spec.rb +1 -0
  97. data/spec/configuration/encryptor/open_ssl_spec.rb +1 -0
  98. data/spec/configuration/notifier/base_spec.rb +32 -0
  99. data/spec/configuration/notifier/campfire_spec.rb +1 -0
  100. data/spec/configuration/notifier/hipchat_spec.rb +1 -0
  101. data/spec/configuration/notifier/mail_spec.rb +1 -0
  102. data/spec/configuration/notifier/presently_spec.rb +1 -0
  103. data/spec/configuration/notifier/prowl_spec.rb +1 -0
  104. data/spec/configuration/notifier/twitter_spec.rb +1 -0
  105. data/spec/configuration/storage/cloudfiles_spec.rb +1 -0
  106. data/spec/configuration/storage/dropbox_spec.rb +4 -3
  107. data/spec/configuration/storage/ftp_spec.rb +1 -0
  108. data/spec/configuration/storage/local_spec.rb +1 -0
  109. data/spec/configuration/storage/ninefold_spec.rb +1 -0
  110. data/spec/configuration/storage/rsync_spec.rb +3 -1
  111. data/spec/configuration/storage/s3_spec.rb +1 -0
  112. data/spec/configuration/storage/scp_spec.rb +1 -0
  113. data/spec/configuration/storage/sftp_spec.rb +1 -0
  114. data/spec/configuration/syncer/rsync/base_spec.rb +33 -0
  115. data/spec/configuration/syncer/rsync/local_spec.rb +10 -0
  116. data/spec/configuration/syncer/rsync/pull_spec.rb +10 -0
  117. data/spec/configuration/syncer/{rsync_spec.rb → rsync/push_spec.rb} +12 -15
  118. data/spec/configuration/syncer/s3_spec.rb +2 -3
  119. data/spec/database/base_spec.rb +35 -20
  120. data/spec/database/mongodb_spec.rb +298 -119
  121. data/spec/database/mysql_spec.rb +147 -72
  122. data/spec/database/postgresql_spec.rb +155 -100
  123. data/spec/database/redis_spec.rb +200 -97
  124. data/spec/database/riak_spec.rb +82 -24
  125. data/spec/dependency_spec.rb +49 -0
  126. data/spec/encryptor/base_spec.rb +30 -0
  127. data/spec/encryptor/gpg_spec.rb +105 -28
  128. data/spec/encryptor/open_ssl_spec.rb +85 -114
  129. data/spec/logger_spec.rb +74 -8
  130. data/spec/model_spec.rb +528 -220
  131. data/spec/notifier/base_spec.rb +89 -0
  132. data/spec/notifier/campfire_spec.rb +147 -119
  133. data/spec/notifier/hipchat_spec.rb +140 -145
  134. data/spec/notifier/mail_spec.rb +190 -248
  135. data/spec/notifier/presently_spec.rb +147 -282
  136. data/spec/notifier/prowl_spec.rb +79 -111
  137. data/spec/notifier/twitter_spec.rb +87 -106
  138. data/spec/package_spec.rb +61 -0
  139. data/spec/packager_spec.rb +154 -0
  140. data/spec/spec_helper.rb +36 -13
  141. data/spec/splitter_spec.rb +90 -41
  142. data/spec/storage/base_spec.rb +95 -239
  143. data/spec/storage/cloudfiles_spec.rb +185 -75
  144. data/spec/storage/cycler_spec.rb +239 -0
  145. data/spec/storage/dropbox_spec.rb +318 -87
  146. data/spec/storage/ftp_spec.rb +165 -152
  147. data/spec/storage/local_spec.rb +206 -54
  148. data/spec/storage/ninefold_spec.rb +264 -128
  149. data/spec/storage/rsync_spec.rb +244 -163
  150. data/spec/storage/s3_spec.rb +175 -64
  151. data/spec/storage/scp_spec.rb +156 -150
  152. data/spec/storage/sftp_spec.rb +153 -135
  153. data/spec/syncer/base_spec.rb +22 -0
  154. data/spec/syncer/rsync/base_spec.rb +118 -0
  155. data/spec/syncer/rsync/local_spec.rb +121 -0
  156. data/spec/syncer/rsync/pull_spec.rb +90 -0
  157. data/spec/syncer/rsync/push_spec.rb +327 -0
  158. data/spec/syncer/s3_spec.rb +180 -91
  159. data/templates/cli/utility/config +1 -1
  160. data/templates/cli/utility/database/mongodb +4 -0
  161. data/templates/cli/utility/database/mysql +3 -0
  162. data/templates/cli/utility/database/postgresql +3 -0
  163. data/templates/cli/utility/database/redis +3 -0
  164. data/templates/cli/utility/database/riak +3 -0
  165. data/templates/cli/utility/storage/dropbox +4 -1
  166. data/templates/cli/utility/syncer/rsync_local +12 -0
  167. data/templates/cli/utility/syncer/{rsync → rsync_pull} +2 -2
  168. data/templates/cli/utility/syncer/rsync_push +17 -0
  169. data/templates/storage/dropbox/authorization_url.erb +1 -1
  170. metadata +42 -17
  171. data/lib/backup/configuration/syncer/rsync.rb +0 -45
  172. data/lib/backup/finder.rb +0 -87
  173. data/lib/backup/storage/object.rb +0 -47
  174. data/lib/backup/syncer/rsync.rb +0 -152
  175. data/spec/backup_spec.rb +0 -11
  176. data/spec/finder_spec.rb +0 -91
  177. data/spec/storage/object_spec.rb +0 -74
  178. data/spec/syncer/rsync_spec.rb +0 -195
@@ -12,6 +12,7 @@ describe Backup::Configuration::Storage::S3 do
12
12
  s3.path = 'my_backups'
13
13
  end
14
14
  end
15
+ after { Backup::Configuration::Storage::S3.clear_defaults! }
15
16
 
16
17
  it 'should set the default S3 configuration' do
17
18
  s3 = Backup::Configuration::Storage::S3
@@ -13,6 +13,7 @@ describe Backup::Configuration::Storage::SCP do
13
13
  scp.keep = 20
14
14
  end
15
15
  end
16
+ after { Backup::Configuration::Storage::SCP.clear_defaults! }
16
17
 
17
18
  it 'should set the default scp configuration' do
18
19
  scp = Backup::Configuration::Storage::SCP
@@ -13,6 +13,7 @@ describe Backup::Configuration::Storage::SFTP do
13
13
  sftp.keep = 20
14
14
  end
15
15
  end
16
+ after { Backup::Configuration::Storage::SFTP.clear_defaults! }
16
17
 
17
18
  it 'should set the default sftp configuration' do
18
19
  sftp = Backup::Configuration::Storage::SFTP
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../../../spec_helper.rb', __FILE__)
4
+
5
+ describe Backup::Configuration::Syncer::RSync::Base do
6
+ before do
7
+ Backup::Configuration::Syncer::RSync::Base.defaults do |rsync|
8
+ #rsync.directories = 'cannot_have_a_default_value'
9
+ rsync.path = '~/backups/'
10
+ rsync.mirror = true
11
+ rsync.additional_options = []
12
+ end
13
+ end
14
+ after { Backup::Configuration::Syncer::RSync::Base.clear_defaults! }
15
+
16
+ it 'should set the default rsync configuration' do
17
+ rsync = Backup::Configuration::Syncer::RSync::Base
18
+ rsync.path.should == '~/backups/'
19
+ rsync.mirror.should == true
20
+ rsync.additional_options.should == []
21
+ end
22
+
23
+ describe '#clear_defaults!' do
24
+ it 'should clear all the defaults, resetting them to nil' do
25
+ Backup::Configuration::Syncer::RSync::Base.clear_defaults!
26
+
27
+ rsync = Backup::Configuration::Syncer::RSync::Base
28
+ rsync.path.should == nil
29
+ rsync.mirror.should == nil
30
+ rsync.additional_options.should == nil
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../../../spec_helper.rb', __FILE__)
4
+
5
+ describe Backup::Configuration::Syncer::RSync::Local do
6
+ it 'should be a subclass of RSync::Base' do
7
+ rsync = Backup::Configuration::Syncer::RSync::Local
8
+ rsync.superclass.should == Backup::Configuration::Syncer::RSync::Base
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../../../spec_helper.rb', __FILE__)
4
+
5
+ describe Backup::Configuration::Syncer::RSync::Pull do
6
+ it 'should be a subclass of RSync::Push' do
7
+ rsync = Backup::Configuration::Syncer::RSync::Pull
8
+ rsync.superclass.should == Backup::Configuration::Syncer::RSync::Push
9
+ end
10
+ end
@@ -1,46 +1,43 @@
1
1
  # encoding: utf-8
2
2
 
3
- require File.expand_path('../../../spec_helper.rb', __FILE__)
3
+ require File.expand_path('../../../../spec_helper.rb', __FILE__)
4
4
 
5
- describe Backup::Configuration::Syncer::RSync do
5
+ describe Backup::Configuration::Syncer::RSync::Push do
6
6
  before do
7
- Backup::Configuration::Syncer::RSync.defaults do |rsync|
7
+ Backup::Configuration::Syncer::RSync::Push.defaults do |rsync|
8
8
  rsync.username = 'my_username'
9
9
  rsync.password = 'my_password'
10
10
  rsync.ip = '123.45.678.90'
11
11
  rsync.port = 22
12
- rsync.path = '~/backups/'
13
- rsync.mirror = true
14
12
  rsync.compress = true
15
- rsync.additional_options = []
16
13
  end
17
14
  end
15
+ after { Backup::Configuration::Syncer::RSync::Push.clear_defaults! }
16
+
17
+ it 'should be a subclass of RSync::Base' do
18
+ rsync = Backup::Configuration::Syncer::RSync::Push
19
+ rsync.superclass.should == Backup::Configuration::Syncer::RSync::Base
20
+ end
18
21
 
19
22
  it 'should set the default rsync configuration' do
20
- rsync = Backup::Configuration::Syncer::RSync
23
+ rsync = Backup::Configuration::Syncer::RSync::Push
21
24
  rsync.username.should == 'my_username'
22
25
  rsync.password.should == 'my_password'
23
26
  rsync.ip.should == '123.45.678.90'
24
27
  rsync.port.should == 22
25
- rsync.path.should == '~/backups/'
26
- rsync.mirror.should == true
27
28
  rsync.compress.should == true
28
- rsync.additional_options.should == []
29
29
  end
30
30
 
31
31
  describe '#clear_defaults!' do
32
32
  it 'should clear all the defaults, resetting them to nil' do
33
- Backup::Configuration::Syncer::RSync.clear_defaults!
33
+ Backup::Configuration::Syncer::RSync::Push.clear_defaults!
34
34
 
35
- rsync = Backup::Configuration::Syncer::RSync
35
+ rsync = Backup::Configuration::Syncer::RSync::Push
36
36
  rsync.username.should == nil
37
37
  rsync.password.should == nil
38
38
  rsync.ip.should == nil
39
39
  rsync.port.should == nil
40
- rsync.path.should == nil
41
- rsync.mirror.should == nil
42
40
  rsync.compress.should == nil
43
- rsync.additional_options.should == nil
44
41
  end
45
42
  end
46
43
  end
@@ -9,11 +9,12 @@ describe Backup::Configuration::Syncer::S3 do
9
9
  s3.secret_access_key = 'my_secret_access_key'
10
10
  s3.bucket = 'my-bucket'
11
11
  s3.path = '/backups/'
12
- s3.directories = '/directories/to/backup/'
12
+ #s3.directories = 'cannot_have_a_default_value'
13
13
  s3.mirror = true
14
14
  s3.additional_options = ['--exclude="*.rb"']
15
15
  end
16
16
  end
17
+ after { Backup::Configuration::Syncer::S3.clear_defaults! }
17
18
 
18
19
  it 'should set the default s3 configuration' do
19
20
  s3 = Backup::Configuration::Syncer::S3
@@ -21,7 +22,6 @@ describe Backup::Configuration::Syncer::S3 do
21
22
  s3.secret_access_key.should == 'my_secret_access_key'
22
23
  s3.bucket.should == 'my-bucket'
23
24
  s3.path.should == '/backups/'
24
- s3.directories.should == '/directories/to/backup/'
25
25
  s3.mirror.should == true
26
26
  s3.additional_options.should == ['--exclude="*.rb"']
27
27
  end
@@ -35,7 +35,6 @@ describe Backup::Configuration::Syncer::S3 do
35
35
  s3.secret_access_key.should == nil
36
36
  s3.bucket.should == nil
37
37
  s3.path.should == nil
38
- s3.directories.should == nil
39
38
  s3.mirror.should == nil
40
39
  s3.additional_options.should == nil
41
40
  end
@@ -3,37 +3,52 @@
3
3
  require File.expand_path('../../spec_helper.rb', __FILE__)
4
4
 
5
5
  describe Backup::Database::Base do
6
+ let(:model) { Backup::Model.new('foo', 'foo') }
7
+ let(:db) { Backup::Database::Base.new(model) }
6
8
 
7
- before do
8
- class Backup::Database::Base
9
- def initialize(&block)
10
- instance_eval(&block) if block_given?
11
- end
12
- end
9
+ it 'should set #utility_path' do
10
+ db.utility_path.should be_nil
11
+ db.utility_path = 'utility path'
12
+ db.utility_path.should == 'utility path'
13
13
  end
14
14
 
15
- let(:db) do
16
- Backup::Database::Base.new do |db|
17
- db.utility_path = '/var/usr/my_util'
15
+ describe '#perform!' do
16
+ it 'should invoke prepare! and log!' do
17
+ s = sequence ''
18
+ db.expects(:prepare!).in_sequence(s)
19
+ db.expects(:log!).in_sequence(s)
20
+
21
+ db.perform!
18
22
  end
19
23
  end
20
24
 
21
- it 'should return the utility path instead of auto-detecting it' do
22
- db.utility(:my_database_util).should == '/var/usr/my_util'
25
+ context 'since CLI::Helpers are included' do
26
+ it 'should respond to the #utility method' do
27
+ db.respond_to?(:utility).should be_true
28
+ end
23
29
  end
24
30
 
25
- it 'should ignore the utility_path when not defined' do
26
- db = Backup::Database::Base.new
27
- db.utility(:my_database_util).should == :my_database_util
31
+ describe '#prepare!' do
32
+ it 'should set and create #dump_path' do
33
+ model = stub(:trigger => 'test_trigger')
34
+ db.instance_variable_set(:@model, model)
35
+ FileUtils.expects(:mkdir_p).with(
36
+ File.join(Backup::Config.tmp_path, 'test_trigger', 'databases', 'Base')
37
+ )
38
+ db.send(:prepare!)
39
+ db.instance_variable_get(:@dump_path).should ==
40
+ File.join(Backup::Config.tmp_path, 'test_trigger', 'databases', 'Base')
41
+ end
28
42
  end
29
43
 
30
- describe '#perform!' do
31
- it 'should invoke prepare! and log!' do
32
- db.expects(:prepare!)
33
- db.expects(:log!)
44
+ describe '#log!' do
45
+ it 'should use #database_name' do
46
+ db.stubs(:name).returns('database_name')
47
+ Backup::Logger.expects(:message).with(
48
+ "Database::Base started dumping and archiving 'database_name'."
49
+ )
34
50
 
35
- db.perform!
51
+ db.send(:log!)
36
52
  end
37
53
  end
38
-
39
54
  end
@@ -3,13 +3,9 @@
3
3
  require File.expand_path('../../spec_helper.rb', __FILE__)
4
4
 
5
5
  describe Backup::Database::MongoDB do
6
-
7
- before do
8
- Backup::Database::MongoDB.any_instance.stubs(:load_defaults!)
9
- end
10
-
6
+ let(:model) { Backup::Model.new(:test_trigger, 'test label') }
11
7
  let(:db) do
12
- Backup::Database::MongoDB.new do |db|
8
+ Backup::Database::MongoDB.new(model) do |db|
13
9
  db.name = 'mydatabase'
14
10
  db.username = 'someuser'
15
11
  db.password = 'secret'
@@ -18,11 +14,14 @@ describe Backup::Database::MongoDB do
18
14
 
19
15
  db.ipv6 = true
20
16
  db.only_collections = ['users', 'pirates']
21
- db.additional_options = ['--query']
17
+ db.additional_options = ['--query', '--foo']
18
+ db.mongodump_utility = '/path/to/mongodump'
19
+ db.mongo_utility = '/path/to/mongo'
22
20
  end
23
21
  end
24
22
 
25
- describe '#new' do
23
+ describe '#initialize' do
24
+
26
25
  it 'should read the adapter details correctly' do
27
26
  db.name.should == 'mydatabase'
28
27
  db.username.should == 'someuser'
@@ -30,178 +29,358 @@ describe Backup::Database::MongoDB do
30
29
  db.host.should == 'localhost'
31
30
  db.port.should == 123
32
31
 
33
- db.only_collections.should == ['users', 'pirates']
34
- db.additional_options.should == '--query'
32
+ db.ipv6.should == true
33
+ db.only_collections.should == ['users', 'pirates']
34
+ db.additional_options.should == ['--query', '--foo']
35
+ db.mongodump_utility.should == '/path/to/mongodump'
36
+ db.mongo_utility.should == '/path/to/mongo'
37
+ db.lock.should == false
35
38
  end
36
39
 
37
- it 'arrays should default to empty arrays when not specified' do
38
- db = Backup::Database::MongoDB.new do |db|
39
- db.name = 'mydatabase'
40
- db.username = 'someuser'
41
- db.password = 'secret'
40
+ context 'when options are not set' do
41
+ before do
42
+ Backup::Database::MongoDB.any_instance.expects(:utility).
43
+ with(:mongodump).returns('/real/mongodump')
44
+ Backup::Database::MongoDB.any_instance.expects(:utility).
45
+ with(:mongo).returns('/real/mongo')
42
46
  end
43
47
 
44
- db.only_collections.should == []
45
- db.additional_options.should == ""
48
+ it 'should use default values' do
49
+ db = Backup::Database::MongoDB.new(model)
50
+
51
+ db.name.should be_nil
52
+ db.username.should be_nil
53
+ db.password.should be_nil
54
+ db.host.should be_nil
55
+ db.port.should be_nil
56
+
57
+ db.ipv6.should be_false
58
+ db.only_collections.should == []
59
+ db.additional_options.should == []
60
+ db.mongodump_utility.should == '/real/mongodump'
61
+ db.mongo_utility.should == '/real/mongo'
62
+ db.lock.should be_false
63
+ end
46
64
  end
47
- end
48
65
 
49
- describe '#only_collections' do
50
- it 'should return a string for the mongodump selected table to dump option' do
51
- db.collections_to_dump.should == %w[users pirates]
66
+ context 'when configuration defaults have been set' do
67
+ after { Backup::Configuration::Database::MongoDB.clear_defaults! }
68
+
69
+ it 'should use configuration defaults' do
70
+ Backup::Configuration::Database::MongoDB.defaults do |db|
71
+ db.name = 'db_name'
72
+ db.username = 'db_username'
73
+ db.password = 'db_password'
74
+ db.host = 'db_host'
75
+ db.port = 789
76
+
77
+ db.ipv6 = true
78
+ db.only_collections = ['collection']
79
+ db.additional_options = ['--opt']
80
+ db.mongodump_utility = '/default/path/to/mongodump'
81
+ db.mongo_utility = '/default/path/to/mongo'
82
+ db.lock = true
83
+ end
84
+
85
+ db = Backup::Database::MongoDB.new(model)
86
+ db.name.should == 'db_name'
87
+ db.username.should == 'db_username'
88
+ db.password.should == 'db_password'
89
+ db.host.should == 'db_host'
90
+ db.port.should == 789
91
+
92
+ db.ipv6.should be_true
93
+ db.only_collections.should == ['collection']
94
+ db.additional_options.should == ['--opt']
95
+ db.mongodump_utility.should == '/default/path/to/mongodump'
96
+ db.mongo_utility.should == '/default/path/to/mongo'
97
+ db.lock.should be_true
98
+ end
52
99
  end
53
- end
100
+ end # describe '#initialize'
54
101
 
55
- describe '#credential_options' do
56
- it 'should return the mongo syntax for the credential options' do
57
- db.credential_options.should == "--username='someuser' --password='secret'"
102
+ describe '#perform!' do
103
+ let(:s) { sequence '' }
104
+
105
+ before do
106
+ # superclass actions
107
+ db.expects(:prepare!).in_sequence(s)
108
+ db.expects(:log!).in_sequence(s)
58
109
  end
59
110
 
60
- it 'should only return the mongo syntax for the user' do
61
- db = Backup::Database::MongoDB.new do |db|
62
- db.username = 'someuser'
111
+ context 'when #lock is set to false' do
112
+
113
+ context 'when #only_collections has not been specified' do
114
+ before { db.only_collections = [] }
115
+ it 'should dump everything without locking' do
116
+ db.expects(:lock_database).never
117
+ db.expects(:unlock_database).never
118
+ db.expects(:specific_collection_dump!).never
119
+
120
+ db.expects(:dump!).in_sequence(s)
121
+ db.expects(:package!).in_sequence(s)
122
+ db.perform!
123
+ end
63
124
  end
64
125
 
65
- db.credential_options.should == "--username='someuser'"
66
- end
67
- end
126
+ context 'when #only_collections has been specified' do
127
+ it 'should dump specific collections without locking' do
128
+ db.expects(:lock_database).never
129
+ db.expects(:unlock_database).never
130
+ db.expects(:dump!).never
68
131
 
69
- describe '#connectivity_options' do
70
- it 'should return the mongo syntax for the connectivity options' do
71
- db.connectivity_options.should == "--host='localhost' --port='123'"
72
- end
132
+ db.expects(:specific_collection_dump!).in_sequence(s)
133
+ db.expects(:package!).in_sequence(s)
134
+ db.perform!
135
+ end
136
+ end
137
+
138
+ end # context 'when #lock is set to false'
73
139
 
74
- it 'should return only the socket' do
75
- db = Backup::Database::MongoDB.new do |db|
76
- db.host = ''
77
- db.port = 123
140
+ context 'when #lock is set to true' do
141
+ before { db.lock = true }
142
+
143
+ context 'when #only_collections has not been specified' do
144
+ before { db.only_collections = [] }
145
+ it 'should dump everything while locking the database' do
146
+ db.expects(:specific_collection_dump!).never
147
+
148
+ db.expects(:lock_database).in_sequence(s)
149
+ db.expects(:dump!).in_sequence(s)
150
+ db.expects(:unlock_database).in_sequence(s)
151
+ db.expects(:package!).in_sequence(s)
152
+ db.perform!
153
+ end
78
154
  end
79
155
 
80
- db.connectivity_options.should == "--port='123'"
81
- end
82
- end
156
+ context 'when #only_collections has been specified' do
157
+ it 'should dump specific collections without locking' do
158
+ db.expects(:lock_database).never
159
+ db.expects(:unlock_database).never
160
+ db.expects(:dump!).never
161
+
162
+ db.expects(:lock_database).in_sequence(s)
163
+ db.expects(:specific_collection_dump!).in_sequence(s)
164
+ db.expects(:unlock_database).in_sequence(s)
165
+ db.expects(:package!).in_sequence(s)
166
+ db.perform!
167
+ end
168
+ end
169
+
170
+ end # context 'when #lock is set to true'
171
+
172
+ context 'when errors occur' do
173
+ it 'should re-raise error and skip package!' do
174
+ db.expects(:specific_collection_dump!).in_sequence(s).
175
+ raises('Test Error Message')
176
+ db.expects(:package!).never
177
+
178
+ expect do
179
+ db.perform!
180
+ end.to raise_error(
181
+ Backup::Errors::Database::MongoDBError,
182
+ "Database::MongoDBError: Database Dump Failed!\n" +
183
+ " Reason: RuntimeError\n" +
184
+ " Test Error Message"
185
+ )
186
+ end
83
187
 
84
- describe '#ipv6' do
85
- it 'should return a mongodb syntax compatible ipv6 flag' do
86
- db.ipv6 = true
87
- db.ipv6.should == '--ipv6'
188
+ it 'should ensure database is unlocked' do
189
+ db.lock = true
190
+
191
+ db.expects(:lock_database).in_sequence(s)
192
+ db.expects(:specific_collection_dump!).in_sequence(s).
193
+ raises('Test Error Message')
194
+ db.expects(:unlock_database).in_sequence(s)
195
+ db.expects(:package!).never
196
+
197
+ expect do
198
+ db.perform!
199
+ end.to raise_error(
200
+ Backup::Errors::Database::MongoDBError,
201
+ "Database::MongoDBError: Database Dump Failed!\n" +
202
+ " Reason: RuntimeError\n" +
203
+ " Test Error Message"
204
+ )
205
+ end
88
206
  end
89
207
 
90
- it 'should return an empty string' do
91
- db.ipv6 = nil
92
- db.ipv6.should == ''
208
+ end # describe '#perform!'
209
+
210
+ describe '#dump!' do
211
+ it 'should run the mongodb dump command' do
212
+ db.expects(:mongodump).returns(:dump_command)
213
+ db.expects(:run).with(:dump_command)
214
+ db.send(:dump!)
93
215
  end
94
216
  end
95
217
 
96
- describe '#mongodump_string' do
97
- it 'should return the full mongodump string' do
98
- db.expects(:utility).with(:mongodump).returns('mongodump')
99
- db.prepare!
100
- db.mongodump.should ==
101
- "mongodump --db='mydatabase' --username='someuser' --password='secret' " +
102
- "--host='localhost' --port='123' --ipv6 --query --out='#{ File.join(Backup::TMP_PATH, Backup::TRIGGER, 'MongoDB') }'"
218
+ describe '#specific_collection_dump!' do
219
+ it 'should run the mongodb dump command for each collection' do
220
+ db.expects(:mongodump).twice.returns('dump_command')
221
+ db.expects(:run).with("dump_command --collection='users'")
222
+ db.expects(:run).with("dump_command --collection='pirates'")
223
+ db.send(:specific_collection_dump!)
103
224
  end
104
225
  end
105
226
 
106
- describe '#perform!' do
227
+ describe '#mongodump' do
107
228
  before do
108
- db.stubs(:utility).returns('mongodump')
109
- db.stubs(:mkdir)
110
- db.stubs(:run)
229
+ db.instance_variable_set(:@dump_path, '/path/to/dump/folder')
111
230
  end
112
231
 
113
- it 'should ensure the directory is available' do
114
- db.expects(:mkdir).with(File.join(Backup::TMP_PATH, "myapp", "MongoDB"))
115
- db.perform!
232
+ it 'should return the mongodb dump command string' do
233
+ db.send(:mongodump).should == "/path/to/mongodump " +
234
+ "--db='mydatabase' --username='someuser' --password='secret' " +
235
+ "--host='localhost' --port='123' --ipv6 " +
236
+ "--query --foo --out='/path/to/dump/folder'"
116
237
  end
238
+ end
117
239
 
118
- it 'should run the mongodump command and dump all collections' do
119
- db.only_collections = []
120
- db.expects(:dump!)
240
+ describe '#package!' do
241
+ let(:compressor) { mock }
121
242
 
122
- db.perform!
123
- end
243
+ context 'when a compressor is configured' do
244
+ before do
245
+ Timecop.freeze(Time.now)
246
+ db.instance_variable_set(:@dump_path, '/path/to/dump/folder')
247
+ db.expects(:utility).with(:tar).returns('tar')
248
+ model.expects(:compressor).twice.returns(compressor)
249
+ compressor.expects(:compress_with).yields('compressor_command', '.gz')
250
+ end
124
251
 
125
- it 'should run the mongodump command and dump all collections' do
126
- db.only_collections = nil
127
- db.expects(:dump!)
252
+ it 'should package the dump directory, then remove it' do
253
+ timestamp = Time.now.to_i.to_s[-5, 5]
254
+ db.expects(:run).with(
255
+ "tar -cf - -C '/path/to/dump' 'folder' | compressor_command" +
256
+ " > /path/to/dump/folder-#{ timestamp }.tar.gz"
257
+ )
258
+ FileUtils.expects(:rm_rf).with('/path/to/dump/folder')
128
259
 
129
- db.perform!
260
+ db.send(:package!)
261
+ end
130
262
  end
131
263
 
132
- it 'should lock database before dump if lock mode is enabled' do
133
- db.lock = true
134
- db.expects(:lock_database)
264
+ context 'when a compressor is not configured' do
265
+ before do
266
+ model.expects(:compressor).returns(nil)
267
+ end
135
268
 
136
- db.perform!
269
+ it 'should return nil' do
270
+ db.expects(:run).never
271
+ db.send(:package!).should be_nil
272
+ end
137
273
  end
274
+ end
138
275
 
139
- it 'should not lock database before dump if lock mode is disabled' do
140
- db.lock = false
141
- db.expects(:lock_database).never
142
-
143
- db.perform!
276
+ describe '#database' do
277
+ context 'when a database name is given' do
278
+ it 'should return the command string for the database' do
279
+ db.send(:database).should == "--db='mydatabase'"
280
+ end
144
281
  end
145
282
 
146
- it 'should unlock database after dump if lock mode is enabled' do
147
- db.lock = true
148
- db.expects(:unlock_database)
283
+ context 'when no database name is given' do
284
+ it 'should return nil' do
285
+ db.name = nil
286
+ db.send(:database).should be_nil
287
+ end
288
+ end
289
+ end
149
290
 
150
- db.perform!
291
+ describe '#credential_options' do
292
+ it 'should return the command string for the user credentials' do
293
+ db.send(:credential_options).should ==
294
+ "--username='someuser' --password='secret'"
151
295
  end
296
+ end
152
297
 
153
- it 'should unlock the database if an exception is raised after it was locked' do
154
- db.lock = true
155
- db.expects(:unlock_database)
156
- db.expects(:lock_database).raises(RuntimeError, 'something went wrong')
157
- db.expects(:raise)
298
+ describe '#connectivity_options' do
299
+ it 'should return the command string for the connectivity options' do
300
+ db.send(:connectivity_options).should == "--host='localhost' --port='123'"
301
+ end
302
+ end
158
303
 
159
- db.perform!
304
+ describe '#ipv6_option' do
305
+ context 'when #ipv6 is set true' do
306
+ it 'should return the command string for the ipv6 option' do
307
+ db.send(:ipv6_option).should == '--ipv6'
308
+ end
160
309
  end
161
310
 
162
- it 'should not unlock database after dump if lock mode is disabled' do
163
- db.lock = false
164
- db.expects(:unlock_database).never
311
+ context 'when #ipv6 is set false' do
312
+ it 'should return and empty string' do
313
+ db.ipv6 = false
314
+ db.send(:ipv6_option).should == ''
315
+ end
316
+ end
317
+ end
165
318
 
166
- db.perform!
319
+ describe '#user_options' do
320
+ context 'when #additional_options are set' do
321
+ it 'should return the command string for the options' do
322
+ db.send(:user_options).should == '--query --foo'
323
+ end
167
324
  end
168
325
 
169
- it 'should dump only the provided collections' do
170
- db.only_collections = %w[users admins profiles]
171
- db.expects(:specific_collection_dump!)
326
+ context 'when #additional_options are not set' do
327
+ it 'should return an empty string' do
328
+ db.additional_options = []
329
+ db.send(:user_options).should == ''
330
+ end
331
+ end
332
+ end
172
333
 
173
- db.perform!
334
+ describe '#dump_directory' do
335
+ it 'should return the command string for the dump path' do
336
+ db.instance_variable_set(:@dump_path, '/path/to/dump/folder')
337
+ db.send(:dump_directory).should == "--out='/path/to/dump/folder'"
174
338
  end
339
+ end
175
340
 
176
- it do
177
- Backup::Logger.expects(:message).
178
- with("Backup::Database::MongoDB started dumping and archiving 'mydatabase'.")
179
- db.perform!
341
+ describe '#lock_database' do
342
+ it 'should return the command to lock the database' do
343
+ db.stubs(:mongo_uri).returns(:mongo_uri_output)
344
+ db.expects(:run).with(
345
+ " echo 'use admin\n" +
346
+ ' db.runCommand({"fsync" : 1, "lock" : 1})\' | /path/to/mongo mongo_uri_output' +
347
+ "\n"
348
+ )
349
+ db.send(:lock_database)
180
350
  end
181
351
  end
182
352
 
183
- describe "#mongo_uri" do
184
- before do
185
- db.host = "flame.mongohq.com"
186
- db.port = 12345
187
- db.username = "sample_username"
188
- db.password = "sample_password"
189
- db.ipv6 = nil
353
+ describe '#unlock_database' do
354
+ it 'should return the command to unlock the database' do
355
+ db.stubs(:mongo_uri).returns(:mongo_uri_output)
356
+ db.expects(:run).with(
357
+ " echo 'use admin\n" +
358
+ ' db.$cmd.sys.unlock.findOne()\' | /path/to/mongo mongo_uri_output' +
359
+ "\n"
360
+ )
361
+ db.send(:unlock_database)
190
362
  end
363
+ end
191
364
 
192
- it "should return URI without database" do
193
- db.name = nil
194
- db.mongo_uri.should == "flame.mongohq.com:12345 --username='sample_username' --password='sample_password'"
365
+ describe '#mongo_uri' do
366
+ before do
367
+ db.stubs(:credential_options).returns(:credential_options_output)
368
+ db.stubs(:ipv6_option).returns(:ipv6_option_output)
195
369
  end
196
370
 
197
- it "should return URI without database" do
198
- db.name = ""
199
- db.mongo_uri.should == "flame.mongohq.com:12345 --username='sample_username' --password='sample_password'"
371
+ context 'when a database name is given' do
372
+ it 'should return the URI specifying the database' do
373
+ db.send(:mongo_uri).should ==
374
+ "localhost:123/mydatabase credential_options_output ipv6_option_output"
375
+ end
200
376
  end
201
377
 
202
- it "should return URI without database" do
203
- db.name = "sample_db"
204
- db.mongo_uri.should == "flame.mongohq.com:12345/sample_db --username='sample_username' --password='sample_password'"
378
+ context 'when no database name is given' do
379
+ it 'should return the URI without specifying the database' do
380
+ db.name = nil
381
+ db.send(:mongo_uri).should ==
382
+ "localhost:123 credential_options_output ipv6_option_output"
383
+ end
205
384
  end
206
385
  end
207
386
  end