backup_checksum 3.0.23

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 (244) hide show
  1. data/.gitignore +7 -0
  2. data/.travis.yml +10 -0
  3. data/Gemfile +28 -0
  4. data/Gemfile.lock +130 -0
  5. data/Guardfile +21 -0
  6. data/LICENSE.md +24 -0
  7. data/README.md +476 -0
  8. data/backup_checksum.gemspec +32 -0
  9. data/bin/backup +11 -0
  10. data/lib/backup.rb +217 -0
  11. data/lib/backup/archive.rb +117 -0
  12. data/lib/backup/binder.rb +22 -0
  13. data/lib/backup/checksum/base.rb +44 -0
  14. data/lib/backup/checksum/shasum.rb +16 -0
  15. data/lib/backup/cleaner.rb +121 -0
  16. data/lib/backup/cli/helpers.rb +88 -0
  17. data/lib/backup/cli/utility.rb +247 -0
  18. data/lib/backup/compressor/base.rb +29 -0
  19. data/lib/backup/compressor/bzip2.rb +50 -0
  20. data/lib/backup/compressor/gzip.rb +47 -0
  21. data/lib/backup/compressor/lzma.rb +50 -0
  22. data/lib/backup/compressor/pbzip2.rb +56 -0
  23. data/lib/backup/config.rb +173 -0
  24. data/lib/backup/configuration/base.rb +15 -0
  25. data/lib/backup/configuration/checksum/base.rb +9 -0
  26. data/lib/backup/configuration/checksum/shasum.rb +9 -0
  27. data/lib/backup/configuration/compressor/base.rb +9 -0
  28. data/lib/backup/configuration/compressor/bzip2.rb +23 -0
  29. data/lib/backup/configuration/compressor/gzip.rb +23 -0
  30. data/lib/backup/configuration/compressor/lzma.rb +23 -0
  31. data/lib/backup/configuration/compressor/pbzip2.rb +28 -0
  32. data/lib/backup/configuration/database/base.rb +19 -0
  33. data/lib/backup/configuration/database/mongodb.rb +49 -0
  34. data/lib/backup/configuration/database/mysql.rb +42 -0
  35. data/lib/backup/configuration/database/postgresql.rb +41 -0
  36. data/lib/backup/configuration/database/redis.rb +39 -0
  37. data/lib/backup/configuration/database/riak.rb +29 -0
  38. data/lib/backup/configuration/encryptor/base.rb +9 -0
  39. data/lib/backup/configuration/encryptor/gpg.rb +17 -0
  40. data/lib/backup/configuration/encryptor/open_ssl.rb +32 -0
  41. data/lib/backup/configuration/helpers.rb +52 -0
  42. data/lib/backup/configuration/notifier/base.rb +28 -0
  43. data/lib/backup/configuration/notifier/campfire.rb +25 -0
  44. data/lib/backup/configuration/notifier/hipchat.rb +41 -0
  45. data/lib/backup/configuration/notifier/mail.rb +112 -0
  46. data/lib/backup/configuration/notifier/presently.rb +25 -0
  47. data/lib/backup/configuration/notifier/prowl.rb +23 -0
  48. data/lib/backup/configuration/notifier/twitter.rb +21 -0
  49. data/lib/backup/configuration/storage/base.rb +18 -0
  50. data/lib/backup/configuration/storage/cloudfiles.rb +25 -0
  51. data/lib/backup/configuration/storage/dropbox.rb +58 -0
  52. data/lib/backup/configuration/storage/ftp.rb +29 -0
  53. data/lib/backup/configuration/storage/local.rb +17 -0
  54. data/lib/backup/configuration/storage/ninefold.rb +20 -0
  55. data/lib/backup/configuration/storage/rsync.rb +29 -0
  56. data/lib/backup/configuration/storage/s3.rb +25 -0
  57. data/lib/backup/configuration/storage/scp.rb +25 -0
  58. data/lib/backup/configuration/storage/sftp.rb +25 -0
  59. data/lib/backup/configuration/syncer/base.rb +10 -0
  60. data/lib/backup/configuration/syncer/cloud.rb +23 -0
  61. data/lib/backup/configuration/syncer/cloud_files.rb +30 -0
  62. data/lib/backup/configuration/syncer/rsync/base.rb +28 -0
  63. data/lib/backup/configuration/syncer/rsync/local.rb +11 -0
  64. data/lib/backup/configuration/syncer/rsync/pull.rb +11 -0
  65. data/lib/backup/configuration/syncer/rsync/push.rb +31 -0
  66. data/lib/backup/configuration/syncer/s3.rb +23 -0
  67. data/lib/backup/database/base.rb +59 -0
  68. data/lib/backup/database/mongodb.rb +232 -0
  69. data/lib/backup/database/mysql.rb +163 -0
  70. data/lib/backup/database/postgresql.rb +146 -0
  71. data/lib/backup/database/redis.rb +139 -0
  72. data/lib/backup/database/riak.rb +69 -0
  73. data/lib/backup/dependency.rb +114 -0
  74. data/lib/backup/encryptor/base.rb +29 -0
  75. data/lib/backup/encryptor/gpg.rb +80 -0
  76. data/lib/backup/encryptor/open_ssl.rb +72 -0
  77. data/lib/backup/errors.rb +124 -0
  78. data/lib/backup/logger.rb +152 -0
  79. data/lib/backup/model.rb +386 -0
  80. data/lib/backup/notifier/base.rb +81 -0
  81. data/lib/backup/notifier/campfire.rb +168 -0
  82. data/lib/backup/notifier/hipchat.rb +99 -0
  83. data/lib/backup/notifier/mail.rb +206 -0
  84. data/lib/backup/notifier/presently.rb +88 -0
  85. data/lib/backup/notifier/prowl.rb +65 -0
  86. data/lib/backup/notifier/twitter.rb +70 -0
  87. data/lib/backup/package.rb +51 -0
  88. data/lib/backup/packager.rb +108 -0
  89. data/lib/backup/pipeline.rb +107 -0
  90. data/lib/backup/splitter.rb +75 -0
  91. data/lib/backup/storage/base.rb +119 -0
  92. data/lib/backup/storage/cloudfiles.rb +87 -0
  93. data/lib/backup/storage/cycler.rb +117 -0
  94. data/lib/backup/storage/dropbox.rb +181 -0
  95. data/lib/backup/storage/ftp.rb +119 -0
  96. data/lib/backup/storage/local.rb +82 -0
  97. data/lib/backup/storage/ninefold.rb +116 -0
  98. data/lib/backup/storage/rsync.rb +149 -0
  99. data/lib/backup/storage/s3.rb +94 -0
  100. data/lib/backup/storage/scp.rb +99 -0
  101. data/lib/backup/storage/sftp.rb +108 -0
  102. data/lib/backup/syncer/base.rb +42 -0
  103. data/lib/backup/syncer/cloud.rb +190 -0
  104. data/lib/backup/syncer/cloud_files.rb +56 -0
  105. data/lib/backup/syncer/rsync/base.rb +52 -0
  106. data/lib/backup/syncer/rsync/local.rb +53 -0
  107. data/lib/backup/syncer/rsync/pull.rb +38 -0
  108. data/lib/backup/syncer/rsync/push.rb +113 -0
  109. data/lib/backup/syncer/s3.rb +47 -0
  110. data/lib/backup/template.rb +46 -0
  111. data/lib/backup/version.rb +43 -0
  112. data/spec/archive_spec.rb +335 -0
  113. data/spec/cleaner_spec.rb +304 -0
  114. data/spec/cli/helpers_spec.rb +176 -0
  115. data/spec/cli/utility_spec.rb +363 -0
  116. data/spec/compressor/base_spec.rb +31 -0
  117. data/spec/compressor/bzip2_spec.rb +83 -0
  118. data/spec/compressor/gzip_spec.rb +83 -0
  119. data/spec/compressor/lzma_spec.rb +83 -0
  120. data/spec/compressor/pbzip2_spec.rb +124 -0
  121. data/spec/config_spec.rb +321 -0
  122. data/spec/configuration/base_spec.rb +35 -0
  123. data/spec/configuration/compressor/bzip2_spec.rb +29 -0
  124. data/spec/configuration/compressor/gzip_spec.rb +29 -0
  125. data/spec/configuration/compressor/lzma_spec.rb +29 -0
  126. data/spec/configuration/compressor/pbzip2_spec.rb +32 -0
  127. data/spec/configuration/database/base_spec.rb +17 -0
  128. data/spec/configuration/database/mongodb_spec.rb +56 -0
  129. data/spec/configuration/database/mysql_spec.rb +53 -0
  130. data/spec/configuration/database/postgresql_spec.rb +53 -0
  131. data/spec/configuration/database/redis_spec.rb +50 -0
  132. data/spec/configuration/database/riak_spec.rb +35 -0
  133. data/spec/configuration/encryptor/gpg_spec.rb +26 -0
  134. data/spec/configuration/encryptor/open_ssl_spec.rb +35 -0
  135. data/spec/configuration/notifier/base_spec.rb +32 -0
  136. data/spec/configuration/notifier/campfire_spec.rb +32 -0
  137. data/spec/configuration/notifier/hipchat_spec.rb +44 -0
  138. data/spec/configuration/notifier/mail_spec.rb +71 -0
  139. data/spec/configuration/notifier/presently_spec.rb +35 -0
  140. data/spec/configuration/notifier/prowl_spec.rb +29 -0
  141. data/spec/configuration/notifier/twitter_spec.rb +35 -0
  142. data/spec/configuration/storage/cloudfiles_spec.rb +41 -0
  143. data/spec/configuration/storage/dropbox_spec.rb +38 -0
  144. data/spec/configuration/storage/ftp_spec.rb +44 -0
  145. data/spec/configuration/storage/local_spec.rb +29 -0
  146. data/spec/configuration/storage/ninefold_spec.rb +32 -0
  147. data/spec/configuration/storage/rsync_spec.rb +41 -0
  148. data/spec/configuration/storage/s3_spec.rb +38 -0
  149. data/spec/configuration/storage/scp_spec.rb +41 -0
  150. data/spec/configuration/storage/sftp_spec.rb +41 -0
  151. data/spec/configuration/syncer/cloud_files_spec.rb +44 -0
  152. data/spec/configuration/syncer/rsync/base_spec.rb +33 -0
  153. data/spec/configuration/syncer/rsync/local_spec.rb +10 -0
  154. data/spec/configuration/syncer/rsync/pull_spec.rb +10 -0
  155. data/spec/configuration/syncer/rsync/push_spec.rb +43 -0
  156. data/spec/configuration/syncer/s3_spec.rb +38 -0
  157. data/spec/database/base_spec.rb +54 -0
  158. data/spec/database/mongodb_spec.rb +428 -0
  159. data/spec/database/mysql_spec.rb +335 -0
  160. data/spec/database/postgresql_spec.rb +278 -0
  161. data/spec/database/redis_spec.rb +260 -0
  162. data/spec/database/riak_spec.rb +108 -0
  163. data/spec/dependency_spec.rb +49 -0
  164. data/spec/encryptor/base_spec.rb +30 -0
  165. data/spec/encryptor/gpg_spec.rb +134 -0
  166. data/spec/encryptor/open_ssl_spec.rb +129 -0
  167. data/spec/errors_spec.rb +306 -0
  168. data/spec/logger_spec.rb +363 -0
  169. data/spec/model_spec.rb +649 -0
  170. data/spec/notifier/base_spec.rb +89 -0
  171. data/spec/notifier/campfire_spec.rb +199 -0
  172. data/spec/notifier/hipchat_spec.rb +188 -0
  173. data/spec/notifier/mail_spec.rb +280 -0
  174. data/spec/notifier/presently_spec.rb +181 -0
  175. data/spec/notifier/prowl_spec.rb +117 -0
  176. data/spec/notifier/twitter_spec.rb +132 -0
  177. data/spec/package_spec.rb +61 -0
  178. data/spec/packager_spec.rb +225 -0
  179. data/spec/pipeline_spec.rb +257 -0
  180. data/spec/spec_helper.rb +59 -0
  181. data/spec/splitter_spec.rb +120 -0
  182. data/spec/storage/base_spec.rb +160 -0
  183. data/spec/storage/cloudfiles_spec.rb +230 -0
  184. data/spec/storage/cycler_spec.rb +239 -0
  185. data/spec/storage/dropbox_spec.rb +370 -0
  186. data/spec/storage/ftp_spec.rb +247 -0
  187. data/spec/storage/local_spec.rb +235 -0
  188. data/spec/storage/ninefold_spec.rb +319 -0
  189. data/spec/storage/rsync_spec.rb +345 -0
  190. data/spec/storage/s3_spec.rb +221 -0
  191. data/spec/storage/scp_spec.rb +209 -0
  192. data/spec/storage/sftp_spec.rb +220 -0
  193. data/spec/syncer/base_spec.rb +22 -0
  194. data/spec/syncer/cloud_files_spec.rb +192 -0
  195. data/spec/syncer/rsync/base_spec.rb +118 -0
  196. data/spec/syncer/rsync/local_spec.rb +121 -0
  197. data/spec/syncer/rsync/pull_spec.rb +90 -0
  198. data/spec/syncer/rsync/push_spec.rb +327 -0
  199. data/spec/syncer/s3_spec.rb +192 -0
  200. data/spec/version_spec.rb +21 -0
  201. data/templates/cli/utility/archive +25 -0
  202. data/templates/cli/utility/compressor/bzip2 +7 -0
  203. data/templates/cli/utility/compressor/gzip +7 -0
  204. data/templates/cli/utility/compressor/lzma +7 -0
  205. data/templates/cli/utility/compressor/pbzip2 +7 -0
  206. data/templates/cli/utility/config +31 -0
  207. data/templates/cli/utility/database/mongodb +18 -0
  208. data/templates/cli/utility/database/mysql +21 -0
  209. data/templates/cli/utility/database/postgresql +17 -0
  210. data/templates/cli/utility/database/redis +16 -0
  211. data/templates/cli/utility/database/riak +11 -0
  212. data/templates/cli/utility/encryptor/gpg +12 -0
  213. data/templates/cli/utility/encryptor/openssl +9 -0
  214. data/templates/cli/utility/model.erb +23 -0
  215. data/templates/cli/utility/notifier/campfire +12 -0
  216. data/templates/cli/utility/notifier/hipchat +15 -0
  217. data/templates/cli/utility/notifier/mail +22 -0
  218. data/templates/cli/utility/notifier/presently +13 -0
  219. data/templates/cli/utility/notifier/prowl +11 -0
  220. data/templates/cli/utility/notifier/twitter +13 -0
  221. data/templates/cli/utility/splitter +7 -0
  222. data/templates/cli/utility/storage/cloud_files +22 -0
  223. data/templates/cli/utility/storage/dropbox +20 -0
  224. data/templates/cli/utility/storage/ftp +12 -0
  225. data/templates/cli/utility/storage/local +7 -0
  226. data/templates/cli/utility/storage/ninefold +9 -0
  227. data/templates/cli/utility/storage/rsync +11 -0
  228. data/templates/cli/utility/storage/s3 +19 -0
  229. data/templates/cli/utility/storage/scp +11 -0
  230. data/templates/cli/utility/storage/sftp +11 -0
  231. data/templates/cli/utility/syncer/cloud_files +48 -0
  232. data/templates/cli/utility/syncer/rsync_local +12 -0
  233. data/templates/cli/utility/syncer/rsync_pull +17 -0
  234. data/templates/cli/utility/syncer/rsync_push +17 -0
  235. data/templates/cli/utility/syncer/s3 +45 -0
  236. data/templates/general/links +11 -0
  237. data/templates/general/version.erb +2 -0
  238. data/templates/notifier/mail/failure.erb +9 -0
  239. data/templates/notifier/mail/success.erb +7 -0
  240. data/templates/notifier/mail/warning.erb +9 -0
  241. data/templates/storage/dropbox/authorization_url.erb +6 -0
  242. data/templates/storage/dropbox/authorized.erb +4 -0
  243. data/templates/storage/dropbox/cache_file_written.erb +10 -0
  244. metadata +311 -0
