stratocumulus 0.0.4 → 0.0.5

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.
@@ -3,3 +3,13 @@ rvm:
3
3
  - 2.1.2
4
4
  - 2.0.0
5
5
  - 1.9.3
6
+ before_install:
7
+ - source /etc/lsb-release && echo "deb http://download.rethinkdb.com/apt $DISTRIB_CODENAME main" | sudo tee /etc/apt/sources.list.d/rethinkdb.list
8
+ - wget -O- http://download.rethinkdb.com/apt/pubkey.gpg | sudo apt-key add -
9
+ - sudo apt-get update -qq
10
+ install:
11
+ - sudo apt-get install -y rethinkdb
12
+ - sudo pip install rethinkdb
13
+ - sudo cp /etc/rethinkdb/default.conf.sample /etc/rethinkdb/instances.d/instance1.conf
14
+ - sudo /etc/init.d/rethinkdb restart
15
+ - bundle install
@@ -1,19 +1,42 @@
1
1
  # encoding: UTF-8
2
- require 'stratocumulus/database/mysql'
3
2
  require 'stratocumulus/database/pipe_io'
3
+ require 'stratocumulus/database/mysql'
4
+ require 'stratocumulus/database/postgresql'
5
+ require 'stratocumulus/database/rethinkdb'
4
6
  require 'English'
5
7
 
6
8
  module Stratocumulus
7
9
  class Database
8
- def initialize(options = {}, backend_class = nil)
10
+ def self.build(options = {})
11
+ backend_class = backends[options['type']]
12
+ fail "#{options['type']} is not a supported database" unless backend_class
13
+ backend_class.new(options)
14
+ end
15
+
16
+ def self.backends
17
+ {
18
+ 'psql' => PostgreSQL,
19
+ 'mysql' => MySQL,
20
+ 'rethinkdb' => RethinkDB
21
+ }
22
+ end
23
+
24
+ def initialize(options = {})
25
+ check_dependencies
26
+ @username = options['username']
27
+ @password = options['password']
9
28
  @name = options['name']
10
29
  fail 'database name not specified' unless @name
11
- setup_backend(backend_class, options)
12
- check_dependencies
30
+ @host = options['host']
31
+ @port = options['port']
13
32
  end
14
33
 
15
34
  def dump
16
- @dump ||= PipeIO.popen("bash -c '#{pipefail} #{@backend.command} | gzip'")
35
+ @dump ||= PipeIO.popen("bash -c '#{pipefail} #{command} | gzip'")
36
+ end
37
+
38
+ def filename
39
+ @name + '/' + file
17
40
  end
18
41
 
19
42
  def success?
@@ -22,31 +45,32 @@ module Stratocumulus
22
45
  $CHILD_STATUS.success?
23
46
  end
24
47
 
25
- def filename
26
- @filename ||= Time.now.utc.strftime("#{@name}/#{@name}.%Y%m%d%H%M.sql.gz")
48
+ def dependencies
49
+ ['gzip']
27
50
  end
28
51
 
29
52
  private
30
53
 
31
- def pipefail
32
- 'set -o pipefail;'
33
- end
34
-
35
54
  def check_dependencies
36
55
  dependencies.each do |cmd|
37
56
  fail "#{cmd} not available" unless system("which #{cmd} >/dev/null")
38
57
  end
39
58
  end
40
59
 
41
- def dependencies
42
- ['gzip'] + @backend.dependencies
60
+ def file
61
+ @file ||= Time.now.utc.strftime("#{@name}.%Y%m%d%H%M#{suffix}")
62
+ end
63
+
64
+ def suffix
65
+ '.sql.gz'
66
+ end
67
+
68
+ def pipefail
69
+ 'set -o pipefail;'
43
70
  end
44
71
 
45
- def setup_backend(backend_class, options)
46
- backend_class ||= MySQL
47
- type = options['type']
48
- fail "#{type} is not a supported database" unless type == 'mysql'
49
- @backend = backend_class.new(options)
72
+ def socket?
73
+ !@host && !@port
50
74
  end
51
75
  end
52
76
  end
@@ -1,44 +1,34 @@
1
1
  # encoding: UTF-8
2
+ require 'stratocumulus/database'
2
3
 
3
4
  module Stratocumulus
