sqlup 0.0.1

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 (39) hide show
  1. data/History.txt +5 -0
  2. data/Manifest.txt +38 -0
  3. data/README.txt +122 -0
  4. data/Rakefile +18 -0
  5. data/bin/sqlup +107 -0
  6. data/bin/sqlup_control +25 -0
  7. data/config/environment.rb +0 -0
  8. data/lib/mysql_backup/entity/files/innodb.rb +77 -0
  9. data/lib/mysql_backup/entity/files/myisam.rb +62 -0
  10. data/lib/mysql_backup/entity/files.rb +95 -0
  11. data/lib/mysql_backup/entity/identifier.rb +179 -0
  12. data/lib/mysql_backup/entity/logs.rb +44 -0
  13. data/lib/mysql_backup/entity/mysqldump.rb +57 -0
  14. data/lib/mysql_backup/entity.rb +38 -0
  15. data/lib/mysql_backup/librarian/backup.rb +134 -0
  16. data/lib/mysql_backup/librarian/backup_collection.rb +63 -0
  17. data/lib/mysql_backup/librarian.rb +176 -0
  18. data/lib/mysql_backup/server.rb +237 -0
  19. data/lib/mysql_backup/storage/s3.rb +110 -0
  20. data/lib/mysql_backup/storage.rb +13 -0
  21. data/lib/mysql_backup/utilities/factory_create_method.rb +51 -0
  22. data/lib/mysql_backup.rb +8 -0
  23. data/lib/sqlup.rb +2 -0
  24. data/test/unit/mysql_backup/entity/files/files_test.rb +45 -0
  25. data/test/unit/mysql_backup/entity/files/innodb_test.rb +50 -0
  26. data/test/unit/mysql_backup/entity/files/myisam_test.rb +42 -0
  27. data/test/unit/mysql_backup/entity/identifier_test.rb +51 -0
  28. data/test/unit/mysql_backup/entity/logs_test.rb +13 -0
  29. data/test/unit/mysql_backup/entity/mysqldump_test.rb +64 -0
  30. data/test/unit/mysql_backup/librarian/backup_collection_test.rb +52 -0
  31. data/test/unit/mysql_backup/librarian/backup_test.rb +25 -0
  32. data/test/unit/mysql_backup/librarian/librarian_test.rb +103 -0
  33. data/test/unit/mysql_backup/server_test.rb +63 -0
  34. data/test/unit/mysql_backup/storage/s3_test.rb +69 -0
  35. data/test/unit/mysql_backup/storage/test_helper.rb +1 -0
  36. data/test/unit/mysql_backup/test_helper.rb +1 -0
  37. data/test/unit/mysql_backup/utilities/test_helper.rb +1 -0
  38. data/test/unit/test_helper.rb +10 -0
  39. metadata +116 -0