@@ -0,0 +1,176 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
+
5
+ describe Backup::CLI::Helpers do
6
+ let(:helpers) { Module.new.extend(Backup::CLI::Helpers) }
7
+
8
+ describe '#run' do
9
+ let(:stdin) { mock }
10
+ let(:stdout) { mock }
11
+ let(:stderr) { mock }
12
+ let(:process_status) { mock }
13
+
14
+ it 'should run the given command using POpen4' do
15
+ Open4.expects(:popen4).with('/path/to/command args').
16
+ returns([123, stdin, stdout, stderr])
17
+ Process.expects(:waitpid2).with(123).returns([123, process_status])
18
+ stdout.expects(:read).returns('stdout message')
19
+ stderr.expects(:read).returns('stderr message')
20
+
21
+ helpers.expects(:command_name).with('/path/to/command args').
22
+ returns('command')
23
+ helpers.expects(:raise_if_command_failed!).with(
24
+ 'command',
25
+ {:status => process_status,
26
+ :stdout => 'stdout message',
27
+ :stderr => 'stderr message',
28
+ :ignore_exit_codes => [0]}
29
+ )
30
+
31
+ helpers.run('/path/to/command args').should == 'stdout message'
32
+ end
33
+
34
+ it 'should accept ignore_exit_codes and add 0 to the list' do
35
+ Open4.expects(:popen4).with('/path/to/command args').
36
+ returns([123, stdin, stdout, stderr])
37
+ Process.expects(:waitpid2).with(123).returns([123, process_status])
38
+ stdout.expects(:read).returns('stdout message')
39
+ stderr.expects(:read).returns('stderr message')
40
+
41
+ helpers.expects(:command_name).with('/path/to/command args').
42
+ returns('command')
43
+ helpers.expects(:raise_if_command_failed!).with(
44
+ 'command',
45
+ {:status => process_status,
46
+ :stdout => 'stdout message',
47
+ :stderr => 'stderr message',
48
+ :ignore_exit_codes => [1, 2, 0]}
49
+ )
50
+
51
+ helpers.run(
52
+ '/path/to/command args', :ignore_exit_codes => [1, 2]
53
+ ).should == 'stdout message'
54
+ end
55
+ end
56
+
57
+ describe '#utility' do
58
+ context 'when a system path for the utility is available' do
59
+ it 'should return the system path with newline removed' do
60
+ helpers.expects(:`).with('which foo 2>/dev/null').returns("system_path\n")
61
+ helpers.utility(:foo).should == 'system_path'
62
+ end
63
+
64
+ it 'should cache the returned path' do
65
+ helpers.expects(:`).once.with('which cache_me 2>/dev/null').
66
+ returns("cached_path\n")
67
+
68
+ helpers.utility(:cache_me).should == 'cached_path'
69
+ helpers.utility(:cache_me).should == 'cached_path'
70
+ end
71
+
72
+ it 'should cache the value for all extended objects' do
73
+ helpers.expects(:`).once.with('which once_only 2>/dev/null').
74
+ returns("cached_path\n")
75
+
76
+ helpers.utility(:once_only).should == 'cached_path'
77
+ Class.new.extend(Backup::CLI::Helpers).utility(:once_only).
78
+ should == 'cached_path'
79
+ end
80
+ end
81
+
82
+
83
+ context 'when a system path for the utility is not available' do
84
+ it 'should raise an error' do
85
+ helpers.expects(:`).with('which unknown 2>/dev/null').returns("\n")
86
+
87
+ expect do
88
+ helpers.utility(:unknown)
89
+ end.to raise_error(Backup::Errors::CLI::UtilityNotFoundError) {|err|
90
+ err.message.should match(/Path to 'unknown' could not be found/)
91
+ }
92
+ end
93
+
94
+ it 'should not cache any value for the utility' do
95
+ helpers.expects(:`).with('which not_cached 2>/dev/null').twice.returns("\n")
96
+
97
+ expect do
98
+ helpers.utility(:not_cached)
99
+ end.to raise_error(Backup::Errors::CLI::UtilityNotFoundError) {|err|
100
+ err.message.should match(/Path to 'not_cached' could not be found/)
101
+ }
102
+
103
+ expect do
104
+ helpers.utility(:not_cached)
105
+ end.to raise_error(Backup::Errors::CLI::UtilityNotFoundError) {|err|
106
+ err.message.should match(/Path to 'not_cached' could not be found/)
107
+ }
108
+ end
109
+ end
110
+ end # describe '#utility'
111
+
112
+ describe '#command_name' do
113
+ context 'given a command line path with no arguments' do
114
+ it 'should return the base command name' do
115
+ cmd = '/path/to/a/command'
116
+ helpers.command_name(cmd).should == 'command'
117
+ end
118
+ end
119
+
120
+ context 'given a command line path with a single argument' do
121
+ it 'should return the base command name' do
122
+ cmd = '/path/to/a/command with_args'
123
+ helpers.command_name(cmd).should == 'command'
124
+ end
125
+ end
126
+
127
+ context 'given a command line path with multiple arguments' do
128
+ it 'should return the base command name' do
129
+ cmd = '/path/to/a/command with multiple args'
130
+ helpers.command_name(cmd).should == 'command'
131
+ end
132
+ end
133
+
134
+ context 'given a command with no path and arguments' do
135
+ it 'should return the base command name' do
136
+ cmd = 'command args'
137
+ helpers.command_name(cmd).should == 'command'
138
+ end
139
+ end
140
+
141
+ context 'given a command with no path and no arguments' do
142
+ it 'should return the base command name' do
143
+ cmd = 'command'
144
+ helpers.command_name(cmd).should == 'command'
145
+ end
146
+ end
147
+ end # describe '#command_name'
148
+
149
+ describe '#raise_if_command_failed!' do
150
+
151
+ it 'returns nil if status exit code is in ignore_exit_codes' do
152
+ process_data = { :status => '3', :ignore_exit_codes => [1,3,5] }
153
+ helpers.raise_if_command_failed!('foo', process_data).should be_nil
154
+ end
155
+
156
+ it 'raises an error with stdout/stderr data' do
157
+ process_data = { :status => '3', :ignore_exit_codes => [2,4,6],
158
+ :stdout => 'stdout data', :stderr => 'stderr data' }
159
+
160
+ expect do
161
+ helpers.raise_if_command_failed!('utility_name', process_data)
162
+ end.to raise_error(
163
+ Backup::Errors::CLI::SystemCallError,
164
+ "CLI::SystemCallError: Failed to run utility_name on #{RUBY_PLATFORM}\n" +
165
+ " The following information should help to determine the problem:\n" +
166
+ " Exit Code: 3\n" +
167
+ " STDERR:\n" +
168
+ " stderr data\n" +
169
+ " STDOUT:\n" +
170
+ " stdout data"
171
+ )
172
+ end
173
+
174
+ end
175
+
176
+ end
@@ -0,0 +1,363 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
+
5
+ describe 'Backup::CLI::Utility' do
6
+ let(:cli) { Backup::CLI::Utility }
7
+ let(:utility) { Backup::CLI::Utility.new }
8
+ let(:s) { sequence '' }
9
+
10
+ before { @argv_save = ARGV }
11
+ after { ARGV.replace(@argv_save) }
12
+
13
+ describe '#perform' do
14
+ let(:model_a) { Backup::Model.new(:test_trigger_a, 'test label a') }
15
+ let(:model_b) { Backup::Model.new(:test_trigger_b, 'test label b') }
16
+
17
+ before { Backup::Model.all.push(model_a, model_b) }
18
+ after { Backup::Model.all.clear }
19
+
20
+ it 'should perform the backup for the given trigger' do
21
+ Backup::Logger.expects(:quiet=).in_sequence(s)
22
+ Backup::Config.expects(:update).in_sequence(s)
23
+ Backup::Config.expects(:load_config!).in_sequence(s)
24
+
25
+ FileUtils.expects(:mkdir_p).in_sequence(s).with(Backup::Config.log_path)
26
+ FileUtils.expects(:mkdir_p).in_sequence(s).with(Backup::Config.cache_path)
27
+ FileUtils.expects(:mkdir_p).in_sequence(s).with(Backup::Config.tmp_path)
28
+
29
+ Backup::Logger.expects(:truncate!)
30
+
31
+ model_a.expects(:prepare!).in_sequence(s)
32
+ model_a.expects(:perform!).in_sequence(s)
33
+ Backup::Logger.expects(:clear!).in_sequence(s)
34
+
35
+ expect do
36
+ ARGV.replace(['perform', '-t', 'test_trigger_a'])
37
+ cli.start
38
+ end.not_to raise_error
39
+ end
40
+
41
+ it 'should perform backups for the multiple triggers' do
42
+ Backup::Logger.expects(:quiet=).in_sequence(s)
43
+ Backup::Config.expects(:update).in_sequence(s)
44
+ Backup::Config.expects(:load_config!).in_sequence(s)
45
+
46
+ FileUtils.expects(:mkdir_p).in_sequence(s).with(Backup::Config.log_path)
47
+ FileUtils.expects(:mkdir_p).in_sequence(s).with(Backup::Config.cache_path)
48
+ FileUtils.expects(:mkdir_p).in_sequence(s).with(Backup::Config.tmp_path)
49
+
50
+ Backup::Logger.expects(:truncate!)
51
+
52
+ model_a.expects(:prepare!).in_sequence(s)
53
+ model_a.expects(:perform!).in_sequence(s)
54
+ Backup::Logger.expects(:clear!).in_sequence(s)
55
+
56
+ model_b.expects(:prepare!).in_sequence(s)
57
+ model_b.expects(:perform!).in_sequence(s)
58
+ Backup::Logger.expects(:clear!).in_sequence(s)
59
+
60
+ expect do
61
+ ARGV.replace(['perform', '-t', 'test_trigger_a,test_trigger_b'])
62
+ cli.start
63
+ end.not_to raise_error
64
+ end
65
+
66
+ context 'when errors occur' do
67
+ it 'should log the error and exit' do
68
+ Backup::Logger.stubs(:quiet=).raises(SystemCallError, 'yikes!')
69
+ Backup::Logger.expects(:error).with do |err|
70
+ err.message.should ==
71
+ "CLIError: SystemCallError: unknown error - yikes!"
72
+ end
73
+
74
+ expect do
75
+ ARGV.replace(['perform', '-t', 'foo'])
76
+ cli.start
77
+ end.to raise_error(SystemExit) {|exit| exit.status.should == 1 }
78
+ end
79
+ end # context 'when errors occur'
80
+
81
+ end # describe '#perform'
82
+
83
+ describe '#generate:model' do
84
+ before do
85
+ FileUtils.unstub(:mkdir_p)
86
+ FileUtils.unstub(:touch)
87
+ end
88
+
89
+ context 'when given a config_path' do
90
+ context 'when no config file exists' do
91
+ it 'should create both a config and a model under the given path' do
92
+ Dir.mktmpdir do |path|
93
+ model_file = File.join(path, 'custom', 'models', 'test_trigger.rb')
94
+ config_file = File.join(path, 'custom', 'config.rb')
95
+
96
+ out, err = capture_io do
97
+ ARGV.replace(['generate:model',
98
+ '--config-path', File.join(path, 'custom'),
99
+ '--trigger', 'test_trigger'
100
+ ])
101
+ cli.start
102
+ end
103
+
104
+ out.should == "Generated model file: '#{ model_file }'.\n" +
105
+ "Generated configuration file: '#{ config_file }'.\n"
106
+ File.exist?(model_file).should be_true
107
+ File.exist?(config_file).should be_true
108
+ end
109
+ end
110
+ end
111
+
112
+ context 'when a config file already exists' do
113
+ it 'should only create a model under the given path' do
114
+ Dir.mktmpdir do |path|
115
+ model_file = File.join(path, 'custom', 'models', 'test_trigger.rb')
116
+ config_file = File.join(path, 'custom', 'config.rb')
117
+ FileUtils.mkdir_p(File.join(path, 'custom'))
118
+ FileUtils.touch(config_file)
119
+
120
+ out, err = capture_io do
121
+ ARGV.replace(['generate:model',
122
+ '--config-path', File.join(path, 'custom'),
123
+ '--trigger', 'test_trigger'
124
+ ])
125
+ cli.start
126
+ end
127
+
128
+ out.should == "Generated model file: '#{ model_file }'.\n"
129
+ File.exist?(model_file).should be_true
130
+ end
131
+ end
132
+ end
133
+
134
+ # These pass, but generate Thor warnings...
135
+ #
136
+ # context 'when a model file already exists' do
137
+ # it 'should prompt to overwrite the model under the given path' do
138
+ # Dir.mktmpdir do |path|
139
+ # model_file = File.join(path, 'models', 'test_trigger.rb')
140
+ # config_file = File.join(path, 'config.rb')
141
+ #
142
+ # cli.any_instance.expects(:overwrite?).with(model_file).returns(false)
143
+ #
144
+ # out, err = capture_io do
145
+ # ARGV.replace(['generate:model',
146
+ # '--config-path', path,
147
+ # '--trigger', 'test_trigger'
148
+ # ])
149
+ # cli.start
150
+ # end
151
+ #
152
+ # out.should == "Generated configuration file: '#{ config_file }'.\n"
153
+ # File.exist?(config_file).should be_true
154
+ # File.exist?(model_file).should be_false
155
+ # end
156
+ # end
157
+ # end
158
+
159
+ end # context 'when given a config_path'
160
+
161
+ context 'when not given a config_path' do
162
+ it 'should create both a config and a model under the root path' do
163
+ Dir.mktmpdir do |path|
164
+ Backup::Config.update(:root_path => path)
165
+ model_file = File.join(path, 'models', 'test_trigger.rb')
166
+ config_file = File.join(path, 'config.rb')
167
+
168
+ out, err = capture_io do
169
+ ARGV.replace(['generate:model', '--trigger', 'test_trigger'])
170
+ cli.start
171
+ end
172
+
173
+ out.should == "Generated model file: '#{ model_file }'.\n" +
174
+ "Generated configuration file: '#{ config_file }'.\n"
175
+ File.exist?(model_file).should be_true
176
+ File.exist?(config_file).should be_true
177
+ end
178
+ end
179
+ end
180
+
181
+ it 'should generate the proper help output' do
182
+ ruby19_output = <<-EOS
183
+ Usage:
184
+ #{ File.basename($0) } generate:model --trigger=TRIGGER
185
+
186
+ Options:
187
+ --trigger=TRIGGER
188
+ [--config-path=CONFIG_PATH] # Path to your Backup configuration directory
189
+ [--databases=DATABASES] # (mongodb, mysql, postgresql, redis, riak)
190
+ [--storages=STORAGES] # (cloud_files, dropbox, ftp, local, ninefold, rsync, s3, scp, sftp)
191
+ [--syncers=SYNCERS] # (cloud_files, rsync_local, rsync_pull, rsync_push, s3)
192
+ [--encryptors=ENCRYPTORS] # (gpg, openssl)
193
+ [--compressors=COMPRESSORS] # (bzip2, gzip, lzma, pbzip2)
194
+ [--notifiers=NOTIFIERS] # (campfire, hipchat, mail, presently, prowl, twitter)
195
+ [--archives]
196
+ [--splitter] # use `--no-splitter` to disable
197
+ # Default: true
198
+ Generates a Backup model file
199
+
200
+ Note:
201
+ '--config-path' is the path to the directory where 'config.rb' is located.
202
+ The model file will be created as '<config_path>/models/<trigger>.rb'
203
+ Default: #{ Backup::Config.root_path }
204
+ EOS
205
+
206
+ out, err = capture_io do
207
+ ARGV.replace(['help', 'generate:model'])
208
+ cli.start
209
+ end
210
+
211
+ expected_lines = ruby19_output.split("\n").map(&:strip).select {|e| !e.empty? }
212
+ output_lines = out.split("\n").map(&:strip).select {|e| !e.empty? }
213
+
214
+ output_lines.sort.should == expected_lines.sort
215
+ end
216
+ end
217
+
218
+ describe '#generate:config' do
219
+ before do
220
+ FileUtils.unstub(:mkdir_p)
221
+ FileUtils.unstub(:touch)
222
+ end
223
+
224
+ context 'when given a config_path' do
225
+ it 'should create a config file in the given path' do
226
+ Dir.mktmpdir do |path|
227
+ config_file = File.join(path, 'custom', 'config.rb')
228
+
229
+ out, err = capture_io do
230
+ ARGV.replace(['generate:config',
231
+ '--config-path', File.join(path, 'custom'),
232
+ ])
233
+ cli.start
234
+ end
235
+
236
+ out.should == "Generated configuration file: '#{ config_file }'.\n"
237
+ File.exist?(config_file).should be_true
238
+ end
239
+ end
240
+ end
241
+
242
+ context 'when not given a config_path' do
243
+ it 'should create a config file in the root path' do
244
+ Dir.mktmpdir do |path|
245
+ Backup::Config.update(:root_path => path)
246
+ config_file = File.join(path, 'config.rb')
247
+
248
+ out, err = capture_io do
249
+ ARGV.replace(['generate:config'])
250
+ cli.start
251
+ end
252
+
253
+ out.should == "Generated configuration file: '#{ config_file }'.\n"
254
+ File.exist?(config_file).should be_true
255
+ end
256
+ end
257
+ end
258
+
259
+ # These pass, but generate Thor warnings...
260
+ #
261
+ # context 'when a config file already exists' do
262
+ # it 'should prompt to overwrite the config file' do
263
+ # Dir.mktmpdir do |path|
264
+ # Backup::Config.update(:root_path => path)
265
+ # config_file = File.join(path, 'config.rb')
266
+ #
267
+ # cli.any_instance.expects(:overwrite?).with(config_file).returns(false)
268
+ #
269
+ # out, err = capture_io do
270
+ # ARGV.replace(['generate:config'])
271
+ # cli.start
272
+ # end
273
+ #
274
+ # out.should be_empty
275
+ # File.exist?(config_file).should be_false
276
+ # end
277
+ # end
278
+ # end
279
+
280
+ end # describe '#generate:config'
281
+
282
+ describe '#decrypt' do
283
+
284
+ # These pass, but generate Thor warnings...
285
+ #
286
+ # it 'should perform OpenSSL decryption' do
287
+ # ARGV.replace(['decrypt', '--encryptor', 'openssl',
288
+ # '--in', 'in_file',
289
+ # '--out', 'out_file',
290
+ # '--base64', '--salt',
291
+ # '--password-file', 'pwd_file'])
292
+ #
293
+ # cli.any_instance.expects(:`).with(
294
+ # "openssl aes-256-cbc -d -base64 -pass file:pwd_file -salt " +
295
+ # "-in 'in_file' -out 'out_file'"
296
+ # )
297
+ # cli.start
298
+ # end
299
+ #
300
+ # it 'should perform GnuPG decryption' do
301
+ # ARGV.replace(['decrypt', '--encryptor', 'gpg',
302
+ # '--in', 'in_file',
303
+ # '--out', 'out_file'])
304
+ #
305
+ # cli.any_instance.expects(:`).with(
306
+ # "gpg -o 'out_file' -d 'in_file'"
307
+ # )
308
+ # cli.start
309
+ # end
310
+
311
+ it 'should show a message if given an invalid encryptor' do
312
+ ARGV.replace(['decrypt', '--encryptor', 'foo',
313
+ '--in', 'in_file',
314
+ '--out', 'out_file'])
315
+ out, err = capture_io do
316
+ cli.start
317
+ end
318
+ err.should == ''
319
+ out.should == "Unknown encryptor: foo\n" +
320
+ "Use either 'openssl' or 'gpg'.\n"
321
+ end
322
+ end
323
+
324
+ # would have the same Thor warnings issues...
325
+ # describe '#dependencies' do
326
+ # end
327
+
328
+ describe '#version' do
329
+ it 'should output the current version' do
330
+ utility.expects(:puts).with("Backup #{ Backup::Version.current }")
331
+ utility.version
332
+ end
333
+
334
+ it 'should output the current version for "-v"' do
335
+ ARGV.replace ['-v']
336
+ out, err = capture_io do
337
+ cli.start
338
+ end
339
+ out.should == "Backup #{ Backup::Version.current }\n"
340
+ end
341
+ end
342
+
343
+ describe '#overwrite?' do
344
+ context 'when the path exists' do
345
+ before { File.expects(:exist?).returns(true) }
346
+
347
+ it 'should prompt user' do
348
+ utility.expects(:yes?).with(
349
+ "A file already exists at 'a/path'. Do you want to overwrite? [y/n]"
350
+ ).returns(:response)
351
+ utility.send(:overwrite?, 'a/path').should == :response
352
+ end
353
+ end
354
+
355
+ context 'when the path does not exist' do
356
+ before { File.expects(:exist?).returns(false) }
357
+ it 'should return true' do
358
+ utility.expects(:yes?).never
359
+ utility.send(:overwrite?, 'a/path').should be_true
360
+ end
361
+ end
362
+ end
363
+ end