4
- class Database
5
- class MySQL
6
- def initialize(options = {})
7
- @username = options['username'] || 'root'
8
- @password = options['password']
9
- @name = options['name']
10
-
11
- @host = options['host']
12
- @port = options['port']
13
- end
14
-
15
- def command
16
- command = 'mysqldump '
17
- command << '--single-transaction '
18
- command << "-u#{@username} "
19
- command << "-h#{host} " unless socket?
20
- command << "-P#{port} " unless socket?
21
- command << "-p#{@password} " if @password
22
- command << @name
23
- end
5
+ class MySQL < Database
6
+ def command
7
+ command = 'mysqldump '
8
+ command << '--single-transaction '
9
+ command << "-u#{username} "
10
+ command << "-h#{host} " unless socket?
11
+ command << "-P#{port} " unless socket?
12
+ command << "-p#{@password} " if @password
13
+ command << @name
14
+ end
24
15
 
25
- def dependencies
26
- ['mysqldump']
27
- end
16
+ def dependencies
17
+ super + ['mysqldump']
18
+ end
28
19
 
29
- private
20
+ private
30
21
 
31
- def host
32
- @host || 'localhost'
33
- end
22
+ def username
23
+ @username || 'root'
24
+ end
34
25
 
35
- def port
36
- @port || 3306
37
- end
26
+ def host
27
+ @host || 'localhost'
28
+ end
38
29
 
39
- def socket?
40
- !@host && !@port
41
- end
30
+ def port
31
+ @port || 3306
42
32
  end
43
33
  end
44
34
  end
@@ -0,0 +1,34 @@
1
+ # encoding: UTF-8
2
+ require 'stratocumulus/database'
3
+
4
+ module Stratocumulus
5
+ class PostgreSQL < Database
6
+ def command
7
+ command = ''
8
+ command << %Q(PGPASSWORD="#{@password}" ) if @password
9
+ command << 'pg_dump '
10
+ command << "-U#{username} "
11
+ command << "-h#{host} " unless socket?
12
+ command << "-p#{port} " unless socket?
13
+ command << @name
14
+ end
15
+
16
+ def dependencies
17
+ super + ['pg_dump']
18
+ end
19
+
20
+ private
21
+
22
+ def username
23
+ @username || 'postgres'
24
+ end
25
+
26
+ def host
27
+ @host || 'localhost'
28
+ end
29
+
30
+ def port
31
+ @port || 5432
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: UTF-8
2
+ require 'stratocumulus/database'
3
+ require 'tmpdir'
4
+
5
+ module Stratocumulus
6
+ class RethinkDB < Database
7
+ def dump
8
+ `#{command}`
9
+ @success = $CHILD_STATUS.success?
10
+ File.open(path)
11
+ end
12
+
13
+ def command
14
+ command = 'rethinkdb dump '
15
+ command << "-c #{host}:#{port} " unless socket?
16
+ command << "-f #{path} "
17
+ command << "-e #{@name}"
18
+ end
19
+
20
+ def success?
21
+ File.delete(path)
22
+ @success
23
+ end
24
+
25
+ def dependencies
26
+ ['rethinkdb-dump']
27
+ end
28
+
29
+ private
30
+
31
+ def path
32
+ Dir.tmpdir + '/' + file
33
+ end
34
+
35
+ def suffix
36
+ '.tar.gz'
37
+ end
38
+ end
39
+ end
@@ -8,7 +8,7 @@ module Stratocumulus
8
8
 
9
9
  def run
10
10
  @config['databases'].each do |database_config|
11
- database = Database.new(database_config)
11
+ database = Database.build(database_config)
12
12
  upload(database, database_config['storage'])
13
13
  end
14
14
  end
@@ -73,7 +73,7 @@ module Stratocumulus
73
73
  end
74
74
 
75
75
  def log
76
- Logger.new(STDERR)
76
+ Logger.new($stderr)
77
77
  end
78
78
  end
79
79
  end
@@ -1,4 +1,4 @@
1
1
  # encoding: UTF-8
2
2
  module Stratocumulus
3
- VERSION = '0.0.4'
3
+ VERSION = '0.0.5'
4
4
  end
@@ -1,30 +1,95 @@
1
1
  # encoding: UTF-8
2
2
  require 'spec_helper'
3
+ require 'zlib'
4
+ require 'rubygems/package'
3
5
 
4
6
  describe Stratocumulus::Database do
5
7
 
6
8
  subject do
7
- described_class.new(config)
9
+ described_class.build(config)
8
10
  end
9
11
 
10
12
  let('config') do
11
13
  {
12
14
  'name' => 'stratocumulus_test',
13
- 'type' => 'mysql'
15
+ 'type' => type
14
16
  }
15
17
  end
16
18
 
19
+ let(:dump) { Zlib::GzipReader.new(subject.dump).read }
20
+
17
21
  describe '#dump' do
