flydata 0.6.3 → 0.6.4
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.
- 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
|