Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'develop'

  • Loading branch information...
commit 22b9e3aa71aeabc619bf702875ecc15ec93bc0b8 2 parents b88ff66 + 30d4d5c
@meskyanichi meskyanichi authored
Showing with 637 additions and 106 deletions.
  1. +0 −7 .infinity_test
  2. +0 −3  .rspec
  3. +8 −2 Gemfile
  4. +21 −10 Gemfile.lock
  5. +17 −0 Guardfile
  6. +87 −42 README.md
  7. +1 −9 backup.gemspec
  8. +6 −2 lib/backup.rb
  9. +1 −1  lib/backup/archive.rb
  10. +1 −1  lib/backup/cli.rb
  11. +64 −0 lib/backup/compressor/bzip2.rb
  12. +23 −0 lib/backup/configuration/compressor/bzip2.rb
  13. +25 −0 lib/backup/configuration/notifier/presently.rb
  14. +1 −1  lib/backup/encryptor/gpg.rb
  15. +105 −0 lib/backup/notifier/presently.rb
  16. +2 −6 lib/backup/storage/s3.rb
  17. +6 −4 lib/backup/syncer/s3.rb
  18. +1 −1  lib/backup/version.rb
  19. +3 −0  lib/templates/archive
  20. +7 −0 lib/templates/compressor/bzip2
  21. +3 −0  lib/templates/compressor/gzip
  22. +3 −0  lib/templates/database/mongodb
  23. +3 −0  lib/templates/database/mysql
  24. +4 −1 lib/templates/database/postgresql
  25. +3 −0  lib/templates/database/redis
  26. +3 −0  lib/templates/encryptor/gpg
  27. +3 −0  lib/templates/encryptor/openssl
  28. +3 −0  lib/templates/notifier/campfire
  29. +3 −0  lib/templates/notifier/mail
  30. +12 −0 lib/templates/notifier/presently
  31. +3 −0  lib/templates/notifier/twitter
  32. +1 −1  lib/templates/readme
  33. +3 −0  lib/templates/storage/cloudfiles
  34. +3 −0  lib/templates/storage/dropbox
  35. +3 −0  lib/templates/storage/ftp
  36. +3 −0  lib/templates/storage/rsync
  37. +14 −1 lib/templates/storage/s3
  38. +3 −0  lib/templates/storage/scp
  39. +3 −0  lib/templates/storage/sftp
  40. +3 −0  lib/templates/syncer/rsync
  41. +3 −0  lib/templates/syncer/s3
  42. +4 −4 spec/archive_spec.rb
  43. +59 −0 spec/compressor/bzip2_spec.rb
  44. +10 −10 spec/encryptor/gpg_spec.rb
  45. +99 −0 spec/notifier/presently_spec.rb
  46. +4 −0 spec/spec_helper.rb