18
- before do
19
- system('mysql -u root < spec/support/test.sql')
22
+ context 'MySQL' do
23
+ before do
24
+ `mysql -u root < spec/support/mysql.sql`
25
+ end
26
+
27
+ let(:type) { 'mysql' }
28
+
29
+ it 'sucessfully dumps a gziped copy of the database' do
30
+ expect(dump).to include('CREATE TABLE `widgets`')
31
+ expect(dump).to include("INSERT INTO `widgets` VALUES (1,'Foo',3,1,2)")
32
+ expect(subject).to be_success
33
+ end
20
34
  end
21
35
 
22
- let(:dump) { Zlib::GzipReader.new(subject.dump).read }
36
+ context 'PostgreSQL' do
37
+ before do
38
+ `psql -U postgres < spec/support/psql.sql`
39
+ end
40
+
41
+ let(:type) { 'psql' }
42
+
43
+ it 'sucessfully dumps a gziped copy of the database' do
44
+ expect(dump).to include('CREATE TABLE widgets')
45
+ expect(dump).to include(
46
+ 'COPY widgets (id, name, leavers, pivots, fulcrums) FROM stdin;'
47
+ )
48
+ expect(dump).to include('1 Foo 3 1 2')
49
+ expect(subject).to be_success
50
+ end
51
+ end
52
+
53
+ context 'RethinkDB' do
54
+ before do
55
+ `rethinkdb restore --force spec/support/rethinkdb.tar.gz`
56
+ end
57
+
58
+ let(:type) { 'rethinkdb' }
59
+
60
+ let(:tarball) { Zlib::GzipReader.new(subject.dump) }
61
+
62
+ let(:dump) do
63
+ Gem::Package::TarReader.new(tarball).each do |tarfile|
64
+ next unless tarfile.full_name =~ /widgets.json/
65
+ return JSON.load(tarfile.read)
66
+ end
67
+ end
68
+
69
+ let(:expected_data) do
70
+ [
71
+ # rubocop:disable Style/LineLength
72
+ { 'pivots' => 5, 'fulcrums' => 3, 'leavers' => 8, 'id' => '1c66308d-492e-48ee-bfc5-83de96a15236', 'name' => 'Plugh' },
73
+ { 'pivots' => 2, 'fulcrums' => 3, 'leavers' => 1, 'id' => '224ba4b1-2184-4905-b81b-ac6368480f43', 'name' => 'Thud' },
74
+ { 'pivots' => 2, 'fulcrums' => 3, 'leavers' => 1, 'id' => '25b68062-7e9f-4fca-92bf-672287961096', 'name' => 'Garply' },
75
+ { 'pivots' => 1, 'fulcrums' => 2, 'leavers' => 3, 'id' => '380c2a12-62d8-4faa-968e-79b2919bf9ad', 'name' => 'Foo' },
76
+ { 'pivots' => 5, 'fulcrums' => 4, 'leavers' => 8, 'id' => '46cd4d4a-2cca-4ae2-835e-19c94c53ce02', 'name' => 'Quux' },
77
+ { 'pivots' => 2, 'fulcrums' => 7, 'leavers' => 8, 'id' => '63441f79-cfe4-4460-8fc7-bda802e93646', 'name' => 'Corge' },
78
+ { 'pivots' => 3, 'fulcrums' => 4, 'leavers' => 7, 'id' => '7d83f209-b4b1-4463-9eec-42dbf9217a39', 'name' => 'Grault' },
79
+ { 'pivots' => 5, 'fulcrums' => 6, 'leavers' => 4, 'id' => '8e1623c8-e28d-48f9-8d74-dc5bf459cff5', 'name' => 'Qux' },
80
+ { 'pivots' => 2, 'fulcrums' => 0, 'leavers' => 2, 'id' => 'a59c4505-c078-4186-a1d5-b0120dba4aa1', 'name' => 'Bar' },
81
+ { 'pivots' => 3, 'fulcrums' => 3, 'leavers' => 3, 'id' => 'b535529c-c822-4c08-af65-f3662d981046', 'name' => 'Xyzzy' },
82
+ { 'pivots' => 0, 'fulcrums' => 0, 'leavers' => 0, 'id' => 'f47bcc2a-ae2a-4d5f-9bbf-df71c8d81a7a', 'name' => 'Waldo' },
83
+ { 'pivots' => 6, 'fulcrums' => 4, 'leavers' => 5, 'id' => 'f6745b27-b0c8-40ca-a472-dbe45310ee19', 'name' => 'Baz' },
84
+ { 'pivots' => 1, 'fulcrums' => 1, 'leavers' => 1, 'id' => 'f88a0196-faaa-4695-88f1-808555a68ffa', 'name' => 'Fred' }
85
+ # rubocop:enable Style/LineLength
86
+ ]
87
+ end
23
88
 
