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
@@ -17,7 +17,7 @@ module Mysql
|
|
17
17
|
r
|
18
18
|
end
|
19
19
|
before do
|
20
|
-
parser_class = ParserProvider.parser(:mysql, :mysql_alter_table)
|
20
|
+
parser_class = Flydata::Parser::ParserProvider.parser(:mysql, :mysql_alter_table)
|
21
21
|
allow(parser_class).to receive(:new).and_return(parser)
|
22
22
|
allow_any_instance_of(described_class).to receive(:check_empty_binlog)
|
23
23
|
record.delete('table_name')
|
@@ -56,8 +56,8 @@ module Mysql
|
|
56
56
|
end
|
57
57
|
context "when event binlog is older than table binlog.pos" do
|
58
58
|
it 'skip sending event' do
|
59
|
-
expect(sync_fm).to receive(:
|
60
|
-
expect(ParserProvider).not_to receive(:parser)
|
59
|
+
expect(sync_fm).to receive(:get_table_source_raw_pos).and_return("mysql-bin.000067\t120").once
|
60
|
+
expect(Flydata::Parser::ParserProvider).not_to receive(:parser)
|
61
61
|
expect(subject.process(record)).to eq(nil)
|
62
62
|
end
|
63
63
|
end
|
@@ -12,7 +12,7 @@ describe DmlRecordHandler do
|
|
12
12
|
let(:tables) { ['items', 'orders'] }
|
13
13
|
let(:sync_fm) {
|
14
14
|
sfm = double('sync_fm')
|
15
|
-
allow(sfm).to receive(:
|
15
|
+
allow(sfm).to receive(:get_table_source_raw_pos).and_return nil
|
16
16
|
sfm
|
17
17
|
}
|
18
18
|
let(:context) {
|
@@ -4,11 +4,13 @@ module Mysql
|
|
4
4
|
let(:database) { target_database }
|
5
5
|
let(:table) { "foo" }
|
6
6
|
let(:seq) { 200 }
|
7
|
+
let(:binlog_pos_string) { "mysql-bin.000065\t120" }
|
8
|
+
let(:binlog_pos_object) { FlydataCore::Mysql::BinlogPos.new(binlog_pos_string) }
|
7
9
|
let(:sync_fm) do
|
8
10
|
r = double('sync_fm')
|
9
|
-
allow(r).to receive(:
|
11
|
+
allow(r).to receive(:get_table_source_raw_pos).and_return(binlog_pos_string)
|
10
12
|
allow(r).to receive(:increment_and_save_table_position).with(table).and_yield(seq).and_return(nil)
|
11
|
-
allow(r).to receive(:
|
13
|
+
allow(r).to receive(:delete_table_source_pos).with(table)
|
12
14
|
r
|
13
15
|
end
|
14
16
|
let(:table_meta) { double'table_meta' }
|
@@ -79,7 +79,7 @@ module Mysql
|
|
79
79
|
context 'when per-table binlog pos exists' do
|
80
80
|
let(:truncate_query) { "TRUNCATE #{table}" }
|
81
81
|
before do
|
82
|
-
allow(sync_fm).to receive(:
|
82
|
+
allow(sync_fm).to receive(:get_table_source_raw_pos).and_return("mysql-bin.000067\t120")
|
83
83
|
end
|
84
84
|
include_examples "skip processing queries"
|
85
85
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'flydata/source_mysql/generate_source_dump'
|
2
|
+
|
3
|
+
module Flydata
|
4
|
+
module SourceMysql
|
5
|
+
|
6
|
+
describe GenerateSourceDump do
|
7
|
+
let(:subject_object) { described_class.new(source, dp, options) }
|
8
|
+
|
9
|
+
let(:source) { double('source') }
|
10
|
+
before do
|
11
|
+
allow(source).to receive(:de).and_return(de)
|
12
|
+
end
|
13
|
+
let(:dp) { double('dp') }
|
14
|
+
let(:options) { double('options') }
|
15
|
+
|
16
|
+
let(:de) { {
|
17
|
+
"mysql_data_entry_preference" => {
|
18
|
+
"host" => "foo",
|
19
|
+
"port" => 1234,
|
20
|
+
"tables" => all_tables,
|
21
|
+
}
|
22
|
+
} }
|
23
|
+
|
24
|
+
let(:all_tables) { %w|a b c d| + partial_tables }
|
25
|
+
let(:partial_tables) { %w|e f| }
|
26
|
+
let(:file_path) { double('file_path') }
|
27
|
+
let(:src_pos_callback) { Proc.new{} }
|
28
|
+
let(:db_size_check) { double('db_size_check') }
|
29
|
+
let(:size) { double('size') }
|
30
|
+
|
31
|
+
let(:options_with_partial_tables) {
|
32
|
+
prefs = de['mysql_data_entry_preference'].clone
|
33
|
+
prefs["tables"] = partial_tables
|
34
|
+
prefs
|
35
|
+
}
|
36
|
+
|
37
|
+
describe '#dump_size' do
|
38
|
+
subject { subject_object.dump_size(partial_tables) }
|
39
|
+
|
40
|
+
it 'creates DatabaseSizeCheck object with correct parameter' do
|
41
|
+
expect(Parser::DatabaseSizeCheck).to receive(:new).
|
42
|
+
with(options_with_partial_tables).and_return(db_size_check)
|
43
|
+
expect(db_size_check).to receive(:get_db_bytesize).and_return(size)
|
44
|
+
|
45
|
+
expect(subject).to eq size
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#dump' do
|
50
|
+
subject { subject_object.dump(partial_tables, file_path, &src_pos_callback) }
|
51
|
+
|
52
|
+
let(:dump_generator) { double('dump_generator') }
|
53
|
+
before do
|
54
|
+
allow(dump_generator).to receive(:dump)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'creates dump_generator with correct parameters' do
|
58
|
+
expect(Parser::MysqlDumpGeneratorNoMasterData).to receive(:new).
|
59
|
+
with(options_with_partial_tables).and_return(dump_generator)
|
60
|
+
expect(dump_generator).to receive(:dump).
|
61
|
+
with(file_path, &src_pos_callback)
|
62
|
+
|
63
|
+
subject
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,280 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'flydata/source_mysql/mysql_compatibility_check'
|
3
|
+
|
4
|
+
module Flydata
|
5
|
+
module SourceMysql
|
6
|
+
|
7
|
+
describe MysqlCompatibilityCheck do
|
8
|
+
let(:subject_object) { described_class.new(dp_hash, de_hash, options) }
|
9
|
+
|
10
|
+
let(:dp_hash) { default_data_port }
|
11
|
+
let(:de_hash) { default_mysql_cred }
|
12
|
+
let(:options) { default_options }
|
13
|
+
|
14
|
+
let(:default_data_port) do
|
15
|
+
{
|
16
|
+
"servers"=>["sample-test-site.com"]
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:default_mysql_cred) do
|
21
|
+
{
|
22
|
+
"host" => "test",
|
23
|
+
"port" => 1234,
|
24
|
+
"username" => "test",
|
25
|
+
"password" => "password",
|
26
|
+
"database" => "test_db"
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:default_options) { {} }
|
31
|
+
|
32
|
+
let(:client) { double('client') }
|
33
|
+
before do
|
34
|
+
allow(Mysql2::Client).to receive(:new).and_return(client)
|
35
|
+
allow(client).to receive(:close)
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#check" do
|
39
|
+
subject { subject_object.check }
|
40
|
+
|
41
|
+
it "calls all check methods" do
|
42
|
+
%w(compatibility56_variable mysql_user_compat mysql_protocol_tcp_compat
|
43
|
+
mysql_parameters_compat rds_master_status mysql_binlog_retention
|
44
|
+
mysql_table_types writing_permissions).each do |method_name|
|
45
|
+
expect(subject_object).to receive("check_#{method_name}".to_sym)
|
46
|
+
end
|
47
|
+
|
48
|
+
subject
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#check_mysql_user_compat" do
|
53
|
+
subject { subject_object.check_mysql_user_compat }
|
54
|
+
|
55
|
+
context "with all privileges in all databases" do
|
56
|
+
before do
|
57
|
+
allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT ALL PRIVILEGES ON *.* TO 'test'@'host"}])
|
58
|
+
end
|
59
|
+
it do
|
60
|
+
expect{subject}.to_not raise_error
|
61
|
+
end
|
62
|
+
end
|
63
|
+
context "with missing privileges in one database" do
|
64
|
+
before do
|
65
|
+
allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT ALL PRIVILEGES ON 'mysql'.* TO 'test'@'host"},
|
66
|
+
{"Grants for test"=>"GRANT SELECT, RELOAD, REPLICATION CLIENT ON `test_db`.* TO 'test'@'host"}])
|
67
|
+
end
|
68
|
+
it do
|
69
|
+
expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /test_db': LOCK TABLES, REPLICATION SLAVE/)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
context "with all required privileges in between all and specific databases" do
|
73
|
+
before do
|
74
|
+
allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT RELOAD, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'test'@'host"},
|
75
|
+
{"Grants for test"=>"GRANT SELECT, LOCK TABLES ON `test_db`.* TO 'test'@'host"},
|
76
|
+
{"Grants for test"=>"GRANT SELECT, LOCK TABLES ON `mysql`.* TO 'test'@'host"}])
|
77
|
+
end
|
78
|
+
it do
|
79
|
+
expect{subject}.to_not raise_error
|
80
|
+
end
|
81
|
+
end
|
82
|
+
context "with missing privileges in each database" do
|
83
|
+
before do
|
84
|
+
allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'test'@'host"},
|
85
|
+
{"Grants for test"=>"GRANT SELECT, LOCK TABLES ON `test_db`.* TO 'test'@'host"},
|
86
|
+
{"Grants for test"=>"GRANT SELECT, LOCK TABLES ON `mysql`.* TO 'test'@'host"}])
|
87
|
+
end
|
88
|
+
it do
|
89
|
+
expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /mysql': RELOAD\n.*test_db': RELOAD/)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
context "with all required privileges in all databases" do
|
93
|
+
before do
|
94
|
+
allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT SELECT, LOCK TABLES, RELOAD, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'test'@'host"}])
|
95
|
+
end
|
96
|
+
it do
|
97
|
+
expect{subject}.to_not raise_error
|
98
|
+
end
|
99
|
+
end
|
100
|
+
context "with missing privileges in all databases" do
|
101
|
+
before do
|
102
|
+
allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT RELOAD, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'test'@'host"}])
|
103
|
+
end
|
104
|
+
it do
|
105
|
+
expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /mysql': SELECT, LOCK TABLES\n.*test_db': SELECT, LOCK TABLES/)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
context "with privileges for other databases only" do
|
109
|
+
before do
|
110
|
+
allow(client).to receive(:query).and_return([{"Grants for test"=>"GRANT REPLICATION CLIENT ON `test_db_01`.* TO 'test'@'host"},
|
111
|
+
{"Grants for test"=>"GRANT LOCK TABLES ON `test_db_02`.* TO 'test'@'host"},
|
112
|
+
{"Grants for test"=>"GRANT SELECT ON `text_db_03`.* TO 'test'@'host"}])
|
113
|
+
end
|
114
|
+
it do
|
115
|
+
expect{subject}.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/)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "#check_mysql_binlog_retention" do
|
122
|
+
subject { subject_object.check_mysql_binlog_retention }
|
123
|
+
context "on on-premise mysql server" do
|
124
|
+
before do
|
125
|
+
allow(subject_object).to receive(:is_rds?).and_return(false)
|
126
|
+
end
|
127
|
+
context "where retention is below limit" do
|
128
|
+
before do
|
129
|
+
allow(client).to receive(:query).and_return([{"Variable_name" => "expire_logs_days", "Value" => 1}])
|
130
|
+
end
|
131
|
+
it do
|
132
|
+
expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /expire_logs_days/)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
context "where retention is 0" do
|
136
|
+
before do
|
137
|
+
allow(client).to receive(:query).and_return([{"Variable_name" => "expire_logs_days", "Value" => 0}])
|
138
|
+
end
|
139
|
+
it do
|
140
|
+
expect{subject}.to_not raise_error
|
141
|
+
end
|
142
|
+
end
|
143
|
+
context "where retention is above limit" do
|
144
|
+
before do
|
145
|
+
allow(client).to receive(:query).and_return([{"expire_logs_days"=>11}])
|
146
|
+
allow(client).to receive(:query).and_return([{"Variable_name" => "expire_logs_days", "Value" => 11}])
|
147
|
+
end
|
148
|
+
it do
|
149
|
+
expect{subject}.to_not raise_error
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
context "on RDS" do
|
154
|
+
before do
|
155
|
+
allow(subject_object).to receive(:is_rds?).and_return(true)
|
156
|
+
end
|
157
|
+
before do
|
158
|
+
allow(client).to receive(:query).with("SELECT @@expire_logs_days").and_return([{"@@expire_logs_days"=>0}])
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
context "where retention period is nil" do
|
163
|
+
before do
|
164
|
+
allow(client).to receive(:query).with("call mysql.rds_show_configuration;").and_return([{"name"=>"binlog retention hours", "value"=>nil}])
|
165
|
+
end
|
166
|
+
it do
|
167
|
+
expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /rds_set_config/)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
context "where retention period is too low" do
|
171
|
+
before do
|
172
|
+
allow(client).to receive(:query).with("call mysql.rds_show_configuration;").and_return([{"name"=>"binlog retention hours", "value"=>4}])
|
173
|
+
end
|
174
|
+
it do
|
175
|
+
expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /rds_set_config/)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
context "where retention period is over recommended limit" do
|
179
|
+
before do
|
180
|
+
allow(client).to receive(:query).with("call mysql.rds_show_configuration;").and_return([{"name"=>"binlog retention hours", "value"=>120}])
|
181
|
+
end
|
182
|
+
it do
|
183
|
+
expect{subject}.to_not raise_error
|
184
|
+
end
|
185
|
+
end
|
186
|
+
context "where user has no access to rds configuration" do
|
187
|
+
before do
|
188
|
+
allow(client).to receive(:query).with("call mysql.rds_show_configuration;").and_raise(Mysql2::Error, "execute command denied to user")
|
189
|
+
end
|
190
|
+
it do
|
191
|
+
expect{subject}.to_not raise_error
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
describe "#check_mysql_table_types" do
|
198
|
+
subject { subject_object.check_mysql_table_types }
|
199
|
+
|
200
|
+
let(:de_hash) do
|
201
|
+
{ "host" => "test",
|
202
|
+
"port" => 1234,
|
203
|
+
"username" => "test",
|
204
|
+
"password" => "password",
|
205
|
+
"database" => "test_db",
|
206
|
+
"tables"=>["normal_table", "engine_table", "view_table"] }
|
207
|
+
end
|
208
|
+
let(:normal_table) { {"table_name"=>"normal_table", "table_type"=>"BASE TABLE", "engine"=>"InnoDB"} }
|
209
|
+
let(:engine_table) { {"table_name"=>"engine_table", "table_type"=>"BASE TABLE", "engine"=>"MEMORY"} }
|
210
|
+
let(:blackhole_table) { {"table_name"=>"blackhole_table", "table_type"=>"BASE TABLE", "engine"=>"BLACKHOLE"} }
|
211
|
+
let(:view) { {"table_name"=>"view_table", "table_type"=>"VIEW", "engine"=>nil} }
|
212
|
+
let(:error) { FlydataCore::MysqlCompatibilityError }
|
213
|
+
let(:base_error_msg) { "FlyData does not support VIEW and MEMORY,BLACKHOLE STORAGE ENGINE table. Remove following tables from data entry: %s" }
|
214
|
+
before do
|
215
|
+
allow(client).to receive(:query).and_return(table_list)
|
216
|
+
allow(client).to receive(:escape).and_return("aaa")
|
217
|
+
end
|
218
|
+
context "where data entry has VIEW and MEMORY engine table" do
|
219
|
+
let(:error_msg) { base_error_msg % engine_table['table_name'] + ', ' + view['table_name'] }
|
220
|
+
let(:table_list) { [ engine_table, view ] }
|
221
|
+
it { expect{subject}.to raise_error(error, /#{error_msg}/) }
|
222
|
+
end
|
223
|
+
context "where data entry has MEMORY engine table" do
|
224
|
+
let(:error_msg) { base_error_msg % engine_table['table_name'] }
|
225
|
+
let(:table_list) { [ engine_table ] }
|
226
|
+
it { expect{subject}.to raise_error(error, /#{error_msg}/) }
|
227
|
+
end
|
228
|
+
context "where data entry has BLACKHOLE engine table" do
|
229
|
+
let(:error_msg) { base_error_msg % blackhole_table['table_name'] }
|
230
|
+
let(:table_list) { [ blackhole_table ] }
|
231
|
+
it { expect{subject}.to raise_error(error, /#{error_msg}/) }
|
232
|
+
end
|
233
|
+
context "where data entry has the VIEW" do
|
234
|
+
let(:error_msg) { base_error_msg % view['table_name'] }
|
235
|
+
let(:table_list) { [ view ] }
|
236
|
+
it { expect{subject}.to raise_error(error, /#{error_msg}/) }
|
237
|
+
end
|
238
|
+
context "where data entry does not have either VIEW and ENGINE table" do
|
239
|
+
let(:table_list) { [ normal_table ] }
|
240
|
+
it { expect{subject}.to_not raise_error }
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe "#check_rds_master_status" do
|
245
|
+
subject { subject_object.check_rds_master_status }
|
246
|
+
|
247
|
+
let(:master_status) { [] }
|
248
|
+
|
249
|
+
before do
|
250
|
+
allow(client).to receive(:query).and_return(master_status)
|
251
|
+
end
|
252
|
+
|
253
|
+
context 'when host is rds' do
|
254
|
+
before do
|
255
|
+
de_hash['host'] = 'rdrss.xxyyzz.rds.amazonaws.com'
|
256
|
+
end
|
257
|
+
|
258
|
+
context "where backup retention period is not set" do
|
259
|
+
let(:master_status) { [] }
|
260
|
+
it { expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /Backup Retention Period/) }
|
261
|
+
end
|
262
|
+
|
263
|
+
context "where backup retention period is set" do
|
264
|
+
let(:master_status) do
|
265
|
+
[{
|
266
|
+
'File' => 'mysql-bin-changelog.026292',
|
267
|
+
'Position' => '31300',
|
268
|
+
'Binlog_Do_DB' => '',
|
269
|
+
'Binlog_Ignore_DB' => '',
|
270
|
+
'Executed_Gtid_Set' => '',
|
271
|
+
}]
|
272
|
+
end
|
273
|
+
it { expect{subject}.not_to raise_error }
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
end
|
280
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'flydata/parser_provider'
|
2
|
+
require 'flydata/parser/parser_provider'
|
3
3
|
|
4
4
|
describe 'MysqlAlterTableParser' do
|
5
5
|
before do
|
6
6
|
#load parser
|
7
|
-
@parser_class =
|
7
|
+
@parser_class = Flydata::Parser::ParserProvider.parser(:mysql, :mysql_alter_table)
|
8
8
|
end
|
9
9
|
|
10
10
|
let(:query) { "" }
|
@@ -3,11 +3,12 @@ require 'spec_helper'
|
|
3
3
|
require 'open3'
|
4
4
|
require 'mysql2'
|
5
5
|
require 'flydata/command/sync'
|
6
|
-
require 'flydata/parser/
|
6
|
+
require 'flydata/source_mysql/parser/dump_parser'
|
7
|
+
require 'flydata-core/mysql/binlog_pos'
|
7
8
|
|
8
9
|
module Flydata
|
9
|
-
module
|
10
|
-
module
|
10
|
+
module SourceMysql
|
11
|
+
module Parser
|
11
12
|
context "Test Dump Generators" do
|
12
13
|
let(:stdin) do
|
13
14
|
s = double(:stdin)
|
@@ -153,8 +154,9 @@ EOT
|
|
153
154
|
content[0...content.index(string)].bytesize + string.bytesize + 1
|
154
155
|
end
|
155
156
|
|
156
|
-
let(:default_parser) { MysqlDumpParser.new(
|
157
|
+
let(:default_parser) { MysqlDumpParser.new(source_pos: default_binlog_pos_object) }
|
157
158
|
let(:default_binlog_pos) { {binfile: 'mysql-bin.000267', pos: 120 } }
|
159
|
+
let(:default_binlog_pos_object) { FlydataCore::Mysql::BinlogPos.new(default_binlog_pos) }
|
158
160
|
let(:dump_pos_after_binlog_pos) { index_after(DUMP_HEADER, '5.6.13-log') }
|
159
161
|
|
160
162
|
let(:create_table_block) { double('create_table_block') }
|
@@ -210,30 +212,30 @@ EOT
|
|
210
212
|
}
|
211
213
|
before { generate_dump_file(dump_content) }
|
212
214
|
it do
|
213
|
-
expect(create_table_block).to receive(:call) { |
|
214
|
-
expect(
|
215
|
+
expect(create_table_block).to receive(:call) { |source_table|
|
216
|
+
expect(source_table.table_name).to eq('users_login')
|
215
217
|
}.once
|
216
218
|
expect(insert_record_block).to receive(:call).never
|
217
|
-
expect(check_point_block).to receive(:call) { |
|
218
|
-
expect(
|
219
|
+
expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
|
220
|
+
expect(source_table).to be_nil
|
219
221
|
expect(last_pos).to eq(dump_pos_after_binlog_pos)
|
220
222
|
expect(binlog_pos).to eq(default_binlog_pos)
|
221
|
-
expect(state).to eq(
|
223
|
+
expect(state).to eq(Flydata::Parser::State::CREATE_TABLE)
|
222
224
|
expect(substate).to be_nil
|
223
225
|
}
|
224
|
-
expect(check_point_block).to receive(:call) { |
|
225
|
-
expect(
|
226
|
-
expect(
|
226
|
+
expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
|
227
|
+
expect(source_table.table_name).to eq('users_login')
|
228
|
+
expect(source_table.columns.keys).to eq([col_name, 'login_count', 'create_time', 'update_time'])
|
227
229
|
expect(last_pos).to eq(index_after(dump_content, 'ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=\'\';'))
|
228
230
|
expect(binlog_pos).to eq(default_binlog_pos)
|
229
|
-
expect(state).to eq(
|
231
|
+
expect(state).to eq(Flydata::Parser::State::INSERT_RECORD)
|
230
232
|
expect(substate).to be_nil
|
231
233
|
}
|
232
|
-
expect(check_point_block).to receive(:call) { |
|
233
|
-
expect(
|
234
|
+
expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
|
235
|
+
expect(source_table.table_name).to eq('users_login')
|
234
236
|
expect(last_pos).to eq(index_after(dump_content, 'UNLOCK TABLES;'))
|
235
237
|
expect(binlog_pos).to eq(default_binlog_pos)
|
236
|
-
expect(state).to eq(
|
238
|
+
expect(state).to eq(Flydata::Parser::State::CREATE_TABLE)
|
237
239
|
expect(substate).to be_nil
|
238
240
|
}
|
239
241
|
expect(check_point_block).to receive(:call).never
|
@@ -302,9 +304,9 @@ EOT
|
|
302
304
|
before { generate_dump_file(dump_content) }
|
303
305
|
it do
|
304
306
|
# create_table_block
|
305
|
-
expect(create_table_block).to receive(:call) { |
|
306
|
-
expect(
|
307
|
-
expect(
|
307
|
+
expect(create_table_block).to receive(:call) { |source_table|
|
308
|
+
expect(source_table.table_name).to eq('users_login')
|
309
|
+
expect(source_table.columns.keys).to eq(['user_id', 'login_count', 'comment', 'create_time', 'update_time'])
|
308
310
|
}.once
|
309
311
|
expect(create_table_block).to receive(:call).never
|
310
312
|
|
@@ -316,8 +318,8 @@ EOT
|
|
316
318
|
[ %w(373 31 out'swearing 1979-10-07\ 08:10:08 2006-02-22\ 16:26:04),
|
317
319
|
%w(493 8 schizophrenic 1979-07-06\ 07:34:07 1970-08-09\ 01:21:01),]
|
318
320
|
].each do |expected_values|
|
319
|
-
expect(insert_record_block).to receive(:call) { |
|
320
|
-
expect(
|
321
|
+
expect(insert_record_block).to receive(:call) { |source_table, values_set|
|
322
|
+
expect(source_table.table_name).to eq('users_login')
|
321
323
|
expect(values_set).to eq(expected_values)
|
322
324
|
nil
|
323
325
|
}.once
|
@@ -326,13 +328,13 @@ EOT
|
|
326
328
|
|
327
329
|
# insert_record_block
|
328
330
|
[
|
329
|
-
{state:
|
330
|
-
{state:
|
331
|
-
{state:
|
331
|
+
{state: Flydata::Parser::State::CREATE_TABLE},
|
332
|
+
{state: Flydata::Parser::State::INSERT_RECORD},
|
333
|
+
{state: Flydata::Parser::State::CREATE_TABLE,
|
332
334
|
last_pos: index_after(dump_content, 'UNLOCK TABLES;')}
|
333
335
|
].each do |expected_params|
|
334
|
-
expect(check_point_block).to receive(:call) { |
|
335
|
-
expect(
|
336
|
+
expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
|
337
|
+
expect(source_table.table_name).to eq('users_login') if source_table
|
336
338
|
expect(state).to eq(expected_params[:state])
|
337
339
|
if expected_params[:last_pos]
|
338
340
|
expect(last_pos).to eq(expected_params[:last_pos])
|
@@ -384,9 +386,9 @@ EOT
|
|
384
386
|
before { generate_dump_file(dump_content) }
|
385
387
|
it do
|
386
388
|
# create_table_block
|
387
|
-
expect(create_table_block).to receive(:call) { |
|
388
|
-
expect(
|
389
|
-
expect(
|
389
|
+
expect(create_table_block).to receive(:call) { |source_table|
|
390
|
+
expect(source_table.table_name).to eq('users_login')
|
391
|
+
expect(source_table.columns.keys).to eq(['user_id', 'login_count', 'comment', 'create_time', 'update_time'])
|
390
392
|
}.once
|
391
393
|
expect(create_table_block).to receive(:call).never
|
392
394
|
|
@@ -396,8 +398,8 @@ EOT
|
|
396
398
|
['35', '6', nil, '1991-10-15 19:38:07', '1970-10-01 22:03:10'],
|
397
399
|
%w(52 33 subfield 1972-08-23\ 20:16:08 1974-10-10\ 23:28:11),],
|
398
400
|
].each do |expected_values|
|
399
|
-
expect(insert_record_block).to receive(:call) { |
|
400
|
-
expect(
|
401
|
+
expect(insert_record_block).to receive(:call) { |source_table, values_set|
|
402
|
+
expect(source_table.table_name).to eq('users_login')
|
401
403
|
expect(values_set).to eq(expected_values)
|
402
404
|
nil
|
403
405
|
}.once
|
@@ -406,13 +408,13 @@ EOT
|
|
406
408
|
|
407
409
|
# insert_record_block
|
408
410
|
[
|
409
|
-
{state:
|
410
|
-
{state:
|
411
|
-
{state:
|
411
|
+
{state: Flydata::Parser::State::CREATE_TABLE},
|
412
|
+
{state: Flydata::Parser::State::INSERT_RECORD},
|
413
|
+
{state: Flydata::Parser::State::CREATE_TABLE,
|
412
414
|
last_pos: index_after(dump_content, 'UNLOCK TABLES;')}
|
413
415
|
].each do |expected_params|
|
414
|
-
expect(check_point_block).to receive(:call) { |
|
415
|
-
expect(
|
416
|
+
expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
|
417
|
+
expect(source_table.table_name).to eq('users_login') if source_table
|
416
418
|
expect(state).to eq(expected_params[:state])
|
417
419
|
if expected_params[:last_pos]
|
418
420
|
expect(last_pos).to eq(expected_params[:last_pos])
|
@@ -472,16 +474,16 @@ EOT
|
|
472
474
|
Proc.new{
|
473
475
|
raise "Should not be called"
|
474
476
|
},
|
475
|
-
Proc.new{ |
|
476
|
-
if
|
477
|
-
@
|
477
|
+
Proc.new{ |source_table, last_pos, bytesize, binlog_pos, state, substate|
|
478
|
+
if source_table
|
479
|
+
@source_table = source_table
|
478
480
|
@option = { status: Flydata::Command::Sync::STATUS_PARSING,
|
479
|
-
table_name:
|
481
|
+
table_name: source_table.table_name,
|
480
482
|
last_pos: last_pos,
|
481
483
|
binlog_pos: binlog_pos,
|
482
484
|
state: state,
|
483
485
|
substate: substate,
|
484
|
-
|
486
|
+
source_table: source_table }
|
485
487
|
end
|
486
488
|
}
|
487
489
|
)
|
@@ -490,15 +492,16 @@ EOT
|
|
490
492
|
table_name: 'users_login',
|
491
493
|
last_pos: index_after(dump_content_head, 'ENGINE=InnoDB DEFAULT CHARSET=utf8;'),
|
492
494
|
binlog_pos: default_binlog_pos,
|
493
|
-
state:
|
495
|
+
state: Flydata::Parser::State::INSERT_RECORD,
|
494
496
|
substate: nil,
|
495
|
-
|
497
|
+
source_table: @source_table
|
496
498
|
})
|
497
499
|
end
|
498
500
|
it do
|
499
501
|
generate_dump_file(dump_content_all)
|
502
|
+
@option.delete(:binlog_pos)
|
503
|
+
@option.merge!( {source_pos: default_binlog_pos_object} )
|
500
504
|
parser_for_resume = MysqlDumpParser.new(@option)
|
501
|
-
|
502
505
|
# create_table_block
|
503
506
|
expect(create_table_block).to receive(:call).never
|
504
507
|
|
@@ -508,8 +511,8 @@ EOT
|
|
508
511
|
%w(35 6 missteer 1991-10-15\ 19:38:07 1970-10-01\ 22:03:10),
|
509
512
|
%w(52 33 subfield 1972-08-23\ 20:16:08 1974-10-10\ 23:28:11),],
|
510
513
|
].each do |expected_values|
|
511
|
-
expect(insert_record_block).to receive(:call) { |
|
512
|
-
expect(
|
514
|
+
expect(insert_record_block).to receive(:call) { |source_table, values|
|
515
|
+
expect(source_table.table_name).to eq('users_login')
|
513
516
|
expect(values).to eq(expected_values)
|
514
517
|
nil
|
515
518
|
}.once
|
@@ -518,11 +521,11 @@ EOT
|
|
518
521
|
|
519
522
|
# check_point_block
|
520
523
|
[
|
521
|
-
{state:
|
524
|
+
{state: Flydata::Parser::State::CREATE_TABLE,
|
522
525
|
last_pos: index_after(dump_content_all, 'UNLOCK TABLES;')}
|
523
526
|
].each do |expected_params|
|
524
|
-
expect(check_point_block).to receive(:call) { |
|
525
|
-
expect(
|
527
|
+
expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
|
528
|
+
expect(source_table.table_name).to eq('users_login') if source_table
|
526
529
|
expect(state).to eq(expected_params[:state])
|
527
530
|
if expected_params[:last_pos]
|
528
531
|
expect(last_pos).to eq(expected_params[:last_pos])
|
@@ -582,16 +585,16 @@ EOT
|
|
582
585
|
dump_io,
|
583
586
|
Proc.new{},
|
584
587
|
insert_record_block_for_resume,
|
585
|
-
Proc.new{ |
|
588
|
+
Proc.new{ |source_table, last_pos, bytesize, binlog_pos, state, substate|
|
586
589
|
if last_pos == index_after(dump_content, "'1972-08-23 20:16:08','1974-10-10 23:28:11');")
|
587
|
-
@
|
590
|
+
@source_table = source_table
|
588
591
|
@option = { status: Flydata::Command::Sync::STATUS_PARSING,
|
589
|
-
table_name:
|
592
|
+
table_name: source_table.table_name,
|
590
593
|
last_pos: last_pos,
|
591
594
|
binlog_pos: binlog_pos,
|
592
595
|
state: state,
|
593
596
|
substate: substate,
|
594
|
-
|
597
|
+
source_table: source_table }
|
595
598
|
end
|
596
599
|
}
|
597
600
|
)
|
@@ -600,13 +603,15 @@ EOT
|
|
600
603
|
table_name: 'users_login',
|
601
604
|
last_pos: index_after(dump_content, "'1972-08-23 20:16:08','1974-10-10 23:28:11');"),
|
602
605
|
binlog_pos: default_binlog_pos,
|
603
|
-
state:
|
606
|
+
state: Flydata::Parser::State::INSERT_RECORD,
|
604
607
|
substate: nil,
|
605
|
-
|
608
|
+
source_table: @source_table
|
606
609
|
})
|
607
610
|
end
|
608
611
|
it do
|
609
612
|
generate_dump_file(dump_content)
|
613
|
+
@option.delete(:binlog_pos)
|
614
|
+
@option.merge!({source_pos: default_binlog_pos_object})
|
610
615
|
parser_for_resume = MysqlDumpParser.new(@option)
|
611
616
|
|
612
617
|
# create_table_block
|
@@ -617,8 +622,8 @@ EOT
|
|
617
622
|
[ %w(194 11 pandemonium 2008-01-22\ 22:15:10 1991-04-04\ 17:30:05),
|
618
623
|
%w(230 7 cloudburst 2010-12-28\ 11:46:11 1971-06-22\ 13:08:01),],
|
619
624
|
].each do |expected_values|
|
620
|
-
expect(insert_record_block).to receive(:call) { |
|
621
|
-
expect(
|
625
|
+
expect(insert_record_block).to receive(:call) { |source_table, values_set|
|
626
|
+
expect(source_table.table_name).to eq('users_login')
|
622
627
|
expect(values_set).to eq(expected_values)
|
623
628
|
nil
|
624
629
|
}.once
|
@@ -627,11 +632,11 @@ EOT
|
|
627
632
|
|
628
633
|
# check_point_block
|
629
634
|
[
|
630
|
-
{state:
|
635
|
+
{state: Flydata::Parser::State::CREATE_TABLE,
|
631
636
|
last_pos: index_after(dump_content, 'UNLOCK TABLES;')}
|
632
637
|
].each do |expected_params|
|
633
|
-
expect(check_point_block).to receive(:call) { |
|
634
|
-
expect(
|
638
|
+
expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
|
639
|
+
expect(source_table.table_name).to eq('users_login') if source_table
|
635
640
|
expect(state).to eq(expected_params[:state])
|
636
641
|
if expected_params[:last_pos]
|
637
642
|
expect(last_pos).to eq(expected_params[:last_pos])
|
@@ -684,9 +689,9 @@ EOT
|
|
684
689
|
before { generate_dump_file(dump_content) }
|
685
690
|
it do
|
686
691
|
# create_table_block
|
687
|
-
expect(create_table_block).to receive(:call) { |
|
688
|
-
expect(
|
689
|
-
expect(
|
692
|
+
expect(create_table_block).to receive(:call) { |source_table|
|
693
|
+
expect(source_table.table_name).to eq('users_login')
|
694
|
+
expect(source_table.columns.keys).to eq(['user_id', 'login_count', 'comment', 'create_time', 'update_time'])
|
690
695
|
}.once
|
691
696
|
expect(create_table_block).to receive(:call).never
|
692
697
|
|
@@ -698,8 +703,8 @@ EOT
|
|
698
703
|
[ ['373','31',"outs\nwearing",'1979-10-07 08:10:08','2006-02-22 16:26:04'],
|
699
704
|
['493','8',"schiz\tophrenic",'1979-07-06 07:34:07\'),','1970-08-09,01:21:01,\')'] ]
|
700
705
|
].each do |expected_values|
|
701
|
-
expect(insert_record_block).to receive(:call) { |
|
702
|
-
expect(
|
706
|
+
expect(insert_record_block).to receive(:call) { |source_table, values_set|
|
707
|
+
expect(source_table.table_name).to eq('users_login')
|
703
708
|
expect(values_set).to eq(expected_values)
|
704
709
|
nil
|
705
710
|
}.once
|
@@ -708,13 +713,13 @@ EOT
|
|
708
713
|
|
709
714
|
# insert_record_block
|
710
715
|
[
|
711
|
-
{state:
|
712
|
-
{state:
|
713
|
-
{state:
|
716
|
+
{state: Flydata::Parser::State::CREATE_TABLE},
|
717
|
+
{state: Flydata::Parser::State::INSERT_RECORD},
|
718
|
+
{state: Flydata::Parser::State::CREATE_TABLE,
|
714
719
|
last_pos: index_after(dump_content, 'UNLOCK TABLES;')}
|
715
720
|
].each do |expected_params|
|
716
|
-
expect(check_point_block).to receive(:call) { |
|
717
|
-
expect(
|
721
|
+
expect(check_point_block).to receive(:call) { |source_table, last_pos, bytesize, binlog_pos, state, substate|
|
722
|
+
expect(source_table.table_name).to eq('users_login') if source_table
|
718
723
|
expect(state).to eq(expected_params[:state])
|
719
724
|
if expected_params[:last_pos]
|
720
725
|
expect(last_pos).to eq(expected_params[:last_pos])
|