View
7 .infinity_test
@@ -1,7 +0,0 @@
-infinity_test do
- heuristics do
- add('lib/') do |file|
- run :all => :tests
- end
- end
-end
View
3  .rspec
@@ -1,3 +0,0 @@
---format Fuubar
---color
---tty
View
10 Gemfile
@@ -19,7 +19,13 @@ end
group :test do
gem 'rspec'
gem 'mocha'
- gem 'infinity_test'
- gem 'fuubar'
gem 'timecop'
+ gem 'fuubar'
+
+ gem 'guard'
+ gem 'guard-rspec'
+ gem 'rb-fsevent' # guard notifications for osx
+ gem 'growl' # $ brew install growlnotify
+ gem 'rb-inotify' # guard notifications for linux
+ gem 'libnotify' # $ apt-get install ???
end
View
31 Gemfile.lock
@@ -18,6 +18,7 @@ GEM
rack (< 2, >= 1.1.0)
faraday_middleware (0.3.2)
faraday (~> 0.5.4)
+ ffi (1.0.9)
fog (0.7.0)
builder
excon (>= 0.5.5)
@@ -28,18 +29,21 @@ GEM
nokogiri (>= 1.4.4)
ruby-hmac
formatador (0.1.1)
- fuubar (0.0.3)
+ fuubar (0.0.5)
rspec (~> 2.0)
rspec-instafail (~> 0.1.4)
- ruby-progressbar (~> 0.0.9)
+ ruby-progressbar (~> 0.0.10)
+ growl (1.0.3)
+ guard (0.3.4)
+ thor (~> 0.14.6)
+ guard-rspec (0.3.1)
+ guard (>= 0.2.2)
hashie (1.0.0)
httparty (0.7.4)
crack (= 0.1.8)
i18n (0.5.0)
- infinity_test (1.0.2)
- notifiers (>= 1.1.0)
- watchr (>= 0.7)
json (1.5.1)
+ libnotify (0.5.5)
mail (2.2.15)
activesupport (>= 2.3.6)
i18n (>= 0.4.0)
@@ -58,10 +62,12 @@ GEM
net-ssh (>= 2.0.9)
net-ssh (2.1.3)
nokogiri (1.4.4)
- notifiers (1.1.0)
oauth (0.4.4)
polyglot (0.3.1)
rack (1.2.2)
+ rb-fsevent (0.4.0)
+ rb-inotify (0.8.5)
+ ffi (>= 0.5.0)
rspec (2.5.0)
rspec-core (~> 2.5.0)
rspec-expectations (~> 2.5.0)
@@ -69,11 +75,12 @@ GEM
rspec-core (2.5.1)
rspec-expectations (2.5.0)
diff-lcs (~> 1.1.2)
- rspec-instafail (0.1.6)
+ rspec-instafail (0.1.7)
rspec-mocks (2.5.0)
ruby-hmac (0.4.0)
- ruby-progressbar (0.0.9)
+ ruby-progressbar (0.0.10)
simple_oauth (0.1.4)
+ thor (0.14.6)
timecop (0.3.5)
treetop (1.4.9)
polyglot (>= 0.3.1)
@@ -84,7 +91,6 @@ GEM
multi_json (~> 0.0.5)
multi_xml (~> 0.2.0)
simple_oauth (~> 0.1.3)
- watchr (0.7)
PLATFORMS
ruby
@@ -93,14 +99,19 @@ DEPENDENCIES
dropbox (~> 1.2.3)
fog (~> 0.7.0)
fuubar
+ growl
+ guard
+ guard-rspec
httparty (~> 0.7.4)
- infinity_test
json (~> 1.5.1)
+ libnotify
mail (~> 2.2.15)
mocha
net-scp (~> 1.0.4)
net-sftp (~> 2.0.5)
net-ssh (~> 2.1.3)
+ rb-fsevent
+ rb-inotify
rspec
timecop
twitter (~> 1.1.2)
View
17 Guardfile
@@ -0,0 +1,17 @@
+##
+# To run the test suite against all 3 rubies: 1.9.2, 1.8.7 and REE, simply run the following command:
+# $ guard start
+#
+# Be use you are using RVM and have Ruby 1.9.2, 1.8.7 and REE installed as well as all
+# Backup's gem dependencies for each of these Ruby intepreters.
+
+guard 'rspec',
+ :version => 2,
+ :rvm => ['1.9.2', '1.8.7', 'ree'],
+ :bundler => true,
+ :cli => '--color --format Fuubar --fail-fast' do
+
+ watch(%r{^spec/.+_spec\.rb})
+ watch(%r{^lib/(.+)\.rb}) { 'spec' }
+ watch('spec/spec_helper.rb') { 'spec' }
+end
View
129 README.md
@@ -1,15 +1,17 @@
Backup 3
========
-Backup is a RubyGem (for UNIX-like operating systems: Linux, Mac OSX) that allows you to configure and perform backups in a simple manner using an elegant Ruby DSL. It supports various databases (MySQL, PostgreSQL, MongoDB and Redis), it supports various storage locations (Amazon S3, Rackspace Cloud Files, Dropbox, any remote server through FTP, SFTP, SCP and RSync), it provide Syncers (RSync, S3) for efficient backups, it can archive files and directories, it can cycle backups, it can do incremental backups, it can compress backups, it can encrypt backups (OpenSSL or GPG), it can notify you about successful and/or failed backups (Email, Twitter or Campfire). It is very extensible and easy to add new functionality to. It's easy to use.
+Backup is a RubyGem, written for Linux and Mac OSX, that allows you to easily perform backup operations on both your remote, as well as your local environment. It provides you with an elegant DSL in Ruby for modeling (configuring) your backups. Backup has built-in support for various databases, storage protocols/services, syncers, compressors, encryptors and notifiers which you can mix and match. It was built with modularity, extensibility and simplicity in mind.
+
Author
------
-**Michael van Rooijen ( [@meskyanichi](http://twitter.com/#!/meskyanichi) )**
+**[Michael van Rooijen](http://michaelvanrooijen.com/) ( [@meskyanichi](http://twitter.com/#!/meskyanichi) )**
Drop me a message for any questions, suggestions, requests, bugs or submit them to the [issue log](https://github.com/meskyanichi/backup/issues).
+
Installation
------------
@@ -27,7 +29,7 @@ I recommend you read this README first, and refer to the [Wiki pages](https://gi
What Backup 3 currently supports
================================
-**Below you find a summary of what the Backup gem currently supports. Each of the items below is more or less isolated from each other, meaning that adding new databases, storage locations, compressors, encryptors, notifiers, and such is relatively easy to do.**
+Below you find a list of components that Backup currently supports. Each of these compontents is isolated, meaning that adding new databases, storage location / service, compressor, encryptor or notifier is easy to do.
Database Support
----------------
@@ -47,8 +49,8 @@ Filesystem Support
[Archive Wiki Page](https://github.com/meskyanichi/backup/wiki/Archives)
-Storage Locations
------------------
+Storage Locations and Services
+------------------------------
- Amazon Simple Storage Service (S3)
- Rackspace Cloud Files (Mosso)
@@ -82,6 +84,7 @@ Compressors
-----------
- Gzip
+- Bzip2
[Compressors Wiki Page](https://github.com/meskyanichi/backup/wiki/Compressors)
@@ -99,6 +102,7 @@ Notifiers
- Mail
- Twitter
- Campfire
+- Presently
[Notifiers Wiki Page](https://github.com/meskyanichi/backup/wiki/Notifiers)
@@ -109,21 +113,11 @@ Supported Ruby versions (Tested with RSpec)
- Ruby 1.8.7
- Ruby Enterprise Edition 1.8.7
-Environments
-------------
-
-Backup **3** runs in **UNIX**-based operating systems: Linux, Mac OSX, etc. It does **NOT** run on the Windows operating system, and there are currently no plans to support it.
-
-Compatibility
--------------
-Backup **3** is **NOT** backwards compatible with Backup **2**. The command line interface has changed. The DSL has changed. And a lot more has changed. All for the better.
+A sample Backup configuration file
+==================================
-
-A sample "Backup" configuration file
-====================================
-
-Below you see a sample configuration file you could create for Backup 3. Just read through it slowly and I'm quite sure you will already know what's going to happen before I explain it to you. **(see explanation after the example)**
+This is a Backup configuration file. Check it out and read the explanation below. Backup has a [great wiki](https://github.com/meskyanichi/backup/wiki) which explains each component of Backup in detail.
Backup::Model.new(:sample_backup, 'A sample backup configuration') do
@@ -191,45 +185,33 @@ Below you see a sample configuration file you could create for Backup 3. Just re
end
-### Explanation for the above example
-
-First it dumps all the tables inside the MySQL database "my_sample_mysql_db", except for the "logs" table. It also dumps the MongoDB database "my_sample_mongo_db", but only the collections "users", "events" and "posts". After that it'll create a "user_avatars.tar" archive with all the uploaded avatars of the users. After that it'll create a "logs.tar" archive with the "production.log", "newrelic_agent.log" and "other.log" logs. After that it'll compress the backup file using Gzip (with the mode set to "best", rather than "fast" for best compression). After that it'll encrypt the whole backup file (everything included: databases, archives) using "OpenSSL". Now the Backup can only be extracted when you know the password to decrypt it ("my_secret_password" in this case). Then it'll store the backup file to Amazon S3 in to 'my_bucket/backups'. Next, we're going to use the S3 Syncer to create a mirror of the `/var/apps/my_app/public/videos` and `/var/apps/my_app/public/music` directories on Amazon S3. (This will not package, compress, encrypt - but will directly sync the specified directories "as is" to your S3 bucket). Finally, it'll notify me by email if the backup raises an error/exception during the process, indicating that something went wrong. However, it does not notify me by email when successful backups occur because I set `mail.on_success` to `false`. It'll also notify me by Twitter when failed backups occur, but also when successful ones occur because I set the `tweet.on_success` to `true`.
-
-### Things to note
-
-The __keep__ option I passed in to the S3 storage location enables "Backup Cycling". In this case, after the 21st backup file gets pushed, it'll exceed the 20 backup limit, and remove the oldest backup from the S3 bucket.
+### Brief explanation for the above example configuration
-The __S3__ Syncer ( `sync_with` ) is a different kind of __Storage__ method. As mentioned above, it does not follow the same procedure as the __Storage__ ( `store_with` ) method. A Storage method stores the final result of a copied/organized/packaged/compressed/encrypted file to the desired remote location. A Syncer directly syncs the specified directories and **completely bypasses** the copy/organize/package/compress/encrypt process. This is especially good for backing up directories containing gigabytes of data, such as images, music, videos, and similar large formats. Also, rather than transferring the whole directory every time, it'll only transfer files in all these directories that have been modified or added, thus, saving huge amounts of bandwidth, cpu load and time. You're also not bound to the 5GB per file restriction like the **Storage** method, unless you actually have files in these directories that are >= 5GB, which often is unlikely. Even if the whole directory (and sub-directories) are > 5GB (split over multiple files), it shouldn't be a problem as long as you don't have any *single* file that is 5GB in size. Also, in the above example you see `s3.mirror = true`, this tells the S3 Syncer to keep a "mirror" of the local directories in the S3 bucket. This means that if you delete a file locally, the next time it syncs, it'll also delete the file from the S3 bucket, keeping the local filesystem 1:1 with the S3 bucket.
+It will dump two databases (MySQL and MongoDB), it'll create two (.t)archives (user_avatars and logs). It'll package the two database and two archives together in a single (.t)archive. It'll run the Gzip compressor to compress that archive, and then it'll run the OpenSSL encryptor to encrypt the compressed archive. Then that encrypted archive will be stored to your Amazon S3 account. If all goes well, and no exceptions are raised, you'll be notified via the Twitter notifier that the backup succeeded. If there was an exception raised during the backup process, then you'd receive an email in your inbox containing detailed exception information, as well as receive a simple Twitter message that something went wrong.
-The __Mail__ notifier. I have not provided the SMTP options to use my Gmail account to notify myself when exceptions are raised during the process. So this won't work, check out the wiki on how to configure this. I left it out in this example.
+As you can see, you can freely mix and match **archives**, **databases**, **compressors**, **encryptors**, **storages** and **notifiers** for your backups. You could even specify 3 storage locations: Amazon S3, Rackspace Cloud Files and Dropbox, it'd then store your packaged backup to 3 separate locations for high redundancy. This also applies to encryptors, you could double encrypt your backup with OpenSSL followed by GPG if you wanted.
-The __Twitter__ notifier. You will require your consumer and oauth credentials, which I have also left out of this example.
+Additionally we have also defined a **S3 Syncer** ( `sync_with S3` ), which does not follow the above process of archiving/compression/encryption, but instead will directly sync the whole `videos` and `music` folder structures from your machine to your Amazon S3 account. (very efficient and cost-effective since it will only transfer files that were changed!)
-MongoDB backup utility (mongodump) by default does not fsync & lock the database, opening a possibility for inconsistent data dump. This is addressed by setting lock = true which causes mongodump to be wrapped with lock&fsync calls (with a lock takedown after the dump). Please check the Wiki on this subject and remember this is a very fresh feature, needing some more real-world testing. Disabled at default.
-
-Check out the Wiki for more information on all the above subjects.
-
-### And that's it!
-
-So as you can see the DSL is straightforward and should be simple to understand and extend to your needs. You can have as many databases, archives, storage locations, syncers, compressors, encryptors and notifiers inside the above example as you need and it'll bundle all of it up in a nice packaged archive and transfer it to every specified location (as redundant as you like).
+There are more **archives**, **databases**, **compressors**, **encryptors**, **storages** and **notifiers** than displayed in the example, all available components are listed at the top of this README, as well as in the [Wiki](https://github.com/meskyanichi/backup/wiki).
### Running the example
-Remember the `Backup::Model.new(:sample_backup, 'A sample backup configuration') do`?
-The `:sample_backup` is called the "id", or "trigger". This is used to identify the backup procedure/file and initialize it.
+Notice the `Backup::Model.new(:sample_backup, 'A sample backup configuration') do` at the top of the above example. The `:sample_backup` is called the **trigger**. This is used to identify the backup procedure/file and initialize it.
- backup perform -t sample_backup
+ backup perform -t [--trigger] sample_backup
-That's it.
+Now it'll run the backup, it's as simple as that.
### Automatic backups
-Since it's a simple command line utility, just write a cron to invoke it whenever you want. I recommend you use the [Whenever Gem](https://github.com/javan/whenever) to manage your cron tasks. It'll enable you to write such elegant automatic backup syntax in Ruby:
+Since Backup is a simple command line utility, you should write a crontask to invoke it periodically. I recommend you use [Whenever](https://github.com/javan/whenever) to manage your crontab. It'll allow you to write to the crontab in pure Ruby, it provides an elegant DSL to do so, for example:
every 6.hours do
- command "backup perform -t sample_backup"
+ command "backup perform --trigger sample_backup"
end
+With this in place, run `whenever --update-crontab backup` to write this Ruby syntax to the crontab in cron-syntax. The operating system will now invoke `backup perform --trigger sample_backup` every 6 hours. Check out the Whenever project page for more information.
Documentation
-------------
@@ -266,8 +248,41 @@ Contributors
<td><a href="https://github.com/szimmermann" target="_blank">Stefan Zimmermann ( szimmermann )</a></td>
<td>Enabling package/archive (tar utility) support for more Linux distro's (FreeBSD, etc)</td>
</tr>
+ <tr>
+ <td><a href="https://github.com/trystant" target="_blank">Mark Nyon ( trystant )</a></td>
+ <td>Helping discuss MongoDump Lock/FSync problem</td>
+ </tr>
+ <tr>
+ <td><a href="https://github.com/imanel" target="_blank">Bernard Potocki ( imanel )</a></td>
+ <td>Helping discuss MongoDump Lock/FSync problem + Submitting a patch</td>
+ </tr>
+ <tr>
+ <td><a href="https://github.com/tomash" target="_blank">Tomasz Stachewicz ( tomash )</a></td>
+ <td>Helping discuss MongoDump Lock/FSync problem + Submitting a patch</td>
+ </tr>
+ <tr>
+ <td><a href="https://github.com/lapluviosilla" target="_blank">Paul Strong ( lapluviosilla )</a></td>
+ <td>Helping discuss MongoDump Lock/FSync problem</td>
+ </tr>
+ <tr>
+ <td><a href="https://github.com/rgnitz" target="_blank">Ryan ( rgnitz )</a></td>
+ <td>Helping discuss MongoDump Lock/FSync problem</td>
+ </tr>
+ <tr>
+ <td><a href="https://github.com/tsigo" target="_blank">Robert Speicher ( tsigo )</a></td>
+ <td>Adding the --quiet [-q] feature to Backup to silence console logging</td>
+ </tr>
+ <tr>
+ <td><a href="https://github.com/jwhitcraft" target="_blank">Jon Whitcraft ( jwhitcraft )</a></td>
+ <td>Adding the ability to add additional options to the S3Syncer</td>
+ </tr>
+ <tr>
+ <td><a href="https://github.com/bgarret" target="_blank">Benoit Garret ( bgarret )</a></td>
+ <td>Presently notifier</td>
+ </tr>
</table>
+
Want to contribute?
-------------------
@@ -280,8 +295,38 @@ Want to contribute?
I can't guarantee I'll pull every pull request. Also, I may accept your pull request and drastically change parts to improve readability/maintainability. Feel free to discuss about improvements, new functionality/features in the [issue log](https://github.com/meskyanichi/backup/issues) before contributing if you need/want more information.
+Easily run tests against all three Ruby versions
+------------------------------------------------
+
+Install [RVM](https://rvm.beginrescueend.com/) and use it to install Ruby 1.9.2, 1.8.7 and REE.
+
+ rvm install 1.9.2 && rvm install 1.8.7 && rvm install ree
+
+Once these are installed, go ahead and install all the necessary dependencies.
+
+ cd backup
+ rvm use 1.9.2 && gem install bundler && bundle install
+ rvm use 1.8.7 && gem install bundler && bundle install
+ rvm use ree && gem install bundler && bundle install
+
+The Backup gem uses [Guard](https://github.com/guard/guard) along with [Guard::RSpec](https://github.com/guard/guard-rspec) to quickly and easily test Backup's code against all three Rubies. If you've done the above, all you have to do is run:
+
+ guard start
+
+from Backup's root and that's it. It'll now test against all three Rubies each time you adjust a file in the `lib` or `spec` directories.
+
+
+Or contribute by writing blogs/tutorials
+----------------------------------------
+
+- http://erik.debill.org/2011/03/26/csing-backup-with-rails
+- http://blog.noizeramp.com/2011/03/31/backing-up-backup-ruby-gem/
+- http://www.sebaugereau.com/using-ruby-to-backup-with-beauty
+- http://outofti.me/post/4159686269/backup-with-pgbackups
+- http://h2ik.co/2011/03/backing-up-with-ruby/
+
Backup 2 - Issues, Wiki, Source, Gems
=====================================
-I won't actively support Backup 2 anymore. The source will remain on [a separate branch](https://github.com/meskyanichi/backup/tree/backup-2). [The Issues](https://github.com/meskyanichi/backup/issues) that belong to Backup 2 have been tagged with a black label "Backup 2". The Backup 2 specific [Wiki pages](https://github.com/meskyanichi/backup/wiki) have been prefixed with "Backup 2) <Article>". [The Backup 2 Gems](http://rubygems.org/gems/backup) will always remain so you can still use Backup 2. I might still accept pull requests, but would highly encourage anyone to [move to __Backup 3__ once it's here](https://github.com/meskyanichi/backup).
+I won't actively support Backup 2 anymore. The source will remain on [a separate branch](https://github.com/meskyanichi/backup/tree/backup-2). [The Issues](https://github.com/meskyanichi/backup/issues) that belong to Backup 2 have been tagged with a black label "Backup 2". The Backup 2 specific [Wiki pages](https://github.com/meskyanichi/backup/wiki) have been prefixed with "Backup 2) <Article>". [The Backup 2 Gems](http://rubygems.org/gems/backup) will always remain so you can still use Backup 2. I might still accept pull requests, but would highly encourage anyone to [move to __Backup 3__ once it's here](https://github.com/meskyanichi/backup).
View
10 backup.gemspec
@@ -12,15 +12,7 @@ Gem::Specification.new do |gem|
gem.authors = 'Michael van Rooijen'
gem.email = 'meskyanichi@gmail.com'
gem.homepage = 'http://rubygems.org/gems/backup'
- gem.summary = 'Backup is a RubyGem (for UNIX-like operating systems: Linux, Mac OSX)
- that allows you to configure and perform backups in a simple manner using
- an elegant Ruby DSL. It supports various databases (MySQL, PostgreSQL, MongoDB and Redis),
- it supports various storage locations (Amazon S3, Rackspace Cloud Files, Dropbox, any remote
- server through FTP, SFTP, SCP and RSync), it provide Syncers (RSync, S3) for efficient backups,
- it can archive files and directories, it can cycle backups, it can do incremental backups, it
- can compress backups, it can encrypt backups (OpenSSL or GPG), it can notify you about
- successful and/or failed backups (Email, Twitter and Campfire). It is very extensible and easy to add new
- functionality to. It\'s easy to use.'
+ gem.summary = 'Backup is a RubyGem, written for Linux and Mac OSX, that allows you to easily perform backup operations on both your remote, as well as your local environment. It provides you with an elegant DSL in Ruby for modeling (configuring) your backups. Backup has built-in support for various databases, storage protocols/services, syncers, compressors, encryptors and notifiers which you can mix and match. It was built with modularity, extensibility and simplicity in mind.'
##
# Files and folder that need to be compiled in to the Ruby Gem
View
8 lib/backup.rb
@@ -18,10 +18,10 @@ module Backup
# database MySQL do |mysql|
DATABASES = ['MySQL', 'PostgreSQL', 'MongoDB', 'Redis']
STORAGES = ['S3', 'CloudFiles', 'Dropbox', 'FTP', 'SFTP', 'SCP', 'RSync']
- COMPRESSORS = ['Gzip']
+ COMPRESSORS = ['Gzip', 'Bzip2']
ENCRYPTORS = ['OpenSSL', 'GPG']
SYNCERS = ['RSync', 'S3']
- NOTIFIERS = ['Mail', 'Twitter', 'Campfire']
+ NOTIFIERS = ['Mail', 'Twitter', 'Campfire', 'Presently']
##
# Backup's internal paths
@@ -64,6 +64,7 @@ module Notifier
autoload :Mail, File.join(CONFIGURATION_PATH, 'notifier', 'mail')
autoload :Twitter, File.join(CONFIGURATION_PATH, 'notifier', 'twitter')
autoload :Campfire, File.join(CONFIGURATION_PATH, 'notifier', 'campfire')
+ autoload :Presently, File.join(CONFIGURATION_PATH, 'notifier', 'presently')
end
module Encryptor
@@ -75,6 +76,7 @@ module Encryptor
module Compressor
autoload :Base, File.join(CONFIGURATION_PATH, 'compressor', 'base')
autoload :Gzip, File.join(CONFIGURATION_PATH, 'compressor', 'gzip')
+ autoload :Bzip2, File.join(CONFIGURATION_PATH, 'compressor', 'bzip2')
end
module Storage
@@ -139,6 +141,7 @@ module Database
module Compressor
autoload :Base, File.join(COMPRESSOR_PATH, 'base')
autoload :Gzip, File.join(COMPRESSOR_PATH, 'gzip')
+ autoload :Bzip2, File.join(COMPRESSOR_PATH, 'bzip2')
end
##
@@ -157,6 +160,7 @@ module Notifier
autoload :Mail, File.join(NOTIFIER_PATH, 'mail')
autoload :Twitter, File.join(NOTIFIER_PATH, 'twitter')
autoload :Campfire, File.join(NOTIFIER_PATH, 'campfire')
+ autoload :Presently, File.join(NOTIFIER_PATH, 'presently')
end
##
View
2  lib/backup/archive.rb
@@ -66,7 +66,7 @@ def paths_to_package
# Returns a "tar-ready" string of all the specified excludes combined
def paths_to_exclude
if excludes.any?
- "--exclude={" + excludes.map{ |e| "'#{e}'" }.join(",") + "}"
+ excludes.map{ |e| "--exclude='#{e}'" }.join(" ")
end
end
end
View
2  lib/backup/cli.rb
@@ -22,10 +22,10 @@ module CLI
# and pass that in to the Backup::CLI#raise_if_command_not_found
def run(command)
command.gsub!(/^\s+/, '')
- %x[#{command}]
raise_if_command_not_found!(
command.slice(0, command.index(/\s/)).split('/')[-1]
)
+ %x[#{command}]
end
##
View
64 lib/backup/compressor/bzip2.rb
@@ -0,0 +1,64 @@
+# encoding: utf-8
+
+module Backup
+ module Compressor
+ class Bzip2 < Base
+
+ ##
+ # Tells Backup::Compressor::Bzip2 to compress
+ # better (-9) rather than faster when set to true
+ attr_writer :best
+
+ ##
+ # Tells Backup::Compressor::Bzip2 to compress
+ # faster (-1) rather than better when set to true
+ attr_writer :fast
+
+ ##
+ # Creates a new instance of Backup::Compressor::Bzip2 and
+ # configures it to either compress faster or better
+ # bzip2 compresses by default with -9 (best compression)
+ # and lower block sizes don't make things significantly faster
+ # (according to official bzip2 docs)
+ def initialize(&block)
+ load_defaults!
+
+ @best ||= false
+ @fast ||= false
+
+ instance_eval(&block) if block_given?
+ end
+
+ ##
+ # Performs the compression of the packages backup file
+ def perform!
+ log!
+ run("#{ utility(:bzip2) } #{ options } '#{ Backup::Model.file }'")
+ Backup::Model.extension += '.bz2'
+ end
+
+ private
+
+ ##
+ # Combines the provided options and returns a bzip2 options string
+ def options
+ (best + fast).join("\s")
+ end
+
+ ##
+ # Returns the bzip2 option syntax for compressing
+ # setting @best to true is redundant, as bzip2 compresses best by default
+ def best
+ return ['--best'] if @best; []
+ end
+
+ ##
+ # Returns the bzip2 option syntax for compressing
+ # (not significantly) faster when @fast is set to true
+ def fast
+ return ['--fast'] if @fast; []
+ end
+
+ end
+ end
+end
View
23 lib/backup/configuration/compressor/bzip2.rb
@@ -0,0 +1,23 @@
+# encoding: utf-8
+
+module Backup
+ module Configuration
+ module Compressor
+ class Bzip2 < Base
+ class << self
+
+ ##
+ # Tells Backup::Compressor::Bzip2 to compress
+ # better (-9) which is bzip2 default anyway
+ attr_accessor :best
+
+ ##
+ # Tells Backup::Compressor::Bzip2 to compress
+ # faster (-1) (but not significantly faster)
+ attr_accessor :fast
+
+ end
+ end
+ end
+ end
+end
View
25 lib/backup/configuration/notifier/presently.rb
@@ -0,0 +1,25 @@
+# encoding: utf-8
+
+module Backup
+ module Configuration
+ module Notifier
+ class Presently < Base
+ class << self
+
+ ##
+ # Presently subdomain
+ attr_accessor :subdomain
+
+ ##
+ # Presently credentials
+ attr_accessor :user_name, :password
+
+ ##
+ # Group id
+ attr_accessor :group_id
+
+ end
+ end
+ end
+ end
+end
View
2  lib/backup/encryptor/gpg.rb
@@ -30,7 +30,7 @@ def initialize(&block)
instance_eval(&block) if block_given?
- @key = key.gsub(/^(\s|\t)+/, '')
+ @key = key.gsub(/^[[:blank:]]+/, '')
end
##
View
105 lib/backup/notifier/presently.rb
@@ -0,0 +1,105 @@
+# encoding: utf-8
+
+Backup::Dependency.load('httparty')
+
+module Backup
+ module Notifier
+ class Presently < Base
+
+ ##
+ # Container for the Presently Client object
+ attr_accessor :presently_client
+
+ ##
+ # Container for the Model object
+ attr_accessor :model
+
+ ##
+ # Presently subdomain
+ attr_accessor :subdomain
+
+ ##
+ # Presently credentials
+ attr_accessor :user_name, :password
+
+ ##
+ # Group id
+ attr_accessor :group_id
+
+ ##
+ # Instantiates a new Backup::Notifier::Presently object
+ def initialize(&block)
+ load_defaults!
+
+ instance_eval(&block) if block_given?
+
+ set_defaults!
+ end
+
+ ##
+ # Performs the notification
+ # Takes an exception object that might've been created if an exception occurred.
+ # If this is the case it'll invoke notify_failure!(exception), otherwise, if no
+ # error was raised, it'll go ahead and notify_success!
+ #
+ # If'll only perform these if on_success is true or on_failure is true
+ def perform!(model, exception = false)
+ @model = model
+
+ if notify_on_success? and exception.eql?(false)
+ log!
+ notify_success!
+ elsif notify_on_failure? and not exception.eql?(false)
+ log!
+ notify_failure!(exception)
+ end
+ end
+
+ private
+
+ ##
+ # Sends a tweet informing the user that the backup operation
+ # proceeded without any errors
+ def notify_success!
+ presently_client.update("[Backup::Succeeded] #{model.label} (#{ File.basename(Backup::Model.file) })")
+ end
+
+ ##
+ # Sends a tweet informing the user that the backup operation
+ # raised an exception
+ def notify_failure!(exception)
+ presently_client.update("[Backup::Failed] #{model.label} (#{ File.basename(Backup::Model.file) })")
+ end
+
+ ##
+ # Create a default Presently::Client object
+ def set_defaults!
+ @presently_client = Client.new subdomain, user_name, password, group_id
+ end
+
+ class Client
+ include HTTParty
+
+ attr_accessor :subdomain, :user_name, :password, :group_id
+
+ def initialize(subdomain, user_name, password, group_id)
+ @subdomain = subdomain
+ @user_name = user_name
+ @password = password
+ @group_id = group_id
+
+ self.class.base_uri "https://#{subdomain}.presently.com"
+ self.class.basic_auth user_name, password
+ end
+
+ def update(message)
+ message = "d @#{group_id} #{message}" if group_id
+ self.class.post "/api/twitter/statuses/update.json", :body => {
+ :status => message,
+ :source => "Backup Notifier"
+ }
+ end
+ end
+ end
+ end
+end
View
8 lib/backup/storage/s3.rb
@@ -84,12 +84,8 @@ def transfer!
File.join(remote_path, remote_file),
File.open(File.join(local_path, local_file))
)
- rescue Excon::Errors::SocketError
- puts "\nAn error occurred while trying to transfer the backup."
- puts "Make sure the bucket exists, and that you specified the correct bucket region.\n\n"
- puts "The available regions are:\n\n"
- puts %w[eu-west-1 us-east-1 ap-southeast-1 us-west-1].map{ |region| "\s\s* #{region}" }.join("\n")
- exit
+ rescue Excon::Errors::NotFound
+ raise "An error occurred while trying to transfer the backup, please make sure the bucket exists."
end
end
View
10 lib/backup/syncer/s3.rb
@@ -48,14 +48,14 @@ def initialize(&block)
# and once it's finished syncing the files and directories to Amazon S3, it'll
# unset these credentials (back to nil values)
def perform!
- set_s3sync_credentials!
+ set_environment_variables!
directories.each do |directory|
Logger.message("#{ self.class } started syncing '#{ directory }'.")
Logger.silent( run("#{ utility(:s3sync) } #{ options } '#{ directory }' '#{ bucket }:#{ path }'") )
end
- unset_s3sync_credentials!
+ unset_environment_variables!
end
##
@@ -99,16 +99,18 @@ def add(path)
# In order for S3Sync to know what credentials to use, we have to set the
# AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, these
# evironment variables will be used by S3Sync
- def set_s3sync_credentials!
+ def set_environment_variables!
ENV['AWS_ACCESS_KEY_ID'] = access_key_id
ENV['AWS_SECRET_ACCESS_KEY'] = secret_access_key
+ ENV['AWS_CALLING_FORMAT'] = 'SUBDOMAIN'
end
##
# Sets the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY back to nil
- def unset_s3sync_credentials!
+ def unset_environment_variables!
ENV['AWS_ACCESS_KEY_ID'] = nil
ENV['AWS_SECRET_ACCESS_KEY'] = nil
+ ENV['AWS_CALLING_FORMAT'] = nil
end
end
View
2  lib/backup/version.rb
@@ -13,7 +13,7 @@ class Version
# Defines the minor version
# PATCH:
# Defines the patch version
- MAJOR, MINOR, PATCH = 3, 0, 15
+ MAJOR, MINOR, PATCH = 3, 0, 16
##
# Returns the major version ( big release based off of multiple minor releases )
View
3  lib/templates/archive
@@ -1,3 +1,6 @@
+ ##
+ # Archive [Archive]
+ #
archive :my_archive do |archive|
archive.add '/path/to/a/file.rb'
archive.add '/path/to/a/folder/'
View
7 lib/templates/compressor/bzip2
@@ -0,0 +1,7 @@
+ ##
+ # Bzip2 [Compressor]
+ #
+ compress_with Bzip2 do |compression|
+ compression.best = true
+ compression.fast = false
+ end
View
3  lib/templates/compressor/gzip
@@ -1,3 +1,6 @@
+ ##
+ # Gzip [Compressor]
+ #
compress_with Gzip do |compression|
compression.best = true
compression.fast = false
View
3  lib/templates/database/mongodb
@@ -1,3 +1,6 @@
+ ##
+ # MongoDB [Database]
+ #
database MongoDB do |db|
db.name = "my_database_name"
db.username = "my_username"
View
3  lib/templates/database/mysql
@@ -1,3 +1,6 @@
+ ##
+ # MySQL [Database]
+ #
database MySQL do |db|
db.name = "my_database_name"
db.username = "my_username"
View
5 lib/templates/database/postgresql
@@ -1,3 +1,6 @@
+ ##
+ # PostgreSQL [Database]
+ #
database PostgreSQL do |db|
db.name = "my_database_name"
db.username = "my_username"
@@ -7,5 +10,5 @@
db.socket = "/tmp/pg.sock"
db.skip_tables = ['skip', 'these', 'tables']
db.only_tables = ['only', 'these' 'tables']
- db.additional_options = ['--quick', '--single-transaction']
+ db.additional_options = ['-xc', '-E=utf8']
end
View
3  lib/templates/database/redis
@@ -1,3 +1,6 @@
+ ##
+ # Redis [Database]
+ #
database Redis do |db|
db.name = "my_database_name"
db.path = "/usr/local/var/db/redis"
View
3  lib/templates/encryptor/gpg
@@ -1,3 +1,6 @@
+ ##
+ # GPG [Encryptor]
+ #
encrypt_with GPG do |encryption|
encryption.key = <<-KEY
-----BEGIN PGP PUBLIC KEY BLOCK-----
View
3  lib/templates/encryptor/openssl
@@ -1,3 +1,6 @@
+ ##
+ # OpenSSL [Encryptor]
+ #
encrypt_with OpenSSL do |encryption|
encryption.password = 'my_password'
encryption.base64 = true
View
3  lib/templates/notifier/campfire
@@ -1,3 +1,6 @@
+ ##
+ # Campfire [Notifier]
+ #
notify_by Campfire do |campfire|
campfire.on_success = true
campfire.on_failure = true
View
3  lib/templates/notifier/mail
@@ -1,3 +1,6 @@
+ ##
+ # Mail [Notifier]
+ #
notify_by Mail do |mail|
mail.on_success = true
mail.on_failure = true
View
12 lib/templates/notifier/presently
@@ -0,0 +1,12 @@
+ ##
+ # Presently [Notifier]
+ #
+ notify_by Presently do |presently|
+ presently.on_success = true
+ presently.on_failure = true
+
+ presently.subdomain = 'my_subdomain'
+ presently.user_name = 'my_user_name'
+ presently.password = 'my_password'
+ presently.group_id = 'my_group_id' # optional
+ end
View
3  lib/templates/notifier/twitter
@@ -1,3 +1,6 @@
+ ##
+ # Twitter [Notifier]
+ #
notify_by Twitter do |tweet|
tweet.on_success = true
tweet.on_failure = true
View
2  lib/templates/readme
@@ -11,5 +11,5 @@
# When you're finished configuring this configuration file,
# you can run it from the command line by issuing the following command:
#
-# $ backup -t my_backup [-c <path_to_configuration_file>]
+# $ backup perform -t my_backup [-c <path_to_configuration_file>]
View
3  lib/templates/storage/cloudfiles
@@ -1,3 +1,6 @@
+ ##
+ # Rackspace Cloud Files [Storage]
+ #
store_with CloudFiles do |cf|
cf.api_key = 'my_api_key'
cf.username = 'my_username'
View
3  lib/templates/storage/dropbox
@@ -1,3 +1,6 @@
+ ##
+ # Dropbox File Hosting Service [Storage]
+ #
store_with Dropbox do |db|
db.email = 'my@email.com'
db.password = 'my_password'
View
3  lib/templates/storage/ftp
@@ -1,3 +1,6 @@
+ ##
+ # FTP (File Transfer Protocol) [Storage]
+ #
store_with FTP do |server|
server.username = 'my_username'
server.password = 'my_password'
View
3  lib/templates/storage/rsync
@@ -1,3 +1,6 @@
+ ##
+ # RSync [Storage]
+ #
store_with RSync do |server|
server.username = 'my_username'
server.password = 'my_password'
View
15 lib/templates/storage/s3
@@ -1,3 +1,14 @@
+ ##
+ # Amazon Simple Storage Service [Storage]
+ #
+ # Available Regions:
+ #
+ # - ap-northeast-1
+ # - ap-southeast-1
+ # - eu-west-1
+ # - us-east-1
+ # - us-west-1
+ #
store_with S3 do |s3|
s3.access_key_id = 'my_access_key_id'
s3.secret_access_key = 'my_secret_access_key'
@@ -5,4 +16,6 @@
s3.bucket = 'bucket-name'
s3.path = '/path/to/my/backups'
s3.keep = 10
- end
+ end
+
+
View
3  lib/templates/storage/scp
@@ -1,3 +1,6 @@
+ ##
+ # SCP (Secure Copy) [Storage]
+ #
store_with SCP do |server|
server.username = 'my_username'
server.password = 'my_password'
View
3  lib/templates/storage/sftp
@@ -1,3 +1,6 @@
+ ##
+ # SFTP (Secure File Transfer Protocol) [Storage]
+ #
store_with SFTP do |server|
server.username = 'my_username'
server.password = 'my_password'
View
3  lib/templates/syncer/rsync
@@ -1,3 +1,6 @@
+ ##
+ # RSync [Syncer]
+ #
sync_with RSync do |rsync|
rsync.ip = "123.45.678.90"
rsync.port = 22
View
3  lib/templates/syncer/s3
@@ -1,3 +1,6 @@
+ ##
+ # Amazon Simple Storage Service [Syncer]
+ #
sync_with S3 do |s3|
s3.access_key_id = "my_access_key_id"
s3.secret_access_key = "my_secret_access_key"
View
8 spec/archive_spec.rb
@@ -9,8 +9,8 @@
a.add '/home/rspecuser/somefile'
a.add '/home/rspecuser/logs/'
a.add '/home/rspecuser/dotfiles/'
- a.exclude '/home/rspecuser/excludefile'
- a.exclude '/home/rspecuser/excludedir/'
+ a.exclude '/home/rspecuser/badfile'
+ a.exclude '/home/rspecuser/wrongdir/'
end
end
@@ -51,7 +51,7 @@
it 'should return a tar -c friendly string' do
archive.send(:paths_to_exclude).should ==
- "--exclude={'/home/rspecuser/excludefile','/home/rspecuser/excludedir/'}"
+ "--exclude='/home/rspecuser/badfile' --exclude='/home/rspecuser/wrongdir/'"
end
end
@@ -64,7 +64,7 @@
context 'when both paths were added and paths that should be excluded were added' do
it 'should render both the syntax for the paths that be included as well as excluded' do
archive.expects(:mkdir).with(File.join(Backup::TMP_PATH, Backup::TRIGGER, 'archive'))
- archive.expects(:run).with("tar -c -f '#{File.join(Backup::TMP_PATH, Backup::TRIGGER, 'archive', "#{:dummy_archive}.tar")}' --exclude={'/home/rspecuser/excludefile','/home/rspecuser/excludedir/'} '/home/rspecuser/somefile' '/home/rspecuser/logs/' '/home/rspecuser/dotfiles/' 2> /dev/null")
+ archive.expects(:run).with("tar -c -f '#{File.join(Backup::TMP_PATH, Backup::TRIGGER, 'archive', "#{:dummy_archive}.tar")}' --exclude='/home/rspecuser/badfile' --exclude='/home/rspecuser/wrongdir/' '/home/rspecuser/somefile' '/home/rspecuser/logs/' '/home/rspecuser/dotfiles/' 2> /dev/null")
archive.expects(:utility).with(:tar).returns(:tar)
archive.perform!
end
View
59 spec/compressor/bzip2_spec.rb
@@ -0,0 +1,59 @@
+# encoding: utf-8
+
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe Backup::Compressor::Bzip2 do
+ let(:compressor) { Backup::Compressor::Bzip2.new }
+
+ before do
+ Backup::Model.extension = 'tar'
+ end
+
+ describe 'the options' do
+ it do
+ compressor.send(:best).should == []
+ end
+
+ it do
+ compressor.send(:fast).should == []
+ end
+ end
+
+ describe '#perform!' do
+ before do
+ [:run, :utility].each { |method| compressor.stubs(method) }
+ Backup::Logger.stubs(:message)
+ end
+
+ it 'should perform the compression' do
+ compressor.expects(:utility).with(:bzip2).returns(:bzip2)
+ compressor.expects(:run).with("bzip2 '#{ File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar") }'")
+ compressor.perform!
+ end
+
+ it 'should perform the compression with the --best and --fast options' do
+ compressor = Backup::Compressor::Bzip2.new do |c|
+ c.best = true
+ c.fast = true
+ end
+
+ compressor.stubs(:utility).returns(:bzip2)
+ compressor.expects(:run).with("bzip2 --best --fast '#{ File.join(Backup::TMP_PATH, "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar") }'")
+ compressor.perform!
+ end
+
+ it 'should set the class variable @extension (Backup::Model.extension) to .bz2' do
+ compressor.stubs(:utility).returns(:bzip2)
+ compressor.expects(:run)
+
+ Backup::Model.extension.should == 'tar'
+ compressor.perform!
+ Backup::Model.extension.should == 'tar.bz2'
+ end
+
+ it 'should log' do
+ Backup::Logger.expects(:message).with("Backup::Compressor::Bzip2 started compressing the archive.")
+ compressor.perform!
+ end
+ end
+end
View
20 spec/encryptor/gpg_spec.rb
@@ -20,19 +20,19 @@
end
context "when a block is provided" do
- it do
+ it "should strip initial whitespace from key lines" do
key = <<-KEY
- -----BEGIN PGP PUBLIC KEY BLOCK-----
- Version: GnuPG v1.4.11 (Darwin)
-
- mQENBE12G/8BCAC4mnlSMYMBwBYTHe5zURcnYYNCORPWOr0iXGiLWuKxYtrDQyLm
- X2Nws44Iz7Wp7AuJRAjkitf1cRBgXyDu8wuogXO7JqPmtsUdBCABz9w5NH6IQjgR
- WNa3g2n0nokA7Zr5FA4GXoEaYivfbvGiyNpd6P4okH+//G2p+3FIryu5xz+89D1b
- =Yvhg
- -----END PGP PUBLIC KEY BLOCK-----
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.11 (Darwin)
+
+mQENBE12G/8BCAC4mnlSMYMBwBYTHe5zURcnYYNCORPWOr0iXGiLWuKxYtrDQyLm
+X2Nws44Iz7Wp7AuJRAjkitf1cRBgXyDu8wuogXO7JqPmtsUdBCABz9w5NH6IQjgR
+WNa3g2n0nokA7Zr5FA4GXoEaYivfbvGiyNpd6P4okH+//G2p+3FIryu5xz+89D1b
+=Yvhg
+-----END PGP PUBLIC KEY BLOCK-----
KEY
- encryptor.key.should == key.gsub(/^(\s|\t)+/, '')
+ encryptor.key.should == key
end
end
View
99 spec/notifier/presently_spec.rb
@@ -0,0 +1,99 @@
+# encoding: utf-8
+
+require File.dirname(__FILE__) + '/../spec_helper'
+
+describe Backup::Notifier::Presently do
+ let(:notifier) do
+ Backup::Notifier::Presently.new do |presently|
+ presently.user_name = 'user_name'
+ presently.subdomain = 'subdomain'
+ presently.password = 'password'
+ presently.group_id = 'group_id'
+ end
+ end
+
+ it do
+ notifier.user_name.should == 'user_name'
+ notifier.subdomain.should == 'subdomain'
+ notifier.password.should == 'password'
+ notifier.group_id.should == 'group_id'
+
+ notifier.on_success.should == true
+ notifier.on_failure.should == true
+ end
+
+ describe 'defaults' do
+ it do
+ Backup::Configuration::Notifier::Presently.defaults do |presently|
+ presently.user_name = 'old_user_name'
+ presently.on_success = false
+ presently.on_failure = true
+ end
+ notifier = Backup::Notifier::Presently.new do |presently|
+ presently.user_name = 'new_user_name'
+ end
+
+ notifier.user_name.should == 'new_user_name'
+ notifier.on_success.should == false
+ notifier.on_failure.should == true
+ end
+ end
+
+ describe '#initialize' do
+ it do
+ Backup::Notifier::Presently.any_instance.expects(:set_defaults!)
+ Backup::Notifier::Presently.new
+ end
+ end
+
+ describe '#perform!' do
+ let(:model) { Backup::Model.new('blah', 'blah') {} }
+ before do
+ notifier.on_success = false
+ notifier.on_failure = false
+ end
+
+ context "when successful" do
+ it do
+ Backup::Logger.expects(:message).with("Backup::Notifier::Presently started notifying about the process.")
+ notifier.expects("notify_success!")
+ notifier.on_success = true
+ notifier.perform!(model)
+ end
+
+ it do
+ notifier.expects("notify_success!").never
+ notifier.on_success = false
+ notifier.perform!(model)
+ end
+ end
+
+ context "when failed" do
+ it do
+ Backup::Logger.expects(:message).with("Backup::Notifier::Presently started notifying about the process.")
+ notifier.expects("notify_failure!")
+ notifier.on_failure = true
+ notifier.perform!(model, Exception.new)
+ end
+
+ it do
+ notifier.expects("notify_failure!").never
+ notifier.on_failure = false
+ notifier.perform!(model, Exception.new)
+ end
+ end
+ end
+
+ describe Backup::Notifier::Presently::Client do
+ let(:client) do
+ Backup::Notifier::Presently::Client.new('subdomain', 'user_name', 'password', 'group_id')
+ end
+
+ it do
+ client.user_name.should == 'user_name'
+ client.subdomain.should == 'subdomain'
+ client.password.should == 'password'
+ client.group_id.should == 'group_id'
+ end
+ end
+end
View
4 spec/spec_helper.rb
@@ -19,3 +19,7 @@ module Backup
TRIGGER = 'myapp'
TIME = Time.now.strftime("%Y.%m.%d.%H.%M.%S")
end
+
+unless @put_ruby_version
+ puts @put_ruby_version = "\n\nRuby version: #{ENV['rvm_ruby_string']}\n\n"
+end
Please sign in to comment.
Something went wrong with that request. Please try again.