@@ -0,0 +1,237 @@
1
+ require 'rubygems'
2
+ require 'named_arguments'
3
+ require 'active_record/vendor/mysql'
4
+ require 'mysql_backup/entity'
5
+ require 'mysql_backup/entity/logs'
6
+ require 'mysql_backup/entity/files/innodb'
7
+ require 'mysql_backup/entity/files/myisam'
8
+
9
+ module MysqlBackup; end
10
+
11
+ # To get the current log position:
12
+ #
13
+ # show_master_status => {:file => 'logfilename_0004', :position => 386}
14
+ #
15
+ # To get a list of the available log files:
16
+ #
17
+ # show_binary_logs => %w(logfilename_0003 logfilename_0004)
18
+ #
19
+ # To get a list of closed log files:
20
+ #
21
+ # completed_logs => %w(logfilename_0003)
22
+ #
23
+ # To get a MysqlBackup::InnodbFiles object:
24
+ #
25
+ #
26
+ class MysqlBackup::Server
27
+ include NamedArguments
28
+
29
+ # The MySQL connection
30
+ attr_accessor :connection
31
+
32
+ # Returns just the base element of innodb_data_file_path.
33
+ # Given
34
+ # ibdata1:10M:autoextend
35
+ # Return
36
+ # ibdata
37
+ def innodb_data_file_path
38
+ v = show_variables
39
+ path = v[:innodb_data_file_path]
40
+ path = path.split(':').first
41
+ path =~ /(.*)\d+$/
42
+ $1
43
+ end
44
+
45
+ def innodb_data_home_dir
46
+ innodb_data_home_dir = show_variables[:innodb_data_home_dir]
47
+ return innodb_data_home_dir unless innodb_data_home_dir.empty?
48
+ datadir
49
+ end
50
+
51
+ def datadir
52
+ show_variables[:datadir]
53
+ end
54
+
55
+ def log_bin_dir
56
+ @log_bin_dir || datadir
57
+ end
58
+
59
+ # Attempts to recreate the option passed
60
+ # to log-bin.
61
+ def log_bin
62
+ logs = show_binary_logs
63
+ logs.last =~ /(.*)\.\d+$/
64
+ $1
65
+ end
66
+
67
+ # Returns an array of log file names.
68
+ #
69
+ # If you need the file sizes, call
70
+ # query_to_array 'show binary logs'
71
+ # directly.
72
+ #
73
+ # Returns [] if there are no logs.
74
+ def show_binary_logs
75
+ query_to_list 'show binary logs', 'Log_name'
76
+ end
77
+
78
+ def create_innodb_files_obj
79
+ MysqlBackup::Entity::Files::Innodb.new :datadir => datadir, :innodb_data_home_dir => innodb_data_home_dir, :innodb_data_file_path => innodb_data_file_path
80
+ end
81
+
82
+ def create_myisam_files_obj
83
+ MysqlBackup::Entity::Files::Myisam.new :datadir => datadir
84
+ end
85
+
86
+ def create_logs_obj
87
+ result = nil
88
+ with_lock do |log_identifier|
89
+ i = log_identifier.merge :log_bin_dir => log_bin_dir, :completed_logs => completed_logs
90
+ result = MysqlBackup::Entity::Logs.new i
91
+ end
92
+ result
93
+ end
94
+
95
+ # Return a hash of the mysql system variables.
96
+ #
97
+ # The keys are lower case symbols.
98
+ def show_variables
99
+ query_to_hash 'show variables', 'Variable_name', "Value"
100
+ end
101
+
102
+ # Returns a hash containing:
103
+ #
104
+ # :file => the name of the current log file
105
+ # :position => the position in the current log file where the next entry will be written
106
+ def show_master_status
107
+ r = query_to_array_of_symbolic_hashes 'show master status'
108
+ r.first
109
+ end
110
+
111
+ # Returns true if any entries have been written to the current log file.
112
+ def current_log_has_entries?
113
+ m = show_master_status
114
+ return false if m.empty?
115
+ m['Position'].to_i > 4
116
+ end
117
+
118
+ # Returns a list of all log files except the open log.
119
+ def completed_logs
120
+ result = show_binary_logs
121
+ result.pop
122
+ result
123
+ end
124
+
125
+ ######################
126
+ # Internal methods below this point
127
+ ######################
128
+
129
+ # Call <tt>flush logs</tt>.
130
+ def flush_logs!
131
+ query_to_array 'flush logs'
132
+ end
133
+
134
+ def with_lock
135
+ lock_tables
136
+ m = show_master_status
137
+ raise RuntimeError, "No results from show master status. Is binary logging enabled?" unless m
138
+ yield :log_file => m[:file], :log_position => m[:position]
139
+ ensure
140
+ unlock_tables
141
+ end
142
+
143
+ def lock_tables
144
+ query_to_array 'FLUSH TABLES WITH READ LOCK'
145
+ end
146
+
147
+ def unlock_tables
148
+ query_to_array 'UNLOCK TABLES'
149
+ end
150
+
151
+ # Required arguments:
152
+ #
153
+ # :connection => The MySQL connection
154
+ def initialize args = {}
155
+ super
156
+ end
157
+
158
+ # Run the query given in +q+ and
159
+ # return the value in the
160
+ # result identified by +field+.
161
+ #
162
+ # Return nil if no rows are returned.
163
+ # There is no way to distinguish
164
+ # between no rows and a nil
165
+ # value. Call query_to_list
166
+ # if you need that functionality.
167
+ def query_to_value q, field
168
+ result = query_to_list q, 'Value'
169
+ result.first
170
+ end
171
+
172
+ # Return a list of values
173
+ # from the column +field+
174
+ # from the query +q+.
175
+ #
176
+ # Return [] if no rows
177
+ # are returned.
178
+ def query_to_list q, field
179
+ r = query_to_array(q).map {|l| l[field.downcase.to_sym]}
180
+ r
181
+ end
182
+
183
+ # Return the rows of the query as
184
+ # an array of
185
+ def query_to_array q
186
+ result = []
187
+ a = @connection.query(q)
188
+ a && a.each_hash do |l|
189
+ result << hash_to_symbolic_hash(l)
190
+ end
191
+ result
192
+ end
193
+
194
+ def query_to_array_of_symbolic_hashes q #:nodoc:
195
+ result = query_to_array q
196
+ result.map {|r| hash_to_symbolic_hash r}
197
+ end
198
+
199
+ # Run the query and return all rows
200
+ # as key/value pairs in a hash.
201
+ def query_to_hash q, k_name, v_name #:nodoc:
202
+ result = {}
203
+ @connection.query(q).each_hash do |l|
204
+ k = l[k_name]
205
+ result[k.to_s.downcase.to_sym] = normalized_value l[v_name]
206
+ end
207
+ result
208
+ end
209
+
210
+ # Run the query given in +q+ and
211
+ # return the first row as a hash.
212
+ #
213
+ # Return nil if no rows are returned.
214
+ def query_to_single_hash q #:nodoc:
215
+ result = query_to_array q
216
+ hash_to_symbolic_hash result.first
217
+ end
218
+
219
+ def hash_to_symbolic_hash h #:nodoc:
220
+ result = {}
221
+ h.each_pair do |k,v|
222
+ result[k.to_s.downcase.to_sym] = normalized_value v
223
+ end
224
+ result
225
+ end
226
+
227
+ def normalized_value v #:nodoc:
228
+ i = v.to_i
229
+ v = i if i.to_s == v.to_s
230
+ v = case v
231
+ when /^(on|yes)$/i: true
232
+ when /^(off|no)$/i: nil
233
+ else v
234
+ end
235
+ v
236
+ end
237
+ end
@@ -0,0 +1,110 @@
1
+ require 'aws/s3'
2
+ require 'mysql_backup/storage'
3
+
4
+ class MysqlBackup::Storage::S3 < MysqlBackup::Storage
5
+ # The name of the bucket storing backup objects
6
+ attr_accessor :bucket
7
+
8
+ # The AWS::S3::Bucket object
9
+ attr_writer :bucket_obj
10
+
11
+ # Takes:
12
+ #
13
+ # :access_key_id => 'abc',
14
+ # :secret_access_key => '123'
15
+ # :bucket => 'name_of_the_backup_bucket'
16
+ def initialize args = {}
17
+ super
18
+ connect! args unless args[:no_connect]
19
+ end
20
+
21
+ # +identifier+ is a MysqlBackup::Entity::Identifier
22
+ # object.
23
+ def save args
24
+ identifier = args[:identifier]
25
+ log && log.info("saving to S3(#{@bucket}): #{identifier}")
26
+ AWS::S3::S3Object.store identifier.to_s, args[:file].open, @bucket
27
+ mark_as_existing identifier.to_s
28
+ end
29
+
30
+ # +identifier+ is a MysqlBackup::Entity::Identifier
31
+ # object.
32
+ def conditional_save args
33
+ identifier = args[:identifier]
34
+ if include? identifier
35
+ log && log.info("not saving; object exists in (#{@bucket}): #{identifier}")
36
+ else
37
+ save args
38
+ end
39
+ end
40
+
41
+ def rm identifier
42
+ AWS::S3::S3Object.delete identifier.to_s, bucket
43
+ end
44
+
45
+ def include? key
46
+ @existing_objects ||= {}
47
+ @existing_objects.include? key.to_s
48
+ end
49
+
50
+ def mark_as_existing key
51
+ @existing_objects ||= {}
52
+ @existing_objects[key.to_s] = nil
53
+ end
54
+
55
+ def read_existing_objects
56
+ yield_objects do |o|
57
+ mark_as_existing s3_object_to_identifier(o).to_s
58
+ true
59
+ end
60
+ end
61
+
62
+ def yield_objects n_keys = 1000 #:nodoc:
63
+ objs = []
64
+ while objs
65
+ objs = bucket_obj.objects :max_keys => n_keys, :marker => (objs.empty? ? nil : objs.last.key)
66
+ objs.each do |o|
67
+ yield o
68
+ end
69
+ objs = nil if objs.empty? || objs.length < n_keys
70
+ end
71
+ end
72
+
73
+ def yield_backup_objects
74
+ yield_objects do |o|
75
+ i = MysqlBackup::Entity::Identifier.build_object :string
76
+ yield o if i
77
+ end
78
+ end
79
+
80
+ def yield_identifiers
81
+ yield_objects do |o|
82
+ i = s3_object_to_identifier o
83
+ yield i if i
84
+ end
85
+ end
86
+
87
+ def retrieve_backup_and_then_yield_file group
88
+ Tempfile.open 'backup_retrieval' do |f|
89
+ group.identifiers.each do |i|
90
+ AWS::S3::S3Object.stream i.to_s, bucket do |chunk|
91
+ f.write chunk
92
+ end
93
+ end
94
+ f.seek 0
95
+ yield f
96
+ end
97
+ end
98
+
99
+ def s3_object_to_identifier o
100
+ MysqlBackup::Entity::Identifier.build_object :string => o.key, :timestamp => o.last_modified
101
+ end
102
+
103
+ def bucket_obj
104
+ @bucket_obj ||= AWS::S3::Bucket.find bucket
105
+ end
106
+
107
+ def connect! args
108
+ AWS::S3::Base.establish_connection! :access_key_id => args[:access_key_id], :secret_access_key => args[:secret_access_key]
109
+ end
110
+ end
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'named_arguments'
3
+
4
+ require 'mysql_backup/entity/identifier'
5
+
6
+ module MysqlBackup; end
7
+
8
+ class MysqlBackup::Storage
9
+ include NamedArguments
10
+
11
+ # The Logger object
12
+ attr_accessor :log
13
+ end
@@ -0,0 +1,51 @@
1
+ module FactoryCreateMethod
2
+ def self.included target
3
+ target.class_eval do
4
+ include NamedArguments::MethodExtensions
5
+ extend ClassMethods
6
+ define_method_with_value :factory_create_base_class, target
7
+ end
8
+ end
9
+
10
+ class NoMatchingFactory < NoMethodError; end
11
+
12
+ module ClassMethods
13
+ # Creates the appropriate object.
14
+ #
15
+ # Throws NoMethodError if no factory method
16
+ # responded to the arguments.
17
+ #
18
+ # Use build_object to return nil instead
19
+ # of throwing an exception.
20
+ def create_object args = {}
21
+ factory_create_base_class.factory_methods.each do |f|
22
+ result = f.call args
23
+ return result if result
24
+ end
25
+ raise FactoryCreateMethod::NoMatchingFactory, "No factory method matched #{args.inspect}"
26
+ end
27
+
28
+ # Note that this method will be replaced on the
29
+ # first call to append_factory_method.
30
+ def factory_methods # nodoc
31
+ return []
32
+ end
33
+
34
+ def build_object args = {}
35
+ create_object args
36
+ rescue
37
+ nil
38
+ end
39
+
40
+ def append_factory_method &block
41
+ orig = factory_create_base_class
42
+ orig.define_method_with_value :factory_methods, [block] + factory_methods
43
+ end
44
+
45
+ def new_if_class klass, field
46
+ append_factory_method do |args|
47
+ klass === args[field] && new(args)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,8 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'mysql_backup/librarian'
4
+ require 'mysql_backup/storage/s3'
5
+
6
+ module MysqlBackup
7
+ VERSION = '0.0.1'
8
+ end
data/lib/sqlup.rb ADDED
@@ -0,0 +1,2 @@
1
+ #$:.unshift File.expand_path(File.dirname(__FILE__))
2
+ #require 'pp'
@@ -0,0 +1,45 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+ require 'mysql_backup/entity/files'
3
+
4
+ class MysqlBackup::Entity::FilesTest < Test::Unit::TestCase
5
+ def test_class_create_tar_files
6
+ build_result = {:files => ['log.001'], :log_position => 12, :n_parts => 1, :log_file => 'log.001', :log_position => 0}
7
+ MysqlBackup::Entity::Files.expects(:build_files).times(0..100).returns(build_result)
8
+ expects(:must_call)
9
+ MysqlBackup::Entity::Files.create_tar_files do |args|
10
+ must_call
11
+ assert_kind_of MysqlBackup::Entity::Identifier, args[:identifier]
12
+ end
13
+ end
14
+
15
+ def test_class_build_files
16
+ o1 = stub(:required_path_strings => ['/tmp/a'], :confirm_required_paths_are_readable => nil)
17
+ o2 = stub(:required_path_strings => ['/tmp/b'], :confirm_required_paths_are_readable => nil)
18
+ ms = stub('mysqlserver')
19
+ ms.expects(:with_lock).yields(:log_file => 'snark', :log_position => 3)
20
+ (MysqlBackup::Entity::Files.expects(:tar_files).with {|t| t == %w(/tmp/a /tmp/b)}).returns([])
21
+ MysqlBackup::Entity::Files.build_files :mysql_server => ms, :mysql_files => [o1, o2]
22
+ end
23
+
24
+ def test_class_do_tar
25
+ end
26
+
27
+ def test_class_tar_files
28
+ MysqlBackup::Entity::Files.expects(:do_tar).with {|x| x[:cmd] =~ /tar.*tmp.a.*gzip.*split/}
29
+ files = MysqlBackup::Entity::Files.tar_files ['/tmp/a']
30
+ end
31
+
32
+ def test_required_path_strings
33
+ f = MysqlBackup::Entity::Files.new
34
+ f.expects(:required_paths).returns([])
35
+ f.required_path_strings
36
+ end
37
+
38
+ def test_set_path_vars
39
+ f = MysqlBackup::Entity::Files.new
40
+ f.expects(:foo=)
41
+ Pathname.any_instance.expects(:readable?).returns true
42
+ f.instance_variable_set(:@foo, '/tmp/foo')
43
+ f.set_path_vars [:foo], :foo => '/tmp/foo'
44
+ end
45
+ end
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+ require 'mysql_backup/entity/files/innodb'
3
+
4
+ class MysqlBackup::Entity::Files::InnodbTest < Test::Unit::TestCase
5
+ def test_required_paths
6
+ paths = std_innodb.required_paths
7
+ assert_equal ["/tmp/fakeinnodb1", "/tmp/mock_database"].sort, (paths.map {|px| px.cleanpath.to_s}).sort
8
+ end
9
+
10
+ def test_innodb_database_dirs
11
+ s = std_innodb
12
+ result = s.innodb_database_dirs
13
+ assert_equal [Pathname.new('/tmp/mock_database')], result
14
+ end
15
+
16
+ def test_innodb_files
17
+ assert_equal [Pathname.new('/tmp/fakeinnodb1')], std_innodb.innodb_files
18
+ end
19
+
20
+ protected
21
+
22
+ def std_innodb
23
+ @innodb = MysqlBackup::Entity::Files::Innodb.new :datadir => @basedir, :innodb_data_home_dir => @basedir, :innodb_data_file_path => 'fakeinnodb'
24
+ end
25
+
26
+ def setup
27
+ @basedir = '/tmp'
28
+ @basepath = Pathname.new @basedir
29
+ p = @basepath + 'mock_database'
30
+ p.mkdir unless p.directory?
31
+ q = p + 'foo.frm'
32
+ q.open 'w' do |qf|
33
+ qf << 'testing'
34
+ end
35
+ # Build fake innodb files
36
+ i = @basepath + 'fakeinnodb1'
37
+ i.open 'w' do |innofile|
38
+ innofile << 'testing'
39
+ end
40
+ end
41
+
42
+ def teardown
43
+ p = @basepath + 'mock_database'
44
+ Pathname.glob(p + '*').each do |f|
45
+ f.unlink
46
+ end
47
+ p.rmdir
48
+ Pathname.glob(@basepath + 'fakeinnodb*').each {|pr| pr.delete}
49
+ end
50
+ end
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+ require 'mysql_backup/entity/files/myisam'
3
+
4
+ class MysqlBackup::Entity::Files::MyisamTest < Test::Unit::TestCase
5
+ def test_required_paths
6
+ paths = std_myisam.required_paths
7
+ assert_equal ["/tmp/mock_myisam_database"].sort, (paths.map {|px| px.cleanpath.to_s}).sort
8
+ end
9
+
10
+ def test_myisam_database_dirs
11
+ s = std_myisam
12
+ assert_equal s.datadir, '/tmp'
13
+ result = s.myisam_database_dirs
14
+ assert_equal [Pathname.new('/tmp/mock_myisam_database')], result
15
+ end
16
+
17
+ protected
18
+
19
+ def std_myisam
20
+ MysqlBackup::Entity::Files::Myisam.new :datadir => @basedir
21
+ end
22
+
23
+ def setup
24
+ @basedir = '/tmp'
25
+ @basepath = Pathname.new @basedir
26
+ p = @basepath + 'mock_myisam_database'
27
+ p.mkdir
28
+ q = p + 'foo.MYD'
29
+ q.open 'w' do |qf|
30
+ qf << 'testing'
31
+ end
32
+ end
33
+
34
+ def teardown
35
+ p = @basepath + 'mock_myisam_database'
36
+ Pathname.glob(p + '*').each do |f|
37
+ f.unlink
38
+ end
39
+ p.rmdir
40
+ Pathname.glob(@basepath + 'fakeinnodb*').each {|pr| pr.delete}
41
+ end
42
+ end
@@ -0,0 +1,51 @@
1
+ require 'rubygems'
2
+ require File.dirname(__FILE__) + '/../test_helper'
3
+ require 'mysql_backup/entity/identifier'
4
+
5
+ class MysqlBackup::Entity::IdentifierTest < Test::Unit::TestCase
6
+ def test_initialize
7
+ n = MysqlBackup::Entity::Identifier.create_object :category => :full, :type => :mysqldump
8
+ assert_kind_of MysqlBackup::Entity::Identifier, n
9
+ assert_equal "full:type_mysqldump:log_file_:log_position_0000000000:n_parts_0000000000:part_number_0000000000", n.to_s
10
+ end
11
+
12
+ def test_object_creation
13
+ n = MysqlBackup::Entity::Identifier.create_object :category => :full, :type => :binary
14
+ assert_kind_of MysqlBackup::Entity::Identifier::Full::Binary, n
15
+ end
16
+
17
+ def test_create_object_with_string
18
+ # Current files
19
+ s = 'log:type_current:log_file_thelog.0000000006:log_position_0000000311:n_parts_0000000001:part_number_0000000000'
20
+ n = MysqlBackup::Entity::Identifier.create_object :string => s
21
+ assert_equal 'log:type_current:log_file_thelog.0000000006:log_position_0000000311', n.to_s
22
+ assert_kind_of MysqlBackup::Entity::Identifier::Log::Current, n
23
+ assert_no_match(/n_parts/, n.to_s)
24
+
25
+ # Complete files
26
+ s = 'log:type_complete:log_file_thelog.0000000006'
27
+ n = MysqlBackup::Entity::Identifier.create_object :string => s
28
+ assert_equal s, n.to_s
29
+ assert_kind_of MysqlBackup::Entity::Identifier::Log::Complete, n
30
+ end
31
+
32
+ def test_class_string_to_args
33
+ a = MysqlBackup::Entity::Identifier.string_to_args('log:type_complete:log_file_thelog.000001')
34
+ assert_equal :log, a[:category]
35
+ assert_equal :complete, a[:type]
36
+ assert_equal 'thelog.000001', a[:log_file]
37
+
38
+ a = MysqlBackup::Entity::Identifier.string_to_args('log:type_current:log_file_thelog.0000000006:log_position_0000000311:n_parts_0000000001:part_number_0000000000')
39
+ assert_equal 311, a[:log_position]
40
+ assert_equal 0, a[:part_number]
41
+
42
+ # log:type_current:log_file_thelog.0000000006:log_position_0000000311:n_parts_0000000001:part_number_0000000000
43
+ # full:type_mysqldump:log_file_thelog.0000000006:log_position_0000000382:n_parts_0000000001:part_number_0000000000
44
+ # full:type_binary:log_file_thelog.0000000006:log_position_0000000311:n_parts_0000000001:part_number_0000000000
45
+ end
46
+
47
+ def test_log_file_number
48
+ t = MysqlBackup::Entity::Identifier.new :log_file => 'testing.003'
49
+ assert_equal 3, t.log_file_number
50
+ end
51
+ end
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+ require 'mysql_backup/entity/logs'
3
+
4
+ class MysqlBackup::Entity::LogsTest < Test::Unit::TestCase
5
+ def test_save
6
+ l = MysqlBackup::Entity::Logs.new :log_file => 'foo.0001', :log_position => 3, :completed_logs => ['foo.0001'], :log_bin_dir => '/tmp'
7
+ expects(:must_call).times(2)
8
+ l.save do |i|
9
+ must_call
10
+ assert_equal 'foo.0001', i[:identifier].log_file
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,64 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper'
2
+ require 'mysql_backup/entity/mysqldump'
3
+
4
+ class MysqlBackup::Entity::MysqldumpTest < Test::Unit::TestCase
5
+ def test_create
6
+ mysqldump_obj = MysqlBackup::Entity::Mysqldump.new
7
+ (mysqldump_obj.expects(:system).with {|m| m =~ /mysqldump --opt/ && m !~ /#</}).returns true
8
+ mysqldump_obj.expects(:get_log_position).returns(true)
9
+ mysqldump_obj.expects(:compress_and_split).returns([stub])
10
+ expects(:must_call)
11
+ mysqldump_obj.create do |args|
12
+ must_call
13
+ i = args[:identifier]
14
+ assert_equal 0, i.part_number
15
+ assert_equal 1, i.n_parts
16
+ end
17
+ end
18
+
19
+ def test_get_log_position
20
+ m = MysqlBackup::Entity::Mysqldump.new
21
+ m.get_log_position mysqldump_sample_data
22
+ assert_equal 'thelog.000005', m.log_file
23
+ assert_equal 1234, m.log_position
24
+ end
25
+
26
+ def mysqldump_sample_data
27
+ StringIO.new <<-EOS
28
+ -- MySQL dump 10.10
29
+ --
30
+ -- Host: localhost Database: test
31
+ -- ------------------------------------------------------
32
+ -- Server version 5.0.27-standard-log
33
+
34
+ /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
35
+ /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
36
+ /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
37
+ /*!40101 SET NAMES utf8 */;
38
+ /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
39
+ /*!40103 SET TIME_ZONE='+00:00' */;
40
+ /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
41
+ /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0
42
+ */;
43
+ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
44
+ /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
45
+
46
+ --
47
+ -- Position to start replication or point-in-time recovery from
48
+ --
49
+
50
+ -- CHANGE MASTER TO MASTER_LOG_FILE='thelog.000005', MASTER_LOG_POS=1234;
51
+ /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
52
+
53
+ /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
54
+ /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
55
+ /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
56
+ /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
57
+ /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
58
+ /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
59
+ /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
60
+
61
+ -- Dump completed on 2007-06-05 0:53:56
62
+ EOS
63
+ end
64
+ end