bibliotech 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/bin/bibliotech +5 -0
  3. data/doc/example_config_file.yml +58 -0
  4. data/doc/todo.txt +19 -0
  5. data/lib/bibliotech/application.rb +95 -0
  6. data/lib/bibliotech/backups/file_record.rb +16 -0
  7. data/lib/bibliotech/backups/prune_list.rb +58 -0
  8. data/lib/bibliotech/backups/pruner.rb +71 -0
  9. data/lib/bibliotech/backups/scheduler.rb +49 -0
  10. data/lib/bibliotech/builders/database.rb +25 -0
  11. data/lib/bibliotech/builders/file.rb +75 -0
  12. data/lib/bibliotech/builders/gzip.rb +51 -0
  13. data/lib/bibliotech/builders/mysql.rb +35 -0
  14. data/lib/bibliotech/builders/postgres.rb +37 -0
  15. data/lib/bibliotech/builders.rb +43 -0
  16. data/lib/bibliotech/cli.rb +24 -0
  17. data/lib/bibliotech/command_generator.rb +86 -0
  18. data/lib/bibliotech/command_runner.rb +36 -0
  19. data/lib/bibliotech/compression/bzip2.rb +6 -0
  20. data/lib/bibliotech/compression/gzip.rb +6 -0
  21. data/lib/bibliotech/compression/sevenzip.rb +5 -0
  22. data/lib/bibliotech/compression.rb +35 -0
  23. data/lib/bibliotech/config.rb +269 -0
  24. data/lib/bibliotech/rake_lib.rb +82 -0
  25. data/lib/bibliotech.rb +7 -0
  26. data/spec/bibliotech/backup_pruner_spec.rb +58 -0
  27. data/spec/bibliotech/backup_scheduler_spec.rb +108 -0
  28. data/spec/bibliotech/command_generator/mysql_spec.rb +170 -0
  29. data/spec/bibliotech/command_generator/postgres_spec.rb +180 -0
  30. data/spec/bibliotech/command_generator_spec.rb +99 -0
  31. data/spec/bibliotech/command_runner_spec.rb +50 -0
  32. data/spec/bibliotech/compression/bunzip2_spec.rb +9 -0
  33. data/spec/bibliotech/compression/bzip2_spec.rb +9 -0
  34. data/spec/bibliotech/compression/gzip_spec.rb +9 -0
  35. data/spec/bibliotech/compression/sevenzip_spec.rb +9 -0
  36. data/spec/bibliotech/compression_spec.rb +28 -0
  37. data/spec/bibliotech/config_spec.rb +151 -0
  38. data/spec/gem_test_suite.rb +0 -0
  39. data/spec/spec_helper.rb +2 -0
  40. metadata +150 -0