24
- it 'sucessfully dumps a gziped copy of the database' do
25
- expect(dump).to include('CREATE TABLE `widgets`')
26
- expect(dump).to include("INSERT INTO `widgets` VALUES (1,'Foo',3,1,2)")
27
- expect(subject).to be_success
89
+ it 'sucessfully dumps a gziped copy of the database' do
90
+ expect(dump).to eq expected_data
91
+ expect(subject).to be_success
92
+ end
28
93
  end
29
94
  end
30
95
  end
@@ -1,6 +1,7 @@
1
1
  # encoding: UTF-8
2
2
  require 'simplecov'
3
3
  require 'coveralls'
4
+ require 'stringio'
4
5
 
5
6
  SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
6
7
  SimpleCov::Formatter::HTMLFormatter,
@@ -32,3 +33,13 @@ RSpec.configure do |config|
32
33
  mocks.syntax = :expect
33
34
  end
34
35
  end
36
+
37
+ def capture_stderr
38
+ old_stderr = $stderr
39
+ fake_stderr = StringIO.new
40
+ $stderr = fake_stderr
41
+ yield
42
+ fake_stderr.string
43
+ ensure
44
+ $stdout = old_stderr
45
+ end
File without changes
@@ -0,0 +1,52 @@
1
+ DROP DATABASE stratocumulus_test;
2
+ CREATE DATABASE stratocumulus_test
3
+ WITH OWNER = postgres
4
+ ENCODING = 'UTF8'
5
+ TABLESPACE = pg_default
6
+ CONNECTION LIMIT = -1;
7
+ \c stratocumulus_test
8
+ SET statement_timeout = 0;
9
+ SET lock_timeout = 0;
10
+ SET client_encoding = 'UTF8';
11
+ SET standard_conforming_strings = on;
12
+ SET check_function_bodies = false;
13
+ SET client_min_messages = warning;
14
+ CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
15
+ COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
16
+ SET search_path = public, pg_catalog;
17
+ SET default_tablespace = '';
18
+ SET default_with_oids = false;
19
+ CREATE TABLE widgets (
20
+ id integer NOT NULL,
21
+ name text,
22
+ leavers integer,
23
+ pivots integer,
24
+ fulcrums integer
25
+ );
26
+ ALTER TABLE public.widgets OWNER TO postgres;
27
+ CREATE SEQUENCE widgets_id_seq
28
+ START WITH 1
29
+ INCREMENT BY 1
30
+ NO MINVALUE
31
+ NO MAXVALUE
32
+ CACHE 1;
33
+ ALTER TABLE public.widgets_id_seq OWNER TO postgres;
34
+ ALTER SEQUENCE widgets_id_seq OWNED BY widgets.id;
35
+ ALTER TABLE ONLY widgets ALTER COLUMN id SET DEFAULT nextval('widgets_id_seq'::regclass);
36
+ COPY widgets (id, name, leavers, pivots, fulcrums) FROM stdin;
37
+ 1 Foo 3 1 2
38
+ 2 Bar 2 2 0
39
+ 3 Baz 5 6 4
40
+ 4 Qux 4 5 6
41
+ 5 Quux 8 5 4
42
+ 6 Corge 8 2 7
43
+ 7 Grault 7 3 4
44
+ 8 Garply 1 2 3
45
+ 9 Waldo 0 0 0
46
+ 10 Fred 1 1 1
47
+ 11 Xyzzy 3 3 3
48
+ 12 Thud 1 2 3
49
+ \.
50
+ SELECT pg_catalog.setval('widgets_id_seq', 12, true);
51
+ ALTER TABLE ONLY widgets
52
+ ADD CONSTRAINT widgets_pkey PRIMARY KEY (id);
@@ -4,7 +4,7 @@ require 'spec_helper'
4
4
  describe Stratocumulus::Database do
5
5
 
6
6
  subject do
7
- described_class.new(config)
7
+ described_class.build(config)
8
8
  end
9
9
 
10
10
  let(:config) { base_config }
@@ -12,19 +12,23 @@ describe Stratocumulus::Database do
12
12
  let(:base_config) do
13
13
  {
14
14
  'name' => 'stratocumulus_test',
15
- 'type' => 'mysql'
15
+ 'type' => type
16
16
  }
17
17
  end
18
18
 
19
+ let(:type) { 'mysql' }
20
+
19
21
  before do
