flydata 0.6.3 → 0.6.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/bin/fdredshift +78 -0
- data/circle.yml +1 -1
- data/ext/flydata/{parser/mysql → source_mysql/parser}/.gitignore +0 -0
- data/ext/flydata/{parser/mysql → source_mysql/parser}/dump_parser_ext.cpp +3 -3
- data/ext/flydata/source_mysql/parser/extconf.rb +3 -0
- data/ext/flydata/{parser/mysql → source_mysql/parser}/parser.txt +0 -0
- data/ext/flydata/{parser/mysql → source_mysql/parser}/sql_parser.cpp +0 -0
- data/ext/flydata/{parser/mysql → source_mysql/parser}/sql_parser.h +0 -0
- data/flydata-core/lib/flydata-core/mysql/binlog_pos.rb +34 -32
- data/flydata-core/lib/flydata-core/mysql/compatibility_checker.rb +20 -0
- data/flydata-core/lib/flydata-core/table_def/mysql_table_def.rb +12 -4
- data/flydata-core/lib/flydata-core/table_def/redshift_table_def.rb +60 -6
- data/flydata-core/spec/mysql/binlog_pos_spec.rb +474 -0
- data/flydata-core/spec/table_def/mysql_table_def_spec.rb +57 -0
- data/flydata-core/spec/table_def/mysql_to_redshift_table_def_spec.rb +174 -20
- data/flydata-core/spec/table_def/mysqldump_test_col_comment_with_AUTO_INCREMENT_keyword.dump +43 -0
- data/flydata-core/spec/table_def/mysqldump_test_col_comment_with_not_null_keyword.dump +43 -0
- data/flydata-core/spec/table_def/mysqldump_test_col_comment_with_unique_keyword.dump +43 -0
- data/flydata-core/spec/table_def/mysqldump_test_col_comment_with_unsigned_keyword.dump +43 -0
- data/flydata-core/spec/table_def/redshift_table_def_spec.rb +41 -8
- data/flydata.gemspec +0 -0
- data/lib/flydata/cli.rb +11 -5
- data/lib/flydata/command/base.rb +14 -1
- data/lib/flydata/command/exclusive_runnable.rb +42 -12
- data/lib/flydata/command/helper.rb +6 -6
- data/lib/flydata/command/sender.rb +4 -3
- data/lib/flydata/command/setup.rb +30 -381
- data/lib/flydata/command/stop.rb +1 -0
- data/lib/flydata/command/sync.rb +273 -301
- data/lib/flydata/compatibility_check.rb +24 -117
- data/lib/flydata/fluent-plugins/in_mysql_binlog_flydata.rb +3 -3
- data/lib/flydata/fluent-plugins/mysql/alter_table_query_handler.rb +2 -2
- data/lib/flydata/fluent-plugins/mysql/binlog_record_handler.rb +6 -6
- data/lib/flydata/fluent-plugins/mysql/truncate_table_query_handler.rb +0 -1
- data/lib/flydata/parser.rb +14 -0
- data/lib/flydata/{parser_provider.rb → parser/parser_provider.rb} +6 -4
- data/lib/flydata/parser/source_table.rb +33 -0
- data/lib/flydata/source.rb +105 -0
- data/lib/flydata/source/component.rb +21 -0
- data/lib/flydata/source/errors.rb +7 -0
- data/lib/flydata/source/generate_source_dump.rb +72 -0
- data/lib/flydata/source/parse_dump_and_send.rb +52 -0
- data/lib/flydata/source/setup.rb +31 -0
- data/lib/flydata/source/source_pos.rb +45 -0
- data/lib/flydata/source/sync.rb +56 -0
- data/lib/flydata/source/sync_generate_table_ddl.rb +43 -0
- data/lib/flydata/source_file/setup.rb +17 -0
- data/lib/flydata/source_file/sync.rb +14 -0
- data/lib/flydata/{command → source_mysql/command}/mysql.rb +2 -1
- data/lib/flydata/{command → source_mysql/command}/mysql_command_base.rb +2 -4
- data/lib/flydata/{command → source_mysql/command}/mysqlbinlog.rb +2 -1
- data/lib/flydata/{command → source_mysql/command}/mysqldump.rb +2 -1
- data/lib/flydata/source_mysql/generate_source_dump.rb +53 -0
- data/lib/flydata/source_mysql/mysql_compatibility_check.rb +114 -0
- data/lib/flydata/source_mysql/parse_dump_and_send.rb +28 -0
- data/lib/flydata/{parser/mysql → source_mysql/parser}/.gitignore +0 -0
- data/lib/flydata/{parser/mysql → source_mysql/parser}/dump_parser.rb +32 -67
- data/lib/flydata/{parser/mysql → source_mysql/parser}/mysql_alter_table.treetop +0 -0
- data/lib/flydata/source_mysql/setup.rb +24 -0
- data/lib/flydata/source_mysql/source_pos.rb +21 -0
- data/lib/flydata/source_mysql/sync.rb +45 -0
- data/lib/flydata/source_mysql/sync_generate_table_ddl.rb +40 -0
- data/lib/flydata/{mysql → source_mysql}/table_ddl.rb +6 -17
- data/lib/flydata/source_zendesk/sync_generate_table_ddl.rb +30 -0
- data/lib/flydata/source_zendesk/zendesk_flydata_tabledefs.rb +133 -0
- data/lib/flydata/sync_file_manager.rb +132 -73
- data/lib/flydata/table_ddl.rb +18 -0
- data/spec/flydata/cli_spec.rb +1 -0
- data/spec/flydata/command/exclusive_runnable_spec.rb +19 -8
- data/spec/flydata/command/sender_spec.rb +1 -1
- data/spec/flydata/command/setup_spec.rb +4 -4
- data/spec/flydata/command/sync_spec.rb +97 -134
- data/spec/flydata/compatibility_check_spec.rb +16 -289
- data/spec/flydata/fluent-plugins/mysql/alter_table_query_handler_spec.rb +3 -3
- data/spec/flydata/fluent-plugins/mysql/dml_record_handler_spec.rb +1 -1
- data/spec/flydata/fluent-plugins/mysql/shared_query_handler_context.rb +4 -2
- data/spec/flydata/fluent-plugins/mysql/truncate_query_handler_spec.rb +1 -1
- data/spec/flydata/source_mysql/generate_source_dump_spec.rb +69 -0
- data/spec/flydata/source_mysql/mysql_compatibility_check_spec.rb +280 -0
- data/spec/flydata/{parser/mysql → source_mysql/parser}/alter_table_parser_spec.rb +2 -2
- data/spec/flydata/{parser/mysql → source_mysql/parser}/dump_parser_spec.rb +75 -70
- data/spec/flydata/source_mysql/sync_generate_table_ddl_spec.rb +137 -0
- data/spec/flydata/{mysql → source_mysql}/table_ddl_spec.rb +2 -2
- data/spec/flydata/source_spec.rb +140 -0
- data/spec/flydata/source_zendesk/sync_generate_table_ddl_spec.rb +33 -0
- data/spec/flydata/sync_file_manager_spec.rb +157 -77
- data/tmpl/redshift_mysql_data_entry.conf.tmpl +1 -1
- metadata +56 -23
- data/ext/flydata/parser/mysql/extconf.rb +0 -3
- data/lib/flydata/mysql/binlog_position.rb +0 -22
- data/spec/flydata/mysql/binlog_position_spec.rb +0 -35
@@ -0,0 +1,18 @@
|
|
1
|
+
module Flydata
|
2
|
+
|
3
|
+
class TableDdl
|
4
|
+
VERSION0 = 0 # the version where no .generated_ddl file was generated.
|
5
|
+
# Therefore, this version never shows up in anywhere.
|
6
|
+
VERSION1 = 1 # the version which doesn't handle server side encoding support.
|
7
|
+
VERSION2 = 2 # the version with server side encoding support, migrated from
|
8
|
+
# the previous versions. Format/functionality-wise, it's the
|
9
|
+
# same as Version 3.
|
10
|
+
VERSION3 = 3 # the version with server side encoding support, generated by
|
11
|
+
# sync:generated_table_ddl command.
|
12
|
+
VERSION4 = 4 # the version with server side encoding support, generated by
|
13
|
+
# the auto-generated CREATE TABLE event.
|
14
|
+
|
15
|
+
VERSION = VERSION3
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/spec/flydata/cli_spec.rb
CHANGED
@@ -23,12 +23,23 @@ describe Exclusiverunnabletest do
|
|
23
23
|
let(:subject_object) { described_class.new }
|
24
24
|
|
25
25
|
let(:file_path) { "/tmp" }
|
26
|
-
let(:
|
27
|
-
let(:
|
26
|
+
let(:info_file) { File.join(file_path, 'exclusive_run.info') }
|
27
|
+
let(:info_command) { 'exclusiverunnabletest:long_running_command' }
|
28
|
+
let(:dummy_pid) { 11234 }
|
29
|
+
let(:info_file_content) { { command: info_command, pid: dummy_pid } }
|
30
|
+
let(:opts) { double('opts') }
|
31
|
+
let(:force_run) { false }
|
28
32
|
|
33
|
+
before do
|
34
|
+
File.unlink info_file if File.exists? info_file
|
35
|
+
end
|
29
36
|
before do
|
30
37
|
described_class.exclusive_run_home = file_path
|
31
38
|
end
|
39
|
+
before do
|
40
|
+
allow(subject_object).to receive(:opts).and_return opts
|
41
|
+
allow(opts).to receive(:force_run?).and_return force_run
|
42
|
+
end
|
32
43
|
|
33
44
|
describe '#normal_method_call' do
|
34
45
|
subject { subject_object.normal_method_call }
|
@@ -38,17 +49,17 @@ describe Exclusiverunnabletest do
|
|
38
49
|
|
39
50
|
context "when a lock file already exists" do
|
40
51
|
before do
|
41
|
-
File.open(
|
52
|
+
File.open(info_file, "w") {|f| f.write(info_file_content)}
|
42
53
|
end
|
43
54
|
|
44
55
|
it "does not delete the lock file" do
|
45
56
|
expect{ subject }.to raise_error
|
46
57
|
|
47
|
-
expect(File.exists?(
|
58
|
+
expect(File.exists?(info_file)).to eq true
|
48
59
|
end
|
49
60
|
|
50
61
|
after do
|
51
|
-
File.delete(
|
62
|
+
File.delete(info_file) if File.exists?(info_file)
|
52
63
|
end
|
53
64
|
end
|
54
65
|
end
|
@@ -62,7 +73,7 @@ describe Exclusiverunnabletest do
|
|
62
73
|
|
63
74
|
sleep 0.1
|
64
75
|
|
65
|
-
expect(File.exists?(
|
76
|
+
expect(File.exists?(info_file)).to eq true
|
66
77
|
|
67
78
|
th.join
|
68
79
|
end
|
@@ -73,7 +84,7 @@ describe Exclusiverunnabletest do
|
|
73
84
|
|
74
85
|
th.join
|
75
86
|
|
76
|
-
expect(File.exists?(
|
87
|
+
expect(File.exists?(info_file)).to eq false
|
77
88
|
end
|
78
89
|
end
|
79
90
|
end
|
@@ -83,7 +94,7 @@ describe Exclusiverunnabletest do
|
|
83
94
|
th = Thread.new{ subject }
|
84
95
|
sleep 0.1
|
85
96
|
expect{ subject_object.normal_method_call }.to raise_exception(
|
86
|
-
|
97
|
+
/`#{info_command}` is already running or terminated abnormally. \(pid:[0-9]+\)/)
|
87
98
|
|
88
99
|
th.join
|
89
100
|
end
|
@@ -23,7 +23,7 @@ module Flydata
|
|
23
23
|
allow(data_port).to receive(:get).and_return("Wibble")
|
24
24
|
|
25
25
|
allow_any_instance_of(Flydata::AgentCompatibilityCheck).to receive(:check).and_return(true)
|
26
|
-
Flydata::Command::Sync.any_instance.should_receive(:
|
26
|
+
Flydata::Command::Sync.any_instance.should_receive(:try_initial_sync).and_return("Wobble")
|
27
27
|
end
|
28
28
|
|
29
29
|
context "as daemon" do
|
@@ -19,21 +19,21 @@ module Flydata
|
|
19
19
|
before do
|
20
20
|
allow(subject).to receive(:retrieve_data_entries).and_return(data_entries)
|
21
21
|
allow(subject).to receive(:flydata).and_return(flydata)
|
22
|
-
|
22
|
+
allow(flydata).to receive(:data_port).and_return(data_port)
|
23
23
|
allow(flydata).to receive(:flydata_api_host).and_return('localhost')
|
24
24
|
expect(flydata).to receive(:credentials).and_return(credentials)
|
25
25
|
expect(credentials).to receive(:authenticated?).and_return(false)
|
26
|
-
|
26
|
+
allow(data_port).to receive(:get).and_return(dp)
|
27
27
|
expect(sender).to receive(:process_exist?).and_return(true)
|
28
28
|
expect(sender).to receive(:stop)
|
29
|
-
|
29
|
+
allow(sync_fm).to receive(:source_pos_path).and_return('/tmp')
|
30
30
|
expect(conf).to receive(:copy_templates)
|
31
31
|
expect(login).to receive(:run)
|
32
32
|
expect(sender).to receive(:restart)
|
33
|
+
allow(Flydata::SyncFileManager).to receive(:new).with(de).and_return(sync_fm)
|
33
34
|
end
|
34
35
|
it do
|
35
36
|
expect(Flydata::Command::Conf).to receive(:new).and_return(conf)
|
36
|
-
expect(Flydata::SyncFileManager).to receive(:new).with(de).and_return(sync_fm)
|
37
37
|
expect(Flydata::Command::Login).to receive(:new).and_return(login)
|
38
38
|
expect(Flydata::Command::Sender).to receive(:new).and_return(sender).twice
|
39
39
|
|
@@ -5,10 +5,10 @@ require 'flydata/command/sync'
|
|
5
5
|
module Flydata
|
6
6
|
module Command
|
7
7
|
describe Sync do
|
8
|
-
let(:subject_object){ described_class.new }
|
9
8
|
subject { subject_object }
|
9
|
+
let(:subject_object){ described_class.new }
|
10
10
|
|
11
|
-
let(:
|
11
|
+
let(:default_dump_dir) do
|
12
12
|
File.join('/tmp', "sync_dump_#{Time.now.to_i}")
|
13
13
|
end
|
14
14
|
let(:default_data_entry) do
|
@@ -36,7 +36,7 @@ module Flydata
|
|
36
36
|
"password"=>"welcome", "database"=>"sync_test", "tables"=>["table1", "table2", "table4"],
|
37
37
|
"invalid_tables"=>["table3"],
|
38
38
|
"new_tables"=>["table4"],
|
39
|
-
"
|
39
|
+
"dump_dir"=>default_dump_dir, "forwarder" => "tcpforwarder",
|
40
40
|
"data_servers"=>"localhost:9905" }
|
41
41
|
}
|
42
42
|
end
|
@@ -46,16 +46,12 @@ module Flydata
|
|
46
46
|
let(:mysql_table_columns) {
|
47
47
|
{"id"=>{:column_name=>"id", :format_type_str=>"int(11)", :format_type=>"int", :format_size=>11}, "name"=>{:column_name=>"name", :format_type_str=>"varchar(40)", :format_type=>"varchar", :format_size=>40, :default=>nil}, "created_at"=>{:column_name=>"created_at", :format_type_str=>"timestamp", :format_type=>"timestamp", :default=>"CURRENT_TIMESTAMP"}, "bin"=>{:column_name=>"bin", :format_type_str=>col4_type_str, :format_type=>col4_type, :format_size=>col4_width, :default=>nil}, "bin2"=>{:column_name=>"bin2", :format_type_str=>"blob", :format_type=>"blob"}, "varbin"=>{:column_name=>"varbin", :format_type_str=>"varchar(34)", :format_type=>"varchar", :format_size=>34, :default=>nil}}
|
48
48
|
}
|
49
|
-
let(:mysql_table) do
|
50
|
-
Flydata::Parser::Mysql::MysqlTable.new("test_table", mysql_table_columns, ['id'])
|
51
|
-
end
|
52
|
-
|
53
49
|
after :each do
|
54
|
-
if Dir.exists?(
|
55
|
-
Dir.delete(
|
50
|
+
if Dir.exists?(default_dump_dir)
|
51
|
+
Dir.delete(default_dump_dir) rescue nil
|
56
52
|
end
|
57
|
-
if File.exists?(
|
58
|
-
File.delete(
|
53
|
+
if File.exists?(default_dump_dir)
|
54
|
+
File.delete(default_dump_dir) rescue nil
|
59
55
|
end
|
60
56
|
end
|
61
57
|
|
@@ -78,7 +74,7 @@ module Flydata
|
|
78
74
|
end
|
79
75
|
end
|
80
76
|
end
|
81
|
-
describe '#
|
77
|
+
describe '#generate_source_dump' do
|
82
78
|
let (:flydata) { double('flydata') }
|
83
79
|
let (:dp) { double('dp') }
|
84
80
|
let (:default_data_port) { double('default_data_port') }
|
@@ -92,10 +88,15 @@ module Flydata
|
|
92
88
|
let (:target_tables) { ["test_table_1"] }
|
93
89
|
let (:db_byte) { 1 }
|
94
90
|
let (:disk_byte) { 100 }
|
91
|
+
before do
|
92
|
+
require 'flydata/source_mysql/generate_source_dump'
|
93
|
+
allow_any_instance_of(Flydata::SourceMysql::GenerateSourceDump).to receive(:dump_size).and_return(db_byte)
|
94
|
+
allow_any_instance_of(Flydata::SourceMysql::GenerateSourceDump).to receive(:run_compatibility_check)
|
95
|
+
end
|
95
96
|
before do
|
96
97
|
expect(subject).to receive(:flydata).and_return(flydata).at_least(:once)
|
98
|
+
allow(subject).to receive(:data_entry).and_return(default_data_entry)
|
97
99
|
expect(flydata).to receive(:data_port).and_return(dp)
|
98
|
-
allow(flydata).to receive(:data_entry).and_return(default_data_entry)
|
99
100
|
expect(dp).to receive(:get).and_return(default_data_port)
|
100
101
|
allow(File).to receive(:exists?).and_return(false)
|
101
102
|
expect(default_sync_fm).to receive(:load_dump_pos).and_return(default_dump_pos)
|
@@ -106,8 +107,6 @@ module Flydata
|
|
106
107
|
expect(subject).to receive(:log_info)
|
107
108
|
expect(subject).to receive(:log_info_stdout).at_least(:once)
|
108
109
|
expect(subject).to receive(:ask_yes_no).and_return(true).at_least(:once)
|
109
|
-
Flydata::Parser::Mysql::DatabaseSizeCheck.any_instance.should_receive(:get_db_bytesize).and_return(db_byte)
|
110
|
-
Flydata::MysqlCompatibilityCheck.any_instance.should_receive(:check)
|
111
110
|
expect_any_instance_of(FlydataCore::Event::ApiEventSender).to receive(:send_event).once
|
112
111
|
end
|
113
112
|
context 'with no stream option' do
|
@@ -118,145 +117,43 @@ module Flydata
|
|
118
117
|
end
|
119
118
|
it 'will export to dump file' do
|
120
119
|
expect(subject).to receive(:call_block_or_return_io)
|
121
|
-
Flydata::
|
120
|
+
expect_any_instance_of(Flydata::SourceMysql::GenerateSourceDump).
|
121
|
+
to receive(:dump).with(target_tables, default_fp)
|
122
122
|
|
123
|
-
subject.send(:
|
123
|
+
subject.send(:generate_source_dump, default_data_entry, default_sync_fm)
|
124
124
|
end
|
125
125
|
it 'will remove dump file on interrupt' do
|
126
126
|
expect(default_sync_fm).to receive(:delete_dump_file)
|
127
|
+
expect_any_instance_of(Flydata::SourceMysql::Parser::MysqlDumpGeneratorNoMasterData).to receive(:dump).and_raise(Interrupt)
|
127
128
|
|
128
129
|
expect {
|
129
|
-
|
130
|
-
subject.send(:generate_mysqldump, default_data_entry, default_sync_fm)
|
130
|
+
subject.send(:generate_source_dump, default_data_entry, default_sync_fm)
|
131
131
|
}.to raise_error
|
132
132
|
end
|
133
133
|
end
|
134
134
|
context 'with stream option' do
|
135
135
|
it 'will export to io' do
|
136
136
|
expect(default_sync_fm).to receive(:save_sync_info).once
|
137
|
-
Flydata::Parser::
|
137
|
+
expect_any_instance_of(Flydata::SourceMysql::Parser::MysqlDumpGeneratorNoMasterData).to receive(:dump)
|
138
138
|
|
139
|
-
subject.send(:
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
describe '#do_generate_table_ddl' do
|
144
|
-
before do
|
145
|
-
allow(subject).to receive(:data_entry).and_return(default_data_entry)
|
146
|
-
allow_any_instance_of(Flydata::Api::DataEntry).to receive(:update_table_validity).and_return(true)
|
147
|
-
subject.send(:set_current_tables, nil, include_all_tables: true)
|
148
|
-
end
|
149
|
-
shared_examples 'throws an error' do
|
150
|
-
it "throws an error" do
|
151
|
-
expect {
|
152
|
-
subject.send(:do_generate_table_ddl, default_data_entry)
|
153
|
-
}.to raise_error
|
154
|
-
end
|
155
|
-
end
|
156
|
-
context 'with full options' do
|
157
|
-
it 'issues mysqldump command with expected parameters' do
|
158
|
-
expect(Open3).to receive(:popen3).with(
|
159
|
-
'mysqldump -h localhost -P 3306 -umasashi -pwelcome --default-character-set=utf8 --protocol=tcp -d sync_test table1 table2 table4 table3')
|
160
|
-
subject.send(:do_generate_table_ddl, default_data_entry)
|
161
|
-
end
|
162
|
-
end
|
163
|
-
context 'without_host' do
|
164
|
-
before do
|
165
|
-
default_data_entry['mysql_data_entry_preference'].delete('host')
|
166
|
-
end
|
167
|
-
include_examples 'throws an error'
|
168
|
-
end
|
169
|
-
context 'with empty host' do
|
170
|
-
before do
|
171
|
-
default_data_entry['mysql_data_entry_preference']['host'] = ""
|
172
|
-
end
|
173
|
-
include_examples 'throws an error'
|
174
|
-
end
|
175
|
-
context 'without_port' do
|
176
|
-
before do
|
177
|
-
default_data_entry['mysql_data_entry_preference'].delete('port')
|
178
|
-
end
|
179
|
-
it "uses the default port" do
|
180
|
-
expect(Open3).to receive(:popen3).with(
|
181
|
-
'mysqldump -h localhost -umasashi -pwelcome --default-character-set=utf8 --protocol=tcp -d sync_test table1 table2 table4 table3')
|
182
|
-
subject.send(:do_generate_table_ddl, default_data_entry)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
context 'with_port_override' do
|
186
|
-
before do
|
187
|
-
default_data_entry['mysql_data_entry_preference']['port'] = 1234
|
188
|
-
end
|
189
|
-
it "uses the specified port" do
|
190
|
-
expect(Open3).to receive(:popen3).with(
|
191
|
-
'mysqldump -h localhost -P 1234 -umasashi -pwelcome --default-character-set=utf8 --protocol=tcp -d sync_test table1 table2 table4 table3')
|
192
|
-
subject.send(:do_generate_table_ddl, default_data_entry)
|
193
|
-
end
|
194
|
-
end
|
195
|
-
context 'without_username' do
|
196
|
-
before do
|
197
|
-
default_data_entry['mysql_data_entry_preference'].delete('username')
|
198
|
-
end
|
199
|
-
include_examples 'throws an error'
|
200
|
-
end
|
201
|
-
context 'with empty username' do
|
202
|
-
before do
|
203
|
-
default_data_entry['mysql_data_entry_preference']['username'] = ""
|
204
|
-
end
|
205
|
-
include_examples 'throws an error'
|
206
|
-
end
|
207
|
-
context 'without_password' do
|
208
|
-
before do
|
209
|
-
default_data_entry['mysql_data_entry_preference'].delete('password')
|
210
|
-
end
|
211
|
-
it "call mysqldump without MYSQL_PW set" do
|
212
|
-
expect(Open3).to receive(:popen3).with(
|
213
|
-
'mysqldump -h localhost -P 3306 -umasashi --default-character-set=utf8 --protocol=tcp -d sync_test table1 table2 table4 table3')
|
214
|
-
subject.send(:do_generate_table_ddl, default_data_entry)
|
215
|
-
end
|
216
|
-
end
|
217
|
-
context 'with password containing symbols' do
|
218
|
-
before do
|
219
|
-
default_data_entry['mysql_data_entry_preference'].delete('password')
|
220
|
-
default_data_entry['mysql_data_entry_preference']['password']="welcome&!@^@#^"
|
221
|
-
end
|
222
|
-
it "call mysqldump with MYSQL_PW set with correct symbols" do
|
223
|
-
expect(Open3).to receive(:popen3).with(
|
224
|
-
'mysqldump -h localhost -P 3306 -umasashi -pwelcome\\&\\!@\\^@\\#\\^ --default-character-set=utf8 --protocol=tcp -d sync_test table1 table2 table4 table3')
|
225
|
-
subject.send(:do_generate_table_ddl, default_data_entry)
|
226
|
-
end
|
227
|
-
end
|
228
|
-
context 'without_database' do
|
229
|
-
before do
|
230
|
-
default_data_entry['mysql_data_entry_preference'].delete('database')
|
231
|
-
end
|
232
|
-
include_examples 'throws an error'
|
233
|
-
end
|
234
|
-
context 'with empty database' do
|
235
|
-
before do
|
236
|
-
default_data_entry['mysql_data_entry_preference']['database'] = ""
|
237
|
-
end
|
238
|
-
include_examples 'throws an error'
|
239
|
-
end
|
240
|
-
context 'with empty tables' do
|
241
|
-
let(:sync_cmd) { described_class.new }
|
242
|
-
before do
|
243
|
-
default_data_entry['mysql_data_entry_preference']['tables'] = []
|
244
|
-
default_data_entry['mysql_data_entry_preference']['invalid_tables'] = []
|
245
|
-
default_data_entry['mysql_data_entry_preference']['new_tables'] = []
|
246
|
-
allow(sync_cmd).to receive(:data_entry).and_return(default_data_entry)
|
247
|
-
sync_cmd.send(:set_current_tables, nil, include_all_tables: true)
|
248
|
-
end
|
249
|
-
it 'should raise error' do
|
250
|
-
expect{sync_cmd.send(:do_generate_table_ddl, default_data_entry)}.to raise_error
|
139
|
+
subject.send(:generate_source_dump, default_data_entry, default_sync_fm, false)
|
251
140
|
end
|
252
141
|
end
|
253
142
|
end
|
254
143
|
describe '#convert_to_flydata_values' do
|
255
|
-
subject { subject_object.send(:convert_to_flydata_values,
|
144
|
+
subject { subject_object.send(:convert_to_flydata_values, source_table, values) }
|
256
145
|
let(:values) { [4, 'John', nil, col4_value, nil, nil] }
|
257
146
|
|
147
|
+
let(:source_table) do
|
148
|
+
Flydata::Parser::SourceTable.new("test_table", mysql_table_columns, ['id'])
|
149
|
+
end
|
150
|
+
|
258
151
|
before do
|
259
|
-
|
152
|
+
require 'flydata/parser/source_table'
|
153
|
+
end
|
154
|
+
|
155
|
+
before do
|
156
|
+
source_table.set_value_converters(FlydataCore::TableDef::MysqlTableDef::VALUE_CONVERTERS)
|
260
157
|
end
|
261
158
|
|
262
159
|
context 'with binary column' do
|
@@ -273,6 +170,72 @@ module Flydata
|
|
273
170
|
end
|
274
171
|
end
|
275
172
|
end
|
173
|
+
|
174
|
+
describe '#data_entry' do
|
175
|
+
subject { subject_object.send(:data_entry) }
|
176
|
+
|
177
|
+
let(:de) { { 'mysql_data_entry_preference' => mp } }
|
178
|
+
let(:mp) { { 'tables' => 'Users,Addresses' } }
|
179
|
+
|
180
|
+
let(:sfm) { double('sfm') }
|
181
|
+
let(:ssl_ca_content) { double('ssl_ca_content') }
|
182
|
+
let(:ssl_ca_path) { double('ssl_ca_path') }
|
183
|
+
|
184
|
+
before do
|
185
|
+
allow(subject_object).to receive(:retrieve_data_entries).
|
186
|
+
and_return([de])
|
187
|
+
end
|
188
|
+
|
189
|
+
context 'type RedshiftMysqlDataEntry' do
|
190
|
+
before { de['type'] = 'RedshiftMysqlDataEntry' }
|
191
|
+
context 'called once' do
|
192
|
+
before do
|
193
|
+
expect(subject_object).to receive(:retrieve_data_entries).
|
194
|
+
and_return([de])
|
195
|
+
end
|
196
|
+
context 'without tables_append_only' do
|
197
|
+
it "expands a table list string to an array of tables" do
|
198
|
+
subject
|
199
|
+
expect(mp['tables']).to eq %w(Users Addresses)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
context 'with tables_append_only' do
|
203
|
+
before { mp['tables_append_only'] = 'Invoices,Sessions,Addresses' }
|
204
|
+
it "creates an array of tables from 'tables' and 'tables_append_only' combined" do
|
205
|
+
subject
|
206
|
+
expect(mp['tables']).to eq %w(Users Addresses Invoices Sessions)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
context 'with ssl_ca_content' do
|
210
|
+
before { mp["ssl_ca_content"] = ssl_ca_content }
|
211
|
+
it "saves the content to a local file via SyncFileManager" do
|
212
|
+
expect(SyncFileManager).to receive(:new).with(de).
|
213
|
+
and_return(sfm)
|
214
|
+
expect(sfm).to receive(:save_ssl_ca).with(ssl_ca_content)
|
215
|
+
expect(sfm).to receive(:ssl_ca_path).and_return(ssl_ca_path)
|
216
|
+
|
217
|
+
subject
|
218
|
+
expect(mp['ssl_ca']).to eq ssl_ca_path
|
219
|
+
expect(mp['sslca']).to eq ssl_ca_path
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
context 'called twice' do
|
224
|
+
before { subject }
|
225
|
+
it "repurposes the saved de" do
|
226
|
+
expect(subject_object).to receive(:retrieve_data_entries).never
|
227
|
+
subject
|
228
|
+
expect(mp['tables']).to eq %w(Users Addresses)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
context 'type RedshiftFileDataEntry' do
|
233
|
+
before { de['type'] = 'RedshiftFileDataEntry' }
|
234
|
+
it "raises an error about unsupported data entry" do
|
235
|
+
expect { subject }.to raise_error /(supported data entry|data entry.*support)/
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
276
239
|
end
|
277
240
|
end
|
278
241
|
end
|
@@ -3,309 +3,36 @@ require 'flydata/compatibility_check'
|
|
3
3
|
|
4
4
|
module Flydata
|
5
5
|
describe AgentCompatibilityCheck do
|
6
|
+
let(:subject_object) { AgentCompatibilityCheck.new("servers" => ['localhost']) }
|
6
7
|
let(:default_data_port) do
|
7
8
|
{
|
8
9
|
"servers"=>["sample-test-site.com"]
|
9
10
|
}
|
10
|
-
end
|
11
|
-
|
12
|
-
describe "#check" do
|
13
|
-
subject { AgentCompatibilityCheck.new("servers" => ['localhost']) }
|
14
|
-
context "runs all check methods" do
|
15
|
-
context "when all ports are accessible" do
|
16
|
-
let(:sock) { double('sock') }
|
17
|
-
before do
|
18
|
-
allow(TCPSocket).to receive(:new).and_return(sock)
|
19
|
-
allow(sock).to receive(:close)
|
20
|
-
end
|
21
|
-
it "does nothing" do
|
22
|
-
subject.check
|
23
|
-
end
|
24
|
-
end
|
25
|
-
context "when a port access fails" do
|
26
|
-
before do
|
27
|
-
allow(TCPSocket).to receive(:new).and_raise(Errno::ETIMEDOUT)
|
28
|
-
end
|
29
|
-
it do
|
30
|
-
expect{subject.check_outgoing_ports}.to raise_error(FlydataCore::AgentCompatibilityError, /ports/)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
11
|
end
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
let(:default_data_port) do
|
39
|
-
{
|
40
|
-
"servers"=>["sample-test-site.com"]
|
41
|
-
}
|
42
|
-
end
|
43
|
-
|
44
|
-
let(:default_mysql_cred) do
|
45
|
-
{
|
46
|
-
"host" => "test",
|
47
|
-
"port" => 1234,
|
48
|
-
"username" => "test",
|
49
|
-
"password" => "password",
|
50
|
-
"database" => "test_db"
|
51
|
-
}
|
12
|
+
let(:sock) { double('sock') }
|
13
|
+
before do
|
14
|
+
allow(sock).to receive(:close)
|
52
15
|
end
|
53
16
|
|
54
|
-
describe "#
|
55
|
-
|
56
|
-
|
57
|
-
before do
|
58
|
-
allow(Mysql2::Client).to receive(:new).and_return(client)
|
59
|
-
allow(client).to receive(:close)
|
60
|
-
end
|
61
|
-
|
62
|
-
context "with all privileges in all databases" do
|
63
|
-
before do
|
64
|
-
allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT ALL PRIVILEGES ON *.* TO 'test'@'host"}])
|
65
|
-
end
|
66
|
-
it do
|
67
|
-
expect{subject.check_mysql_user_compat}.to_not raise_error
|
68
|
-
end
|
69
|
-
end
|
70
|
-
context "with missing privileges in one database" do
|
71
|
-
before do
|
72
|
-
allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT ALL PRIVILEGES ON 'mysql'.* TO 'test'@'host"},
|
73
|
-
{"Grants for test"=>"GRANT SELECT, RELOAD, REPLICATION CLIENT ON `test_db`.* TO 'test'@'host"}])
|
74
|
-
end
|
75
|
-
it do
|
76
|
-
expect{subject.check_mysql_user_compat}.to raise_error(FlydataCore::MysqlCompatibilityError, /test_db': LOCK TABLES, REPLICATION SLAVE/)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
context "with all required privileges in between all and specific databases" do
|
80
|
-
before do
|
81
|
-
allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT RELOAD, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'test'@'host"},
|
82
|
-
{"Grants for test"=>"GRANT SELECT, LOCK TABLES ON `test_db`.* TO 'test'@'host"},
|
83
|
-
{"Grants for test"=>"GRANT SELECT, LOCK TABLES ON `mysql`.* TO 'test'@'host"}])
|
84
|
-
end
|
85
|
-
it do
|
86
|
-
expect{subject.check_mysql_user_compat}.to_not raise_error
|
87
|
-
end
|
88
|
-
end
|
89
|
-
context "with missing privileges in each database" do
|
90
|
-
before do
|
91
|
-
allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'test'@'host"},
|
92
|
-
{"Grants for test"=>"GRANT SELECT, LOCK TABLES ON `test_db`.* TO 'test'@'host"},
|
93
|
-
{"Grants for test"=>"GRANT SELECT, LOCK TABLES ON `mysql`.* TO 'test'@'host"}])
|
94
|
-
end
|
95
|
-
it do
|
96
|
-
expect{subject.check_mysql_user_compat}.to raise_error(FlydataCore::MysqlCompatibilityError, /mysql': RELOAD\n.*test_db': RELOAD/)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
context "with all required privileges in all databases" do
|
100
|
-
before do
|
101
|
-
allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT SELECT, LOCK TABLES, RELOAD, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'test'@'host"}])
|
102
|
-
end
|
103
|
-
it do
|
104
|
-
expect{subject.check_mysql_user_compat}.to_not raise_error
|
105
|
-
end
|
106
|
-
end
|
107
|
-
context "with missing privileges in all databases" do
|
108
|
-
before do
|
109
|
-
allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT RELOAD, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'test'@'host"}])
|
110
|
-
end
|
111
|
-
it do
|
112
|
-
expect{subject.check_mysql_user_compat}.to raise_error(FlydataCore::MysqlCompatibilityError, /mysql': SELECT, LOCK TABLES\n.*test_db': SELECT, LOCK TABLES/)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
context "with privileges for other databases only" do
|
17
|
+
describe "#check" do
|
18
|
+
subject { subject_object.check }
|
19
|
+
context "when all ports are accessible" do
|
116
20
|
before do
|
117
|
-
allow(
|
118
|
-
{"Grants for test"=>"GRANT LOCK TABLES ON `test_db_02`.* TO 'test'@'host"},
|
119
|
-
{"Grants for test"=>"GRANT SELECT ON `text_db_03`.* TO 'test'@'host"}])
|
120
|
-
end
|
121
|
-
it do
|
122
|
-
expect{subject.check_mysql_user_compat}.to raise_error(FlydataCore::MysqlCompatibilityError, /mysql': SELECT, RELOAD, LOCK TABLES, REPLICATION SLAVE, REPLICATION CLIENT\n.*test_db': SELECT, RELOAD, LOCK TABLES, REPLICATION SLAVE, REPLICATION CLIENT/)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
end
|
127
|
-
|
128
|
-
describe "#check_mysql_binlog_retention" do
|
129
|
-
context "on on-premise mysql server" do
|
130
|
-
subject { MysqlCompatibilityCheck.new(default_data_port, default_mysql_cred) }
|
131
|
-
context "where retention is below limit" do
|
132
|
-
let(:client) { double('client') }
|
133
|
-
before do
|
134
|
-
allow(Mysql2::Client).to receive(:new).and_return(client)
|
135
|
-
allow(client).to receive(:query).and_return([{"Variable_name" => "expire_logs_days", "Value" => 1}])
|
136
|
-
allow(client).to receive(:close)
|
137
|
-
allow(subject).to receive(:is_rds?).and_return(false)
|
138
|
-
end
|
139
|
-
it do
|
140
|
-
expect{subject.check_mysql_binlog_retention}.to raise_error(FlydataCore::MysqlCompatibilityError, /expire_logs_days/)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
context "where retention is 0" do
|
144
|
-
let(:client) { double('client') }
|
145
|
-
before do
|
146
|
-
allow(Mysql2::Client).to receive(:new).and_return(client)
|
147
|
-
allow(client).to receive(:query).and_return([{"Variable_name" => "expire_logs_days", "Value" => 0}])
|
148
|
-
allow(client).to receive(:close)
|
149
|
-
allow(subject).to receive(:is_rds?).and_return(false)
|
150
|
-
end
|
151
|
-
it do
|
152
|
-
expect{subject.check_mysql_binlog_retention}.to_not raise_error
|
153
|
-
end
|
154
|
-
end
|
155
|
-
context "where retention is above limit" do
|
156
|
-
let(:client) { double('client') }
|
157
|
-
before do
|
158
|
-
allow(Mysql2::Client).to receive(:new).and_return(client)
|
159
|
-
allow(client).to receive(:query).and_return([{"expire_logs_days"=>11}])
|
160
|
-
allow(client).to receive(:query).and_return([{"Variable_name" => "expire_logs_days", "Value" => 11}])
|
161
|
-
allow(client).to receive(:close)
|
162
|
-
allow(subject).to receive(:is_rds?).and_return(false)
|
163
|
-
end
|
164
|
-
it do
|
165
|
-
expect{subject.check_mysql_binlog_retention}.to_not raise_error
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
context "on RDS" do
|
170
|
-
subject { MysqlCompatibilityCheck.new(default_data_port, default_mysql_cred) }
|
171
|
-
context "where retention period is nil" do
|
172
|
-
let(:client) { double('client') }
|
173
|
-
before do
|
174
|
-
allow(Mysql2::Client).to receive(:new).and_return(client)
|
175
|
-
allow(client).to receive(:query).with("SELECT @@expire_logs_days").and_return([{"@@expire_logs_days"=>0}])
|
176
|
-
allow(client).to receive(:query).with("call mysql.rds_show_configuration;").and_return([{"name"=>"binlog retention hours", "value"=>nil}])
|
177
|
-
allow(client).to receive(:close)
|
178
|
-
allow(subject).to receive(:is_rds?).and_return(true)
|
179
|
-
end
|
180
|
-
it do
|
181
|
-
expect{subject.check_mysql_binlog_retention}.to raise_error(FlydataCore::MysqlCompatibilityError, /rds_set_config/)
|
182
|
-
end
|
21
|
+
allow(TCPSocket).to receive(:new).and_return(sock)
|
183
22
|
end
|
184
|
-
|
185
|
-
|
186
|
-
before do
|
187
|
-
allow(Mysql2::Client).to receive(:new).and_return(client)
|
188
|
-
allow(client).to receive(:query).with("SELECT @@expire_logs_days").and_return([{"@@expire_logs_days"=>0}])
|
189
|
-
allow(client).to receive(:query).with("call mysql.rds_show_configuration;").and_return([{"name"=>"binlog retention hours", "value"=>4}])
|
190
|
-
allow(client).to receive(:close)
|
191
|
-
allow(subject).to receive(:is_rds?).and_return(true)
|
192
|
-
end
|
193
|
-
it do
|
194
|
-
expect{subject.check_mysql_binlog_retention}.to raise_error(FlydataCore::MysqlCompatibilityError, /rds_set_config/)
|
195
|
-
end
|
196
|
-
end
|
197
|
-
context "where retention period is over recommended limit" do
|
198
|
-
let(:client) { double('client') }
|
199
|
-
before do
|
200
|
-
allow(Mysql2::Client).to receive(:new).and_return(client)
|
201
|
-
allow(client).to receive(:query).with("SELECT @@expire_logs_days").and_return([{"@@expire_logs_days"=>0}])
|
202
|
-
allow(client).to receive(:query).with("call mysql.rds_show_configuration;").and_return([{"name"=>"binlog retention hours", "value"=>120}])
|
203
|
-
allow(client).to receive(:close)
|
204
|
-
allow(subject).to receive(:is_rds?).and_return(true)
|
205
|
-
end
|
206
|
-
it do
|
207
|
-
expect{subject.check_mysql_binlog_retention}.to_not raise_error
|
208
|
-
end
|
209
|
-
end
|
210
|
-
context "where user has no access to rds configuration" do
|
211
|
-
let(:client) { double('client') }
|
212
|
-
before do
|
213
|
-
allow(Mysql2::Client).to receive(:new).and_return(client)
|
214
|
-
allow(client).to receive(:query).with("SELECT @@expire_logs_days").and_return([{"@@expire_logs_days"=>0}])
|
215
|
-
allow(client).to receive(:query).with("call mysql.rds_show_configuration;").and_raise(Mysql2::Error, "execute command denied to user")
|
216
|
-
allow(client).to receive(:close)
|
217
|
-
allow(subject).to receive(:is_rds?).and_return(true)
|
218
|
-
end
|
219
|
-
it do
|
220
|
-
expect{subject.check_mysql_binlog_retention}.to_not raise_error
|
221
|
-
end
|
23
|
+
it "does nothing" do
|
24
|
+
subject
|
222
25
|
end
|
223
26
|
end
|
224
27
|
end
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
{ "host" => "test",
|
229
|
-
"port" => 1234,
|
230
|
-
"username" => "test",
|
231
|
-
"password" => "password",
|
232
|
-
"database" => "test_db",
|
233
|
-
"tables"=>["normal_table", "engine_table", "view_table"] }
|
234
|
-
end
|
235
|
-
let(:normal_table) { {"table_name"=>"normal_table", "table_type"=>"BASE TABLE", "engine"=>"InnoDB"} }
|
236
|
-
let(:engine_table) { {"table_name"=>"engine_table", "table_type"=>"BASE TABLE", "engine"=>"MEMORY"} }
|
237
|
-
let(:blackhole_table) { {"table_name"=>"blackhole_table", "table_type"=>"BASE TABLE", "engine"=>"BLACKHOLE"} }
|
238
|
-
let(:view) { {"table_name"=>"view_table", "table_type"=>"VIEW", "engine"=>nil} }
|
239
|
-
let(:client) { double('client') }
|
240
|
-
let(:subject_object) { MysqlCompatibilityCheck.new(default_data_port,test_data_entry, {}) }
|
241
|
-
let(:error) { FlydataCore::MysqlCompatibilityError }
|
242
|
-
let(:base_error_msg) { "FlyData does not support VIEW and MEMORY,BLACKHOLE STORAGE ENGINE table. Remove following tables from data entry: %s" }
|
243
|
-
subject { subject_object.check_mysql_table_types }
|
244
|
-
before do
|
245
|
-
allow(Mysql2::Client).to receive(:new).and_return(client)
|
246
|
-
allow(client).to receive(:query).and_return(table_list)
|
247
|
-
allow(client).to receive(:escape).and_return("aaa")
|
248
|
-
allow(client).to receive(:close)
|
249
|
-
end
|
250
|
-
context "where data entry has VIEW and MEMORY engine table" do
|
251
|
-
let(:error_msg) { base_error_msg % engine_table['table_name'] + ', ' + view['table_name'] }
|
252
|
-
let(:table_list) { [ engine_table, view ] }
|
253
|
-
it { expect{subject}.to raise_error(error, /#{error_msg}/) }
|
254
|
-
end
|
255
|
-
context "where data entry has MEMORY engine table" do
|
256
|
-
let(:error_msg) { base_error_msg % engine_table['table_name'] }
|
257
|
-
let(:table_list) { [ engine_table ] }
|
258
|
-
it { expect{subject}.to raise_error(error, /#{error_msg}/) }
|
259
|
-
end
|
260
|
-
context "where data entry has BLACKHOLE engine table" do
|
261
|
-
let(:error_msg) { base_error_msg % blackhole_table['table_name'] }
|
262
|
-
let(:table_list) { [ blackhole_table ] }
|
263
|
-
it { expect{subject}.to raise_error(error, /#{error_msg}/) }
|
264
|
-
end
|
265
|
-
context "where data entry has the VIEW" do
|
266
|
-
let(:error_msg) { base_error_msg % view['table_name'] }
|
267
|
-
let(:table_list) { [ view ] }
|
268
|
-
it { expect{subject}.to raise_error(error, /#{error_msg}/) }
|
269
|
-
end
|
270
|
-
context "where data entry does not have either VIEW and ENGINE table" do
|
271
|
-
let(:table_list) { [ normal_table ] }
|
272
|
-
it { expect{subject}.to_not raise_error }
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
describe "#check_rds_master_status" do
|
277
|
-
let(:client) { double('client') }
|
278
|
-
let(:subject_object) { MysqlCompatibilityCheck.new(default_data_port, default_mysql_cred) }
|
279
|
-
subject { subject_object.check_rds_master_status }
|
280
|
-
let(:master_status) { [] }
|
281
|
-
|
282
|
-
before do
|
283
|
-
allow(Mysql2::Client).to receive(:new).and_return(client)
|
284
|
-
allow(client).to receive(:query).and_return(master_status)
|
285
|
-
allow(client).to receive(:close)
|
286
|
-
end
|
287
|
-
|
288
|
-
context 'when host is rds' do
|
28
|
+
describe '#check_outgoing_ports' do
|
29
|
+
subject { subject_object.check_outgoing_ports }
|
30
|
+
context "when a port access fails" do
|
289
31
|
before do
|
290
|
-
|
32
|
+
allow(TCPSocket).to receive(:new).and_raise(Errno::ETIMEDOUT)
|
291
33
|
end
|
292
|
-
|
293
|
-
|
294
|
-
let(:master_status) { [] }
|
295
|
-
it { expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /Backup Retention Period/) }
|
296
|
-
end
|
297
|
-
|
298
|
-
context "where backup retention period is set" do
|
299
|
-
let(:master_status) do
|
300
|
-
[{
|
301
|
-
'File' => 'mysql-bin-changelog.026292',
|
302
|
-
'Position' => '31300',
|
303
|
-
'Binlog_Do_DB' => '',
|
304
|
-
'Binlog_Ignore_DB' => '',
|
305
|
-
'Executed_Gtid_Set' => '',
|
306
|
-
}]
|
307
|
-
end
|
308
|
-
it { expect{subject}.not_to raise_error }
|
34
|
+
it do
|
35
|
+
expect{subject}.to raise_error(FlydataCore::AgentCompatibilityError, /ports/)
|
309
36
|
end
|
310
37
|
end
|
311
38
|
end
|