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.
- data/History.txt +5 -0
- data/Manifest.txt +38 -0
- data/README.txt +122 -0
- data/Rakefile +18 -0
- data/bin/sqlup +107 -0
- data/bin/sqlup_control +25 -0
- data/config/environment.rb +0 -0
- data/lib/mysql_backup/entity/files/innodb.rb +77 -0
- data/lib/mysql_backup/entity/files/myisam.rb +62 -0
- data/lib/mysql_backup/entity/files.rb +95 -0
- data/lib/mysql_backup/entity/identifier.rb +179 -0
- data/lib/mysql_backup/entity/logs.rb +44 -0
- data/lib/mysql_backup/entity/mysqldump.rb +57 -0
- data/lib/mysql_backup/entity.rb +38 -0
- data/lib/mysql_backup/librarian/backup.rb +134 -0
- data/lib/mysql_backup/librarian/backup_collection.rb +63 -0
- data/lib/mysql_backup/librarian.rb +176 -0
- data/lib/mysql_backup/server.rb +237 -0
- data/lib/mysql_backup/storage/s3.rb +110 -0
- data/lib/mysql_backup/storage.rb +13 -0
- data/lib/mysql_backup/utilities/factory_create_method.rb +51 -0
- data/lib/mysql_backup.rb +8 -0
- data/lib/sqlup.rb +2 -0
- data/test/unit/mysql_backup/entity/files/files_test.rb +45 -0
- data/test/unit/mysql_backup/entity/files/innodb_test.rb +50 -0
- data/test/unit/mysql_backup/entity/files/myisam_test.rb +42 -0
- data/test/unit/mysql_backup/entity/identifier_test.rb +51 -0
- data/test/unit/mysql_backup/entity/logs_test.rb +13 -0
- data/test/unit/mysql_backup/entity/mysqldump_test.rb +64 -0
- data/test/unit/mysql_backup/librarian/backup_collection_test.rb +52 -0
- data/test/unit/mysql_backup/librarian/backup_test.rb +25 -0
- data/test/unit/mysql_backup/librarian/librarian_test.rb +103 -0
- data/test/unit/mysql_backup/server_test.rb +63 -0
- data/test/unit/mysql_backup/storage/s3_test.rb +69 -0
- data/test/unit/mysql_backup/storage/test_helper.rb +1 -0
- data/test/unit/mysql_backup/test_helper.rb +1 -0
- data/test/unit/mysql_backup/utilities/test_helper.rb +1 -0
- data/test/unit/test_helper.rb +10 -0
- 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,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
|
data/lib/mysql_backup.rb
ADDED
data/lib/sqlup.rb
ADDED
@@ -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
|