20
- allow_any_instance_of(described_class).to receive(:system).and_return(true)
22
+ allow_any_instance_of(Stratocumulus::Database).to(
23
+ receive(:system).and_return(true)
24
+ )
21
25
  end
22
26
 
23
27
  describe '.new' do
24
- context 'the database type is not mysql' do
28
+ context 'the database type is not supported' do
25
29
  let(:config) { base_config.merge('type' => 'nosqlioid') }
26
30
 
27
- it 'thows an error unless the type is mysql' do
31
+ it 'thows an error unless the type is supported' do
28
32
  expect { subject }.to raise_error(
29
33
  RuntimeError,
30
34
  'nosqlioid is not a supported database'
@@ -32,18 +36,35 @@ describe Stratocumulus::Database do
32
36
  end
33
37
  end
34
38
 
35
- it 'throws an error if mysqldump is not installed' do
36
- allow_any_instance_of(described_class)
37
- .to receive(:system).with(/which mysqldump/)
39
+ context 'mysql' do
40
+ it 'throws an error if mysqldump is not installed' do
41
+ allow_any_instance_of(Stratocumulus::Database).to(
42
+ receive(:system).with(/which mysqldump/)
43
+ )
38
44
 
39
- expect { subject }.to raise_error(
40
- RuntimeError,
41
- 'mysqldump not available'
42
- )
45
+ expect { subject }.to raise_error(
46
+ RuntimeError,
47
+ 'mysqldump not available'
48
+ )
49
+ end
50
+ end
51
+
52
+ context 'postgresql' do
53
+ let(:type) { 'psql' }
54
+
55
+ it 'throws an error if pg_dump is not installed' do
56
+ allow_any_instance_of(Stratocumulus::Database)
57
+ .to receive(:system).with(/which pg_dump/)
58
+
59
+ expect { subject }.to raise_error(
60
+ RuntimeError,
61
+ 'pg_dump not available'
62
+ )
63
+ end
43
64
  end
44
65
 
45
66
  it 'throws an error if gzip is not installed' do
46
- allow_any_instance_of(described_class)
67
+ allow_any_instance_of(Stratocumulus::Database)
47
68
  .to receive(:system).with(/which gzip/)
48
69
 
49
70
  expect { subject }.to raise_error(
@@ -68,133 +89,6 @@ describe Stratocumulus::Database do
68
89
  end
69
90
  end
70
91
 
71
- describe 'dump' do
72
-
73
- after do
74
- subject.dump
75
- end
76
-
77
- describe 'username' do
78
- context 'default' do
79
- it 'uses root' do
80
- expect(IO).to receive(:popen) do |command|
81
- expect(command).to include(' -uroot ')
82
- end
83
- end
84
- end
85
-
86
- context 'setting the username' do
87
- let(:config) { base_config.merge('username' => 'susan') }
88
-
89
- it 'uses the correct username' do
90
- expect(IO).to receive(:popen) do |command|
91
- expect(command).to include(' -ususan ')
92
- end
93
- end
94
- end
95
- end
96
-
97
- describe 'password' do
98
- context 'default' do
99
- it 'uses no password' do
100
- expect(IO).to receive(:popen) do |command|
101
- expect(command).to_not include('-p')
102
- end
103
- end
104
- end
105
-
106
- context 'setting the passsword' do
107
- let(:config) { base_config.merge('password' => 'sekret') }
108
-
109
- it 'uses the correct password' do
110
- expect(IO).to receive(:popen) do |command|
111
- expect(command).to include(' -psekret ')
112
- end
113
- end
114
- end
115
- end
116
-
117
- describe 'host' do
118
- context 'default with the port set' do
119
- let(:config) { base_config.merge('port' => '3306') }
120
-
121
- it 'uses localhost' do
122
- expect(IO).to receive(:popen) do |command|
123
- expect(command).to include(' -hlocalhost ')
124
- end
125
- end
126
- end
127
-
128
- context 'default' do
129
- it 'uses the default socket' do
130
- expect(IO).to receive(:popen) do |command|
131
- expect(command).to_not include(' -hlocalhost ')
132
- end
133
- end
134
- end
135
-
136
- context 'setting the host' do
137
- let(:config) { base_config.merge('host' => 'db.awesome-server.net') }
138
-
139
- it 'uses the correct hostname' do
140
- expect(IO).to receive(:popen) do |command|
141
- expect(command).to include(' -hdb.awesome-server.net ')
142
- end
143
- end
144
- end
145
- end
146
-
147
- describe 'port' do
148
- context 'default with the host set' do
149
- let(:config) { base_config.merge('host' => 'db.awesome-server.net') }
150
-
151
- it 'uses 3306' do
152
- expect(IO).to receive(:popen) do |command|
153
- expect(command).to include(' -P3306 ')
154
- end
155
- end
156
- end
157
-
158
- context 'default' do
159
- it 'uses the default socket' do
160
- expect(IO).to receive(:popen) do |command|
161
- expect(command).to_not include(' -P3306 ')
162
- end
163
- end
164
- end
165
-
166
- context 'setting the port' do
167
- let(:config) { base_config.merge('port' => '4306') }
168
-
169
- it 'uses the correct port' do
170
- expect(IO).to receive(:popen) do |command|
171
- expect(command).to include(' -P4306 ')
172
- end
173
- end
174
- end
175
- end
176
-
177
- describe 'the dump command' do
178
- it 'sets pipefail' do
179
- expect(IO).to receive(:popen) do |command|
180
- expect(command).to include("bash -c 'set -o pipefail;")
181
- end
182
- end
183
-
184
- it 'uses mysqldump --single-transaction option to not lock tables' do
185
- expect(IO).to receive(:popen) do |command|
186
- expect(command).to include(' mysqldump --single-transaction ')
187
- end
188
- end
189
-
190
- it 'pipes the output of mysql to gzip' do
191
- expect(IO).to receive(:popen) do |command|
192
- expect(command).to match(/.*mysqldump.*\| gzip/)
193
- end
194
- end
195
- end
196
- end
197
-
198
92
  describe '#filename' do
199
93
  it 'calculates a filename based on the name and timestamp' do
200
94
  timestamp = Time.now.utc.strftime('%Y%m%d%H%M')
@@ -210,50 +104,32 @@ describe Stratocumulus::Database do
210
104
  end
211
105
 
212
106
  describe '#success?' do
213
- subject do
214
- described_class.new(
215
- { 'name' => 'foo', 'type' => 'mysql' },
216
- backend
217
- )
218
- end
219
-
220
- context 'the backend fails' do
221
- let(:backend) { FailingBackend }
107
+ describe 'the dump fails' do
108
+ subject { FailingDatabase.new('name' => 'test_database') }
222
109
 
223
110
  it 'returns false' do
224
111
  expect(subject).to_not be_success
225
112
  end
226
-
227
113
  end
228
114
 
229
- context 'the backend is sucessfull' do
230
- let(:backend) { SucessBackend }
115
+ describe 'the dump is sucessfull' do
116
+ subject { SucessDatabase.new('name' => 'test_database') }
231
117
 
232
- it 'returns true' do
118
+ it 'returns false' do
233
119
  expect(subject).to be_success
234
120
  end
235
-
236
- end
237
-
238
- class FakeBackend
239
- def initialize(*)
240
- end
241
-
242
- def dependencies
243
- []
244
- end
245
121
  end
122
+ end
246
123
 
247
- class FailingBackend < FakeBackend
248
- def command
249
- 'exit 127'
250
- end
124
+ class SucessDatabase < described_class
125
+ def command
126
+ 'echo boo'
251
127
  end
128
+ end
252
129
 
253
- class SucessBackend < FakeBackend
254
- def command
255
- 'exit 0'
256
- end
130
+ class FailingDatabase < described_class
131
+ def command
132
+ 'exit 127'
257
133
  end
258
134
  end
259
135
  end
@@ -0,0 +1,104 @@
1
+ # encoding: UTF-8
2
+ require 'spec_helper'
3
+
4
+ describe Stratocumulus::MySQL do
5
+ subject do
6
+ described_class.new(config)
7
+ end
8
+
9
+ let(:config) do
10
+ { 'name' => 'stratocumulus_test' }
11
+ end
12
+
13
+ describe '#dependencies' do
14
+ specify do
15
+ expect(subject.dependencies).to eq %w(gzip mysqldump)
16
+ end
17
+ end
18
+
19
+ describe '#command' do
20
+ context 'default' do
21
+ it 'generates the dump command with sensible defaults' do
22
+ expect(subject.command).to eq(
23
+ 'mysqldump --single-transaction -uroot stratocumulus_test'
24
+ )
25
+ end
26
+ end
27
+
28
+ context 'with the password set' do
29
+ let(:config) do
30
+ {
31
+ 'name' => 'stratocumulus_test',
32
+ 'password' => 'seecrit'
33
+ }
34
+ end
35
+
36
+ it 'generates the dump command with a default host' do
37
+ expect(subject.command).to eq(
38
+ 'mysqldump --single-transaction -uroot -pseecrit stratocumulus_test'
39
+ )
40
+ end
41
+ end
42
+
43
+ context 'with the port set' do
44
+ let(:config) do
45
+ {
46
+ 'name' => 'stratocumulus_test',
47
+ 'port' => 13_306
48
+ }
49
+ end
50
+
51
+ it 'generates the dump command with a default host' do
52
+ expect(subject.command).to eq(
53
+ 'mysqldump --single-transaction -uroot -hlocalhost -P13306 stratocumulus_test' # rubocop:disable Style/LineLength
54
+ )
55
+ end
56
+ end
57
+
58
+ context 'with the host set' do
59
+ let(:config) do
60
+ {
61
+ 'name' => 'stratocumulus_test',
62
+ 'host' => 'db.example.com'
63
+ }
64
+ end
65
+
66
+ it 'generates the dump command with a default port' do
67
+ expect(subject.command).to eq(
68
+ 'mysqldump --single-transaction -uroot -hdb.example.com -P3306 stratocumulus_test' # rubocop:disable Style/LineLength
69
+ )
70
+ end
71
+ end
72
+
73
+ context 'with the port and host set' do
74
+ let(:config) do
75
+ {
76
+ 'name' => 'stratocumulus_test',
77
+ 'port' => 33_306,
78
+ 'host' => 'db.example.com'
79
+ }
80
+ end
81
+
82
+ it 'generates the dump command with the port and host' do
83
+ expect(subject.command).to eq(
84
+ 'mysqldump --single-transaction -uroot -hdb.example.com -P33306 stratocumulus_test' # rubocop:disable Style/LineLength
85
+ )
86
+ end
87
+ end
88
+
89
+ context 'with the username set' do
90
+ let(:config) do
91
+ {
92
+ 'name' => 'stratocumulus_test',
93
+ 'username' => 'susan'
94
+ }
95
+ end
96
+
97
+ it 'generates the dump command with the username' do
98
+ expect(subject.command).to eq(
99
+ 'mysqldump --single-transaction -ususan stratocumulus_test'
100
+ )
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,104 @@
1
+ # encoding: UTF-8
2
+ require 'spec_helper'
3
+
4
+ describe Stratocumulus::PostgreSQL do
5
+ subject do
6
+ described_class.new(config)
7
+ end
8
+
9
+ let(:config) do
10
+ { 'name' => 'stratocumulus_test' }
11
+ end
12
+
13
+ describe '#dependencies' do
14
+ specify do
15
+ expect(subject.dependencies).to eq %w(gzip pg_dump)
16
+ end
17
+ end
18
+
19
+ describe '#command' do
20
+ context 'default' do
21
+ it 'generates the dump command with sensible defaults' do
22
+ expect(subject.command).to eq(
23
+ 'pg_dump -Upostgres stratocumulus_test'
24
+ )
25
+ end
26
+ end
27
+
28
+ context 'with the password set' do
29
+ let(:config) do
30
+ {
31
+ 'name' => 'stratocumulus_test',
32
+ 'password' => 'sekret'
33
+ }
34
+ end
35
+
36
+ it 'sets the password env var' do
37
+ expect(subject.command).to eq(
38
+ 'PGPASSWORD="sekret" pg_dump -Upostgres stratocumulus_test'
39
+ )
40
+ end
41
+ end
42
+
43
+ context 'with the port set' do
44
+ let(:config) do
45
+ {
46
+ 'name' => 'stratocumulus_test',
47
+ 'port' => 15_432
48
+ }
49
+ end
50
+
51
+ it 'generates the dump command with a default host' do
52
+ expect(subject.command).to eq(
53
+ 'pg_dump -Upostgres -hlocalhost -p15432 stratocumulus_test'
54
+ )
55
+ end
56
+ end
57
+
58
+ context 'with the host set' do
59
+ let(:config) do
60
+ {
61
+ 'name' => 'stratocumulus_test',
62
+ 'host' => 'db.example.com'
63
+ }
64
+ end
65
+
66
+ it 'generates the dump command with a default port' do
67
+ expect(subject.command).to eq(
68
+ 'pg_dump -Upostgres -hdb.example.com -p5432 stratocumulus_test'
69
+ )
70
+ end
71
+ end
72
+
73
+ context 'with the port and host set' do
74
+ let(:config) do
75
+ {
76
+ 'name' => 'stratocumulus_test',
77
+ 'port' => 15_432,
78
+ 'host' => 'db.example.com'
79
+ }
80
+ end
81
+
82
+ it 'generates the dump command with port and host set' do
83
+ expect(subject.command).to eq(
84
+ 'pg_dump -Upostgres -hdb.example.com -p15432 stratocumulus_test'
85
+ )
86
+ end
87
+ end
88
+
89
+ context 'with the username set' do
90
+ let(:config) do
91
+ {
92
+ 'name' => 'stratocumulus_test',
93
+ 'username' => 'susan'
94
+ }
95
+ end
96
+
97
+ it 'generates the dump command with the username' do
98
+ expect(subject.command).to eq(
99
+ 'pg_dump -Ususan stratocumulus_test'
100
+ )
101
+ end
102
+ end
103
+ end
104
+ end
@@ -30,12 +30,18 @@ describe Stratocumulus::Storage do
30
30
  )
31
31
  end
32
32
 
33
+ let(:stderr) do
34
+ capture_stderr do
35
+ subject.upload(database)
36
+ end
37
+ end
38
+
33
39
  before do
34
40
  allow(Fog::Storage).to receive(:new).and_return(connection)
35
41
  end
36
42
 
37
43
  after do
38
- subject.upload(database)
44
+ stderr
39
45
  end
40
46
 
41
47
  it 'uploads the dump to s3' do
@@ -122,6 +128,12 @@ describe Stratocumulus::Storage do
122
128
  it 'does not create a expiry rule' do
123
129
  expect(service).to_not receive(:put_bucket_lifecycle)
124
130
  end
131
+
132
+ it 'logs the error to stderr' do
133
+ expect(stderr).to include(
134
+ 'ERROR -- : there was an error generating foo.sql.gz'
135
+ )
136
+ end
125
137
  end
126
138
 
127
139
  context 'rules allready set on the bucket' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stratocumulus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-06-18 00:00:00.000000000 Z
12
+ date: 2014-06-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fog
@@ -162,17 +162,23 @@ files:
162
162
  - lib/stratocumulus/database.rb
163
163
  - lib/stratocumulus/database/mysql.rb
164
164
  - lib/stratocumulus/database/pipe_io.rb
165
+ - lib/stratocumulus/database/postgresql.rb
166
+ - lib/stratocumulus/database/rethinkdb.rb
165
167
  - lib/stratocumulus/retention.rb
166
168
  - lib/stratocumulus/runner.rb
167
169
  - lib/stratocumulus/storage.rb
168
170
  - lib/stratocumulus/version.rb
169
171
  - spec/intergration/database_spec.rb
170
172
  - spec/spec_helper.rb
171
- - spec/support/test.sql
173
+ - spec/support/mysql.sql
174
+ - spec/support/psql.sql
175
+ - spec/support/rethinkdb.tar.gz
172
176
  - spec/support/test_config_file.yml
173
177
  - spec/unit/cli_spec.rb
174
178
  - spec/unit/database_spec.rb
179
+ - spec/unit/mysql_spec.rb
175
180
  - spec/unit/pipe_io_spec.rb
181
+ - spec/unit/postgresql_spec.rb
176
182
  - spec/unit/retention_spec.rb
177
183
  - spec/unit/runner_spec.rb
178
184
  - spec/unit/storage_spec.rb
@@ -192,7 +198,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
192
198
  version: '0'
193
199
  segments:
194
200
  - 0
195
- hash: 815129825214945472
201
+ hash: 646644050683609050
196
202
  required_rubygems_version: !ruby/object:Gem::Requirement
197
203
  none: false
198
204
  requirements:
@@ -201,7 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
201
207
  version: '0'
202
208
  segments:
203
209
  - 0
204
- hash: 815129825214945472
210
+ hash: 646644050683609050
205
211
  requirements: []
206
212
  rubyforge_project:
207
213
  rubygems_version: 1.8.25
@@ -211,11 +217,15 @@ summary: Backup Databases to Cloud Storage
211
217
  test_files:
212
218
  - spec/intergration/database_spec.rb
213
219
  - spec/spec_helper.rb
214
- - spec/support/test.sql
220
+ - spec/support/mysql.sql
221
+ - spec/support/psql.sql
222
+ - spec/support/rethinkdb.tar.gz
215
223
  - spec/support/test_config_file.yml
216
224
  - spec/unit/cli_spec.rb
217
225
  - spec/unit/database_spec.rb
226
+ - spec/unit/mysql_spec.rb
218
227
  - spec/unit/pipe_io_spec.rb
228
+ - spec/unit/postgresql_spec.rb
219
229
  - spec/unit/retention_spec.rb
220
230
  - spec/unit/runner_spec.rb
221
231
  - spec/unit/storage_spec.rb