@@ -0,0 +1,170 @@
1
+ require 'spec_helper'
2
+ require 'pry'
3
+
4
+ module BiblioTech
5
+ describe CommandGenerator, "for mysql" do
6
+ let :config do
7
+ Config.new(nil).tap do |config|
8
+ config.hash = config_hash
9
+ end
10
+ end
11
+ let :generator do
12
+ CommandGenerator.new(config)
13
+ end
14
+ let( :db_name ) { "db_name" }
15
+ let( :username ) { "user_name" }
16
+ let( :password ) { "password123" }
17
+ let( :host ) { "127.0.0.1" }
18
+ let( :filename ) { "export.sql" }
19
+ let( :path ) { "/some/path" }
20
+
21
+ let :base_config_hash do
22
+ { "database_config" => {
23
+ "adapter" => :mysql,
24
+ "database" => db_name,
25
+ "username" => username
26
+ }}
27
+ end
28
+ let(:config_hash){ base_config_hash }
29
+
30
+ let(:options){ {} }
31
+
32
+ def first_cmd
33
+ command.commands[0]
34
+ end
35
+
36
+ def second_cmd
37
+ command.commands[1]
38
+ end
39
+
40
+ describe :export do
41
+ subject :command do
42
+ generator.export(options)
43
+ end
44
+
45
+ context 'with username and database' do
46
+ context 'and password' do
47
+ let :config_hash do
48
+ #binding.pry
49
+ base_config_hash.tap do |hash|
50
+ hash["database_config"]["password"] = password
51
+ end
52
+ end
53
+
54
+ it { is_expected.to be_a(Caliph::CommandLine) }
55
+ it { expect(command.executable).to eq('mysqldump') }
56
+ it { expect(command.options).to eq(["-u #{username}", "--password='#{password}'", "#{db_name}"]) }
57
+ end
58
+
59
+ context 'and hostname' do
60
+ let :config_hash do
61
+ base_config_hash.tap do |hash|
62
+ hash["database_config"]["host"] = host
63
+ end
64
+ end
65
+
66
+ it { expect(command.options).to eq(["-h #{host}", "-u #{username}", "#{db_name}"]) }
67
+ end
68
+
69
+ context 'plus filename and path' do
70
+ let :options do
71
+ {:backups => { :filename => filename, :dir => path}}
72
+ end
73
+
74
+ context 'and compressor' do
75
+ let :options do
76
+ { :backups => {
77
+ :filename => filename,
78
+ :dir => path,
79
+ :compress => :gzip
80
+ }}
81
+ end
82
+
83
+ it { expect(command).to be_a(Caliph::PipelineChain) }
84
+ it { expect(second_cmd.redirections).to eq([ "1>#{path}/#{filename}.gz" ]) }
85
+
86
+ context "first command" do
87
+ it { expect(first_cmd.executable).to eq('mysqldump') }
88
+ it { expect(first_cmd.options).to eq(["-u #{username}", "#{db_name}"]) }
89
+ end
90
+ context "second command" do
91
+ it { expect(second_cmd.executable).to eq('gzip') }
92
+ end
93
+ end
94
+ end
95
+
96
+ context 'with the whole shebang' do
97
+ let :options do
98
+ { :backups => { :filename => filename, :dir => path, :compress => :gzip} }
99
+ end
100
+ let :config_hash do
101
+ base_config_hash.tap do |hash|
102
+ hash["database_config"].merge!( "host" => host, "password" => password)
103
+ end
104
+ end
105
+
106
+ it { expect(second_cmd.redirections).to eq(["1>#{path}/#{filename}.gz"]) }
107
+
108
+ context "first command" do
109
+ it { expect(first_cmd.executable).to eq("mysqldump") }
110
+ it { expect(first_cmd.options).to eq(["-h #{host}", "-u #{username}", "--password='#{password}'", "#{db_name}"]) }
111
+ end
112
+
113
+ context "second command" do
114
+ it { expect(second_cmd.executable).to eq('gzip') }
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+
121
+ describe :import do
122
+ let :command do
123
+ generator.import(options)
124
+ end
125
+
126
+ subject do
127
+ command
128
+ end
129
+
130
+ context 'with username, database, file, and path' do
131
+ let :options do
132
+ { :backups => { :filename => filename, :dir => path }}
133
+ end
134
+
135
+ it { expect(command).to be_a(Caliph::CommandLine) }
136
+
137
+ it { expect(command.redirections).to eq(["0<#{path}/#{filename}"]) }
138
+ it { expect(command.executable).to eq('mysql')}
139
+ it { expect(command.options).to eq(["-u #{username}", db_name ]) }
140
+
141
+ context "plus password" do
142
+ let :config_hash do
143
+ base_config_hash.tap do |hash|
144
+ hash["database_config"]["password"] = password
145
+ end
146
+ end
147
+
148
+ it { expect(command.options).to eq(["-u #{username}","--password='#{password}'", "#{db_name}"]) }
149
+
150
+ context 'and compressor' do
151
+ let :options do
152
+ { :backups => {
153
+ :filename => filename + '.gz',
154
+ :dir => path,
155
+ :compress => :gzip
156
+ } }
157
+ end
158
+
159
+ it { expect(command).to be_a(Caliph::PipelineChain) }
160
+ it { expect(first_cmd.executable).to eq('gunzip') }
161
+ it { expect(first_cmd.options).to eq(["#{path}/#{filename}.gz"]) }
162
+ end
163
+ end
164
+ end
165
+ end
166
+
167
+
168
+
169
+ end
170
+ end
@@ -0,0 +1,180 @@
1
+ require 'spec_helper'
2
+
3
+ module BiblioTech
4
+ describe CommandGenerator do
5
+ let :generator do
6
+ CommandGenerator.new(config)
7
+ end
8
+
9
+ let (:db_name){ "db_name" }
10
+ let (:username){ "user_name" }
11
+ let (:password){ "password123" }
12
+ let (:host){ "127.0.0.1" }
13
+ let (:filename){ "export.pg" }
14
+ let (:path){ "/some/path" }
15
+
16
+
17
+ let (:base_options){{}}
18
+
19
+ let :base_config_hash do
20
+ { "database_config" =>
21
+ {
22
+ "adapter" => :postgres,
23
+ "database" => db_name,
24
+ "username" => username
25
+ }
26
+ }
27
+
28
+ end
29
+
30
+ let(:config_hash){ base_config_hash }
31
+ let(:options){ base_options }
32
+
33
+ let :config do
34
+ Config.new(nil).tap do |config|
35
+ config.hash = config_hash
36
+ end
37
+ end
38
+
39
+ def first_cmd
40
+ command.commands[0]
41
+ end
42
+
43
+ def second_cmd
44
+ command.commands[1]
45
+ end
46
+
47
+ describe :export do
48
+ let :command do
49
+ generator.export(options)
50
+ end
51
+
52
+ subject do
53
+ command
54
+ end
55
+
56
+ context 'with username and database' do
57
+ let :config_hash do
58
+ base_config_hash
59
+ end
60
+
61
+ context 'and password' do
62
+ let :config_hash do
63
+ base_config_hash.tap do |hash|
64
+ hash["database_config"]["password"] = password
65
+ end
66
+ end
67
+
68
+ it { is_expected.to be_a(Caliph::CommandLine) }
69
+ it { expect(command.executable).to eq('pg_dump') }
70
+ it { expect(command.options).to eq(["-Fc", "-U #{username}", "#{db_name}"]) }
71
+ it { expect(command.env['PGPASSWORD']).to eq(password) }
72
+ end
73
+
74
+ context 'and hostname' do
75
+ let :config_hash do
76
+ base_config_hash.tap do |hash|
77
+ hash["database_config"]["host"] = host
78
+ end
79
+ end
80
+
81
+ it { expect(command.options).to eq(["-Fc", "-h #{host}", "-U #{username}", "#{db_name}"]) }
82
+ end
83
+
84
+ context 'plus filename and path and compressor' do
85
+ let :options do
86
+ base_options.merge( :backups => {
87
+ :dir => path,
88
+ :filename => filename,
89
+ :compress => :gzip
90
+ })
91
+ end
92
+
93
+ it { expect(command).to be_a(Caliph::PipelineChain) }
94
+ it { expect(command.commands[1].redirections).to eq([ "1>#{path}/#{filename}.gz" ]) }
95
+
96
+ context "first command" do
97
+ it { expect(first_cmd.executable).to eq('pg_dump') }
98
+ it { expect(first_cmd.options).to eq(["-Fc", "-U #{username}", "#{db_name}"]) }
99
+ end
100
+ context "second command" do
101
+ it { expect(second_cmd.executable).to eq('gzip') }
102
+ end
103
+ end
104
+
105
+ context 'with the whole shebang' do
106
+ let :options do
107
+ base_options.merge( :backups => {
108
+ :filename => filename,
109
+ :dir => path,
110
+ :compress => :gzip
111
+ })
112
+ end
113
+ let :config_hash do
114
+ base_config_hash.tap do |hash|
115
+ hash["database_config"] = hash["database_config"].merge({ "host" => host, "password" => password })
116
+ end
117
+ end
118
+
119
+ it { expect(second_cmd.redirections).to eq(["1>#{path}/#{filename}.gz"]) }
120
+
121
+ context "first command" do
122
+ it { expect(first_cmd.executable).to eq("pg_dump") }
123
+ it { expect(first_cmd.options).to eq(["-Fc", "-h #{host}", "-U #{username}", "#{db_name}"]) }
124
+ it { expect(first_cmd.env['PGPASSWORD']).to eq(password) }
125
+ end
126
+
127
+ context "second command" do
128
+ it { expect(second_cmd.executable).to eq('gzip') }
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+
135
+ describe :import do
136
+ let :command do
137
+ generator.import(options)
138
+ end
139
+
140
+ subject do
141
+ command
142
+ end
143
+
144
+ context 'with username, database, file, and path' do
145
+ let :options do
146
+ base_options.merge(:backups => { :filename => filename, :dir => path })
147
+ end
148
+
149
+ it { expect(command.redirections).to eq(["0<#{path}/#{filename}"]) }
150
+ it { expect(command.executable).to eq('pg_restore')}
151
+ it { expect(command.options).to eq(["-U #{username}", "-d #{db_name}" ]) }
152
+
153
+ context "plus password" do
154
+ let :config_hash do
155
+ base_config_hash.tap do |hash|
156
+ hash["database_config"]["password"] = password
157
+ end
158
+ end
159
+
160
+ it { expect(command.options).to eq(["-U #{username}", "-d #{db_name}"]) }
161
+ it { expect(command.env['PGPASSWORD']).to eq(password) }
162
+
163
+ context 'and compressor' do
164
+ let :options do
165
+ base_options.merge(:backups => {
166
+ :filename => filename + '.gz',
167
+ :dir => path,
168
+ :compressor => :gzip
169
+ })
170
+ end
171
+
172
+ it { expect(command).to be_a(Caliph::PipelineChain) }
173
+ it { expect(first_cmd.executable).to eq('gunzip') }
174
+ it { expect(first_cmd.options).to eq(["#{path}/#{filename}.gz"]) }
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+ require 'bibliotech/application'
3
+
4
+ module BiblioTech
5
+ describe CommandGenerator do
6
+ describe "class methods", :pending => true do
7
+ describe "adapter lookup" do
8
+ class CommandOne < CommandGenerator; end;
9
+ class CommandTwo < CommandGenerator; end;
10
+ let :class_1 do CommandOne end
11
+ let :class_2 do CommandTwo end
12
+ let :config do { :adapter => :type_1 } end
13
+ let :return_adapter do double(CommandGenerator) end
14
+
15
+ before do
16
+ CommandGenerator.class_eval do
17
+ @adapter_registry = nil
18
+ end
19
+ end
20
+
21
+ context "with one class registered" do
22
+ before do
23
+ CommandGenerator.register(:type_1, CommandOne)
24
+ end
25
+ it "should list single supported adapter" do
26
+ expect(CommandGenerator.supported_adapters()).to eq([:type_1])
27
+ end
28
+ it "should return the correct adapter, instantiated with the config" do
29
+ expect(CommandOne).to receive(:new).and_return(return_adapter)
30
+ expect(CommandGenerator.for(config)).to eq(return_adapter)
31
+ end
32
+ end
33
+
34
+ context "with two classes registered" do
35
+ before do
36
+ CommandGenerator.register(:type_1, CommandOne)
37
+ CommandGenerator.register(:type_2, CommandTwo)
38
+ end
39
+ it "should return a single registered class" do
40
+ expect(CommandGenerator.supported_adapters()).to include(:type_1, :type_2)
41
+ end
42
+ end
43
+ context "with one class registered twice" do
44
+ before do
45
+ CommandGenerator.register(:type_1, CommandOne)
46
+ CommandGenerator.register(:type_1a, CommandOne)
47
+ end
48
+ it "should list single supported adapter" do
49
+ expect(CommandGenerator.supported_adapters()).to eq([:type_1, :type_1a])
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ describe "skeleton methods" do
56
+ let :generator do
57
+ CommandGenerator.new(config)
58
+ end
59
+
60
+ let :app do
61
+ Application.new
62
+ end
63
+
64
+ let :config do
65
+ app.config
66
+ end
67
+
68
+ it "should produce a remote_cli command" do
69
+ expect(generator.remote_cli("staging", "latest").command).to match(/\Assh.*-- '.*bibliotech latest'\z/)
70
+ end
71
+
72
+ it "should produce a fetch command" do
73
+ expect(generator.fetch("staging", "latest.sql.gz").command).to match(/\Ascp.*@.*latest\.sql\.gz.*latest\.sql\.gz\z/)
74
+ end
75
+
76
+ it "should produce a push command" do
77
+ expect(generator.push("staging", "latest.sql.gz").command).to match(/\Ascp.*latest\.sql\.gz.*@.*latest\.sql\.gz\z/)
78
+ end
79
+
80
+ it "should raise_error an error when calling wipe" do
81
+ expect do
82
+ generator.wipe()
83
+ end.to raise_error(NotImplementedError)
84
+ end
85
+
86
+ it "should raise_error an error when calling delete" do
87
+ expect do
88
+ generator.delete()
89
+ end.to raise_error(NotImplementedError)
90
+ end
91
+
92
+ it "should raise_error an error when calling create" do
93
+ expect do
94
+ generator.create()
95
+ end.to raise_error(NotImplementedError)
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+ require 'bibliotech/command_runner'
3
+
4
+
5
+ module BiblioTech
6
+ describe CommandRunner do
7
+ let :config do
8
+ double(Config,
9
+ :db_config => {},
10
+ :environment => :development
11
+ )
12
+ end
13
+
14
+ let :generator do
15
+ double(CommandGenerator,
16
+ :export => 'export command'
17
+ )
18
+ end
19
+
20
+ let :command do "some cli command" end
21
+
22
+ let :shell do
23
+ double("Caliph::Shell")
24
+ end
25
+
26
+ let :runner do
27
+ CommandRunner.new(config).tap do |runner|
28
+ runner.shell = shell
29
+ end
30
+ end
31
+
32
+ before do
33
+ allow(CommandGenerator).to receive(:for).and_return(generator)
34
+ end
35
+
36
+ describe "single commands" do
37
+ it 'should do export' do
38
+ expect(generator).to receive(:export).and_return(command)
39
+ expect(shell).to receive(:run).with(command)
40
+ runner.export('path/to/file')
41
+ end
42
+
43
+ it 'should do import' do
44
+ expect(generator).to receive(:import).and_return(command)
45
+ expect(shell).to receive(:run).with(command)
46
+ runner.import('path/to/file')
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ module BiblioTech
4
+ describe Compression::Bzip2 do
5
+ # TODO
6
+ end
7
+ end
8
+
9
+
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ module BiblioTech
4
+ describe Compression::Bzip2 do
5
+ # TODO
6
+ end
7
+ end
8
+
9
+
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ module BiblioTech
4
+ describe Compression::Gzip do
5
+ # TODO
6
+ end
7
+ end
8
+
9
+
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ module BiblioTech
4
+ describe Compression::SevenZip do
5
+ # TODO
6
+ end
7
+ end
8
+
9
+
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ module BiblioTech
4
+ describe Compression do
5
+
6
+ let :generator do
7
+ double(CommandGenerator)
8
+ end
9
+
10
+ describe 'for' do
11
+ it do
12
+ expect(Compression.for("my_archive.sql.gz", generator)).to be_a(Compression::Gzip)
13
+ end
14
+
15
+ it do
16
+ expect(Compression.for("my_archive.sql.bz2", generator)).to be_a(Compression::Bzip2)
17
+ end
18
+
19
+ it do
20
+ expect(Compression.for("my_archive.sql.7z", generator)).to be_a(Compression::SevenZip)
21
+ end
22
+
23
+ it do
24
+ expect(Compression.for("my_archive.sql", generator)).to equal(generator)
25
+ end
26
+ end
27
+ end
